[erlang-questions] Dialyzer question

Steve Strong <>
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 < (mailto:)> 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
> >  (mailto:)
> > 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.html>


More information about the erlang-questions mailing list