[erlang-questions] Trouble with init/1 spec

Kostis Sagonas <>
Wed Mar 24 21:34:54 CET 2010


Jay Nelson wrote:
> 
> On Mar 24, 2010, at 9:40 AM, Kostis Sagonas wrote:
>> For example, I tried the following (a simplified version of your code):
>> ---------------------------------------------------------------
>> -module(jay).
>> -export([init/1]).
>>
>> -record(twfsm_state, {server = "abc" :: string(),
>>                       port = 42 :: integer()}).
>>
>> -spec init(list()) -> {ok, #twfsm_state{}}.
>>
>> init([Server, Port]) ->
>>     {ok, #twfsm_state{server=Server, port=Port}}.
>> ---------------------------------------------------------------
>> I really want to understand this.  What exactly is that you claim you 
>> cannot really do without getting a dialyzer warning?
>>
>> Kostis
>>
> 
> I had another mistake in one of the other fields in the record that 
> caused the problem (but other errors led me to my arguments issue).  I 
> had declared:
> 
> -record(twfsm_state, {
>                server :: string(),
>                port :: pos_integer(),
>                conn_attempts = 0 :: pos_integer()
>          }.
> 
> jay.erl:20: The specification for jay:init/1 states that the function 
> might also return {'ok',{'twfsm_state','undefined' | 
> string(),'undefined' | pos_integer(),pos_integer(),binary()}} but the 
> inferred return is none()
> jay.erl:22: Function init/1 has no local return
> jay.erl:23: Record construction 
> #twfsm_state{server::any(),port::any(),conn_attempts::0} violates the 
> declared type for #twfsm_state{}
> 
> 
> Changing conn_attempts to non_neg_integer() solves the problem that my 
> initial value is invalid for the type.
> 
> What would have helped is if the record construction error singled out 
> only the fields that violated the declared datatypes after the entry 
> 'jay.erl:23', maybe as a list similar to error_logger:error_report might 
> present, since I actually had 15 or so fields.
> 
> For example:
> 
> jay.erl:23: Record construction 
> #twfsm_state{server::any(),port::any(),conn_attempts::0} violates the 
> declared type for #twfsm_state{}
> 
> jay.erl:23: The following fields are incorrect:
> conn_attempts::0 => pos_integer()

Yes, this would have indeed helped, but I do not see how this error is 
relevant/related to the input arguments of the spec, which triggered 
this discussion.  The dialyzer warnings you got clearly state that:

   1) there is an error in the return type of function init/1
   2) the function has no local return and
   3) there is some type violation in the record construction.

Nothing of these is related to whether the spec for init/1 has arguments 
of type list(any()) or something else.

> Although, I still would have thought there was a type failure.  In your 
> example, you set the values of the record to values of type any() even 
> though they were declared to be of type string() and integer().  Why is 
> that acceptable?  In my error printout it shows dialyzer interpreting 
> the fields as type any().

The type any() means "anything goes".  It's possible that you are not 
fully aware of what specs and type declarations in records do. They put 
extra constraints that have to be compatible with the types that 
dialyzer infers (the so called "success typings"). An inferred type of 
any() for some record field is compatible with a user declaration that 
the field is of type string().  If compatible, the strongest of the two 
-- in this case string() -- is used from then on.

Kostis


More information about the erlang-questions mailing list