I have a behaviour X and a callback function with parameter type:
%{a: any}
Module Y implements behaviour X and the callback function in implementing module Y has parameter type:
%{a: any, b: any}
Dialyzer doesn't like that and complains:
(#{'a':=_, 'b':=_, _=>_})
is not a supertype of
#{'a':=_}
This implies dialyzer attempts to determine if callback parameter's type in implementing module Y is a supertype of param type in behaviour X. In other words, it asks:
Is behaviour X's callback param type
%{a: any}a subtype of implementing module Y's param type%{a: any, b: any}?
Why does dialyzer expect behaviour callback's param type to be a subtype instead of a supertype?
In the context of programming language type theory, subtype is defined as:
type S is a subtype of a type T, written S <: T, if an expression of type S can be used in any context that expects an element of type T. Another way of putting this is that any expression of type S can masquerade as an expression of type T.
In light of the definition above, it makes sense to me if parameter type of behaviour callback is T and that of implementing module is S. Because implementing module still keeps the behaviour contract. However, I'm clueless as to why dialyzer expects the other way around.
Please help me understand this.
Note: This question is a follow-up but independent of another SO question Erlang (Elixir) Dialyzer - confusing supertype error.
Because implementing module still keeps the behaviour contract.I don't think it does. Now you have a module that you say implementsXbut no one can actually call the function with%{a: any}as the behavior says because your implementation also requiresb: anyin the map. - Dogbertb: anyin the map, it's good to allow any operation that can be performed on the original type specified by behaviour X. It respects width subtyping rule: en.wikipedia.org/wiki/Subtyping#Width_and_depth_subtyping - Ahmad Ferdous%{a: 1}to all the implementors of X but I can't do that to Y because it requires an additional field:b. The reverse is fine -- if X requires%{a: any, b: any}andYrequires%{a: any}, that's fine because I can call it like the behaviour says andbwill be ignored byY. - Dogbert