Typespecs of functions that may fail

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Typespecs of functions that may fail

Bastien Chamagne
Hello,

I'm trying to use dialyzer and I don't know how to type functions that are written in "happy path" (may crash).
Here's a sample function that may or may not crash depending if Field correspond to a relation field on given Model:

    -spec is_relation(field(), model()) -> {true, relation_type()} | false.

    %% @doc Sets a relation on the given model.
    -spec set_relation(field(), model(), model()) -> model() | no_return().
    set_relation(Field, RelatedModel, Model) ->
        % On next line, I'm OK that this function crashes if I try to set a relation on a non-relation field
        {true, RelationType} = is_relation(Field, Model),
        set_relation(Field, RelatedModel, Model, RelationType).

Here's what dialyzer says:

    model.erl:180: Function set_relation/3 has no local return
    model.erl:181: The pattern {'true', RelationType} can never match the type 'false'

Is there anything that I can do to inform dialyzer that this is a OK behaviour for me?

Cheers!

ps: I'm using erlang 17 if that matters.
ps: Sorry if it's a duplicate, I can't find the previous message on the archive.


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Typespecs of functions that may fail

Stavros Aronis
Hi Bastien,

can it be the case that "is_relation/2" is only used "locally" (i.e. within the module itself) and all such calls to "is_relation/2" will return 'false'?

This looks like a case where dialyzer has inferred such a thing and thus complains about the pattern that can't match.

Regards,

Stavros

On Tue, Jan 17, 2017 at 3:47 PM, Bastien Chamagne <[hidden email]> wrote:
Hello,

I'm trying to use dialyzer and I don't know how to type functions that are written in "happy path" (may crash).
Here's a sample function that may or may not crash depending if Field correspond to a relation field on given Model:

    -spec is_relation(field(), model()) -> {true, relation_type()} | false.

    %% @doc Sets a relation on the given model.
    -spec set_relation(field(), model(), model()) -> model() | no_return().
    set_relation(Field, RelatedModel, Model) ->
        % On next line, I'm OK that this function crashes if I try to set a relation on a non-relation field
        {true, RelationType} = is_relation(Field, Model),
        set_relation(Field, RelatedModel, Model, RelationType).

Here's what dialyzer says:

    model.erl:180: Function set_relation/3 has no local return
    model.erl:181: The pattern {'true', RelationType} can never match the type 'false'

Is there anything that I can do to inform dialyzer that this is a OK behaviour for me?

Cheers!

ps: I'm using erlang 17 if that matters.
ps: Sorry if it's a duplicate, I can't find the previous message on the archive.


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Typespecs of functions that may fail

Bastien Chamagne

Thank you for the quick reply Stavros!

You mean that dialyzer inference is stronger than the defined typespec?


On 01/17/2017 04:08 PM, Stavros Aronis wrote:
Hi Bastien,

can it be the case that "is_relation/2" is only used "locally" (i.e. within the module itself) and all such calls to "is_relation/2" will return 'false'?

This looks like a case where dialyzer has inferred such a thing and thus complains about the pattern that can't match.

Regards,

Stavros

On Tue, Jan 17, 2017 at 3:47 PM, Bastien Chamagne <[hidden email]> wrote:
Hello,

I'm trying to use dialyzer and I don't know how to type functions that are written in "happy path" (may crash).
Here's a sample function that may or may not crash depending if Field correspond to a relation field on given Model:

    -spec is_relation(field(), model()) -> {true, relation_type()} | false.

    %% @doc Sets a relation on the given model.
    -spec set_relation(field(), model(), model()) -> model() | no_return().
    set_relation(Field, RelatedModel, Model) ->
        % On next line, I'm OK that this function crashes if I try to set a relation on a non-relation field
        {true, RelationType} = is_relation(Field, Model),
        set_relation(Field, RelatedModel, Model, RelationType).

Here's what dialyzer says:

    model.erl:180: Function set_relation/3 has no local return
    model.erl:181: The pattern {'true', RelationType} can never match the type 'false'

Is there anything that I can do to inform dialyzer that this is a OK behaviour for me?

Cheers!

ps: I'm using erlang 17 if that matters.
ps: Sorry if it's a duplicate, I can't find the previous message on the archive.


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions




_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Typespecs of functions that may fail

Stavros Aronis
Yes. Dialyzer collects all local calls to a non-exported function and analyses its body with the additional constraint that the arguments given to the function are only the ones in those calls. In such cases it may be able to infer types that are stronger than the relevant specs (you can get a warning about the spec itself by using the "-Wunderspecs" option).

You can eliminate the warning by e.g. exporting 'is_relation/2' or by using it locally in situations where it may also return `{true, ...}`.

Cheers!

Stavros


On Tue, Jan 17, 2017 at 4:22 PM Bastien Chamagne <[hidden email]> wrote:

Thank you for the quick reply Stavros!

You mean that dialyzer inference is stronger than the defined typespec?


On 01/17/2017 04:08 PM, Stavros Aronis wrote:
Hi Bastien,

can it be the case that "is_relation/2" is only used "locally" (i.e. within the module itself) and all such calls to "is_relation/2" will return 'false'?

This looks like a case where dialyzer has inferred such a thing and thus complains about the pattern that can't match.

Regards,

Stavros

