[erlang-questions] Trouble with init/1 spec
Kostis Sagonas
kostis@REDACTED
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