[erlang-questions] Dialyzer question
Steve Strong
steve@REDACTED
Mon Nov 14 12:32:32 CET 2011
That makes some sense, and indeed if I just export test/0 then it does work nicely. Alas, do_something is what I really want to be exporting and if I do so, then dialyzer stops warning me. I completely understand that in isolation, dialyzer has to infer that do_something can return any() - I was hoping that it would adjust that inference when in the context of the caller, where the mapping function is constraining the return type.
Again, this seems analogous to lists:map/2, which is exported and yet dialyzer seems to do "the right thing".
Confused :)
-- Steve Strong
@srstrong
Sent with Sparrow (http://www.sparrowmailapp.com/?sig)
On Monday, 14 November 2011 at 11:58, Joe Armstrong wrote:
> Change export_all to
>
> -export([test/0]).
>
> Then you'll get this:
>
> test.erl:8: Function test/0 has no local return
> test.erl:9: The pattern {'rec2', _} can never match the type #rec1{}
>
> With export_all the arguments to do_something are totally unconstrained and can come from
> any wild place - so the inferred types are too permissive.
>
> With export_all typer infers the following:
>
> > typer test.erl
> %% File: "test.erl"
> %% ----------------
> -spec test() -> #rec2{}.
> -spec do_something(_,fun((_) -> any())) -> any().
> -spec map(_) -> #rec1{}.
>
> The (.... any()) -> any() is because the second argument of do_something can come from anywhere
> so there are no type errors
>
> But with -export([test/0]). we get this:
>
> -spec test() -> none().
> -spec do_something(1,fun((_) -> #rec1{})) -> #rec1{}.
> -spec map(_) -> #rec1{}.
>
>
> /Joe
>
>
>
>
> On Mon, Nov 14, 2011 at 11:40 AM, Steve Strong <steve@REDACTED (mailto:steve@REDACTED)> wrote:
> > Hi All,
> >
> > I have a question on the behaviour of Dialyzer with higher-order functions. Consider the following trivial code:
> >
> > -module(test).
> >
> > -compile(export_all).
> >
> > -record(rec1, {fred}).
> > -record(rec2, {harry}).
> >
> > test() ->
> > #rec2{} = do_something(1, fun map/1).
> >
> > do_something(Num, MapFun) ->
> > MapFun(Num).
> >
> > map(_X) ->
> > #rec1{}.
> >
> > If I run Dialyzer against it, I get no errors or warnings logged, even though it's quite apparent that it will fail. I would have expected that Dialyzer could infer that the return type of do_something was the return type of MapFun; within the context of do_something(), that is clearly any(), but within the context of test() I would have thought that it could see that do_something() is actually going to return a #rec1{} record, that being the return type of map().
> >
> > If I replace the call to MapFun with a call to map(), as in:
> >
> > do_something(Num, _MapFun) ->
> > map(Num).
> >
> >
> > Then everything works as expected - Dialyzer correctly tells me that my code is broken. Is there anything I can do to "teach" dialyzer how to interpret the MapFun? It works as I would like with functions such as lists:map():
> >
> > -module(test).
> >
> > -compile(export_all).
> >
> > -record(rec1, {fred}).
> > -record(rec2, {harry}).
> >
> > test() ->
> > [#rec2{}] = lists:map(fun map/1, [1]).
> >
> > map(_X) ->
> > #rec1{}.
> >
> >
> > With the above, I get the expected warning. I've looked at lists.erl, and it doesn't look to be doing anything different. It does have some -spec directives, but adding those in my code did not appear to help.
> >
> > Any hints?
> >
> > Cheers,
> >
> > Steve
> >
> > -- Steve Strong
> > @srstrong
> >
> > Sent with Sparrow (http://www.sparrowmailapp.com/?sig)
> >
> >
> > _______________________________________________
> > erlang-questions mailing list
> > erlang-questions@REDACTED (mailto:erlang-questions@REDACTED)
> > http://erlang.org/mailman/listinfo/erlang-questions
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20111114/a21b7228/attachment.htm>
More information about the erlang-questions
mailing list