On Tue, Jan 17, 2017 at 3:47 PM, Bastien Chamagne <[hidden email]> wrote:
Hello,

I'm trying to use dialyzer and I don't know how to type functions that are written in "happy path" (may crash).
Here's a sample function that may or may not crash depending if Field correspond to a relation field on given Model:

    -spec is_relation(field(), model()) -> {true, relation_type()} | false.

    %% @doc Sets a relation on the given model.
    -spec set_relation(field(), model(), model()) -> model() | no_return().
    set_relation(Field, RelatedModel, Model) ->
        % On next line, I'm OK that this function crashes if I try to set a relation on a non-relation field
        {true, RelationType} = is_relation(Field, Model),
        set_relation(Field, RelatedModel, Model, RelationType).

Here's what dialyzer says:

    model.erl:180: Function set_relation/3 has no local return
    model.erl:181: The pattern {'true', RelationType} can never match the type 'false'

Is there anything that I can do to inform dialyzer that this is a OK behaviour for me?

Cheers!

ps: I'm using erlang 17 if that matters.
ps: Sorry if it's a duplicate, I can't find the previous message on the archive.


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions




_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Typespecs of functions that may fail

Kostis Sagonas-2
In reply to this post by Bastien Chamagne
On 01/17/2017 03:47 PM, Bastien Chamagne wrote:
> Hello,
>
> I'm trying to use dialyzer and I don't know how to type functions that
> are written in "happy path" (may crash).

Dialyzer's core (known as "success typings") are designed for _exactly_
this purpose.  So that you only specify what's happening in the "happy
paths", i.e., in the paths that a function returns ("succeeds").  So you
cannot (and should not) specify anything regarding the "sad paths."


> Here's a sample function that may or may not crash depending if Field
> correspond to a relation field on given Model:
>
>     -spec is_relation(field(), model()) -> {true, relation_type()} | false.
>
>     %% @doc Sets a relation on the given model.
>     -spec set_relation(field(), model(), model()) -> model() | no_return().
>     set_relation(Field, RelatedModel, Model) ->
>         % On next line, I'm OK that this function crashes if I try to
> set a relation on a non-relation field
>         {true, RelationType} = is_relation(Field, Model),
>         set_relation(Field, RelatedModel, Model, RelationType).
>
> Here's what dialyzer says:
>
>     model.erl:180: Function set_relation/3 has no local return
>     model.erl:181: The pattern {'true', RelationType} can never match
> the type 'false'
>
> Is there anything that I can do to inform dialyzer that this is a OK
> behaviour for me?

This behaviour should NOT be OK for you.  Dialyzer is telling you that
it has somehow discovered that it your is_relation/2 function call
always returns 'false' here.  Unless your version of Dialyzer has some
bug, which is unlikely, you cannot ignore that this warning.

In any case, the problem is not in the set_relation/2 function but in
the is_relation/2 function for which you have not showed us its code;
actually, you need to show us the whole module in order to tell you with
certaintly what's happening.


Kostis

PS. Types of the form  type() | no_return()  are equally verbose as
writing 42 + 0 for the integer 42 ...
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Typespecs of functions that may fail

Bastien Chamagne
Makes perfect sense! Thank you Kostis for this explanation.

I'll dig deeper.



On 01/17/2017 04:52 PM, Kostis Sagonas wrote:

> On 01/17/2017 03:47 PM, Bastien Chamagne wrote:
>> Hello,
>>
>> I'm trying to use dialyzer and I don't know how to type functions that
>> are written in "happy path" (may crash).
>
> Dialyzer's core (known as "success typings") are designed for
> _exactly_ this purpose.  So that you only specify what's happening in
> the "happy paths", i.e., in the paths that a function returns
> ("succeeds").  So you cannot (and should not) specify anything
> regarding the "sad paths."
>
>
>> Here's a sample function that may or may not crash depending if Field
>> correspond to a relation field on given Model:
>>
>>     -spec is_relation(field(), model()) -> {true, relation_type()} |
>> false.
>>
>>     %% @doc Sets a relation on the given model.
>>     -spec set_relation(field(), model(), model()) -> model() |
>> no_return().
>>     set_relation(Field, RelatedModel, Model) ->
>>         % On next line, I'm OK that this function crashes if I try to
>> set a relation on a non-relation field
>>         {true, RelationType} = is_relation(Field, Model),
>>         set_relation(Field, RelatedModel, Model, RelationType).
>>
>> Here's what dialyzer says:
>>
>>     model.erl:180: Function set_relation/3 has no local return
>>     model.erl:181: The pattern {'true', RelationType} can never match
>> the type 'false'
>>
>> Is there anything that I can do to inform dialyzer that this is a OK
>> behaviour for me?
>
> This behaviour should NOT be OK for you.  Dialyzer is telling you that
> it has somehow discovered that it your is_relation/2 function call
> always returns 'false' here.  Unless your version of Dialyzer has some
> bug, which is unlikely, you cannot ignore that this warning.
>
> In any case, the problem is not in the set_relation/2 function but in
> the is_relation/2 function for which you have not showed us its code;
> actually, you need to show us the whole module in order to tell you
> with certaintly what's happening.
>
>
> Kostis
>
> PS. Types of the form  type() | no_return()  are equally verbose as
> writing 42 + 0 for the integer 42 ...
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions