As a side effect of reporting a bug on the erlang-bugs list I got an detailed answer this from Kostis Sagonas, the inventor of dialyzer and typer.
To my side question I got the following great and detailed answer:
On Sun, May 1, 2011 at 5:53 PM, Kostis Sagonas wrote:
Peer Stritzinger wrote:
BTW: is it normal not to get any warnings when just doing --annotate
in typer and then dialyzer with no manually tweaked spec's
Yes. In fact, typer is just a front end for dialyzer's basic type inference (i.e. without the warning identification component).
IMO, there is very little point in doing this if you do not intend to manually "massage" the specs that you get and provide more info for some of them. Take a look at your previous program. The fact that the two <<:64,:_*8>> types were referring to the same quantity could be expressed better if you introduced a type as in:
-type packet() :: <<_:64,_:_*8>>,
Similarly for channel:
-type channel() :: atom() | pid() |{atom(),_}.
and then the spec would already look better. Also, dialyzer/typer has no info on what type of fun you intend to use in the second argument of function recv/3
but you do! From the code it is clear that it takes #can_pkt{}
record, so why don't you add appropriate types to its fields and introduce a type for it?
-record(can_pkt, {id :: id(), data :: binary(), timestamp :: ts()}).
-type can_pkt() :: #can_pkt{}.
then the specs can look much better:
-spec recv(packet(), fun((can_pkt()) -> R), channel()) -> R.
-spec decode(packet()) -> can_pkt().
and note that I've used a placeholder type variable R
to denote the fact that function recv/2
returns whatever type the fun in its second argument returns. You probably know what this type is so you should also introduce a type for it and use its proper name.
Hope this helps,
Kostis
PS. It's a pity you posted this in erlang-bugs as the information contained in the above is IMO more interesting than the actual bug.
Since he refers to a code fragment, I included in my bug report, I include it here. The following code fragment was automatically annotated by typer --annotate
:
-record(can_pkt, {id, data, timestamp}).
-spec recv(<<_:64,_:_*8>>,fun((_) ->
any()),atom() | pid() | {atom(),_}) -> any().
recv(Packet, Recv_fun, Chan) ->
P = decode(Packet),
#can_pkt{id=Can_id, data=Can_data}=P,
Recv_fun(P).
-spec decode(<<_:64,_:_*8>>) ->
#can_pkt{id::<<_:11>>,data::binary(),timestamp::char()}.
decode(<<_:12, Len:4, Timestamp:16,
0:3, Id:11/bitstring, 0:18,
Data:Len/binary, _/binary>>) ->
#can_pkt{id=Id, data=Data, timestamp=Timestamp}.