[erlang-questions] http_uri_parse/1 inconsistent return value + dialyser headache

22 views
Skip to first unread message

Zabrane Mickael

unread,
Aug 14, 2012, 6:32:25 AM8/14/12
to Erlang Questions
Hi guys, Hi Kostis,

http_uri_parse/1 returns inconsistent value since 15RB.
I'm trying to build a wrapper around it to make my code works on =<R14B04 too.

Here's what i got so far:

-spec http_uri_parse([byte()]) -> {ok, tuple()} | {error, atom()}.
http_uri_parse(URL) when is_list(URL) ->
case http_uri:parse(URL) of
{ok,{Scheme, UserInfo, Host, Port, Path, Query}} -> %% >=R15B
http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query);
{Scheme, UserInfo, Host, Port, Path, Query} -> %% =< R14B <------- LINE 1106
http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query);
Error ->
Error
end.

http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query) ->
{ok, {Scheme, UserInfo, Host, Port, Path, Query}}.

But Dilayzer isn't happy:

Checking whether the PLT /Users/younes/.otp_plt is up-to-date... yes
Proceeding with analysis...
pimco.erl:1106: The pattern {Scheme, UserInfo, Host, Port, Path, Query} can never match the type {'error','no_scheme' | {_,atom(),_}}


Any hint/help to get rid of this warning?

Regards
Zabrane
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://erlang.org/mailman/listinfo/erlang-questions

Motiejus Jakštys

unread,
Aug 14, 2012, 6:46:28 AM8/14/12
to Zabrane Mickael, Erlang Questions
On Tue, Aug 14, 2012 at 1:32 PM, Zabrane Mickael <zabr...@gmail.com> wrote:
> Hi guys, Hi Kostis,
>
> http_uri_parse/1 returns inconsistent value since 15RB.
> I'm trying to build a wrapper around it to make my code works on =<R14B04 too.
>
> Here's what i got so far:
>
> -spec http_uri_parse([byte()]) -> {ok, tuple()} | {error, atom()}.
> http_uri_parse(URL) when is_list(URL) ->
> case http_uri:parse(URL) of
> {ok,{Scheme, UserInfo, Host, Port, Path, Query}} -> %% >=R15B
> http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query);
> {Scheme, UserInfo, Host, Port, Path, Query} -> %% =< R14B <------- LINE 1106
> http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query);
> Error ->
> Error
> end.
>
> http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query) ->
> {ok, {Scheme, UserInfo, Host, Port, Path, Query}}.
>
> But Dilayzer isn't happy:
>
> Checking whether the PLT /Users/younes/.otp_plt is up-to-date... yes
> Proceeding with analysis...
> pimco.erl:1106: The pattern {Scheme, UserInfo, Host, Port, Path, Query} can never match the type {'error','no_scheme' | {_,atom(),_}}
>
>
> Any hint/help to get rid of this warning?

One way would be to define a constant at compile-time which version of
Erlang are you running. Then check for it in source and put the right
function/case statement accordingly.

rebar -> erl_opts -> platform_define is one of the ways to define that constant.

--
Motiejus Jakštys

Zabrane Mickael

unread,
Aug 14, 2012, 6:56:44 AM8/14/12
to Motiejus Jakštys, Erlang Questions
Thanks Motiejus,

Yep, that's a way to solve it.
Anything else?

Regards,
Zabrane

Magnus Henoch

unread,
Aug 14, 2012, 7:04:04 AM8/14/12
to Zabrane Mickael, Erlang Questions
Zabrane Mickael <zabr...@gmail.com> writes:

> http_uri_parse/1 returns inconsistent value since 15RB.
> I'm trying to build a wrapper around it to make my code works on =<R14B04 too.
>
> Here's what i got so far:
>
> -spec http_uri_parse([byte()]) -> {ok, tuple()} | {error, atom()}.
> http_uri_parse(URL) when is_list(URL) ->
> case http_uri:parse(URL) of
> {ok,{Scheme, UserInfo, Host, Port, Path, Query}} -> %% >=R15B
> http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query);
> {Scheme, UserInfo, Host, Port, Path, Query} -> %% =< R14B <------- LINE 1106
> http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query);
> Error ->
> Error
> end.
>
> http_uri_parse_1(Scheme, UserInfo, Host, Port, Path, Query) ->
> {ok, {Scheme, UserInfo, Host, Port, Path, Query}}.
>
> But Dilayzer isn't happy:
>
> Checking whether the PLT /Users/younes/.otp_plt is up-to-date... yes
> Proceeding with analysis...
> pimco.erl:1106: The pattern {Scheme, UserInfo, Host, Port, Path, Query} can never match the type {'error','no_scheme' | {_,atom(),_}}
>
>
> Any hint/help to get rid of this warning?

You've already been given the nice way to do it, so let me show the
hackish way to get rid of the warning. Dialyzer can't infer anything
about what a 'catch' expression returns, so if you write this instead:

case catch http_uri:parse(URL) of

then Dialyzer won't complain.

An advanced variant of that is to define a ?catch_for_dialyzer macro
that expands to nothing for normal compilation, and to 'catch' when
running Dialyzer.

Regards,
Magnus

Motiejus Jakštys

unread,
Aug 14, 2012, 7:23:20 AM8/14/12
to Magnus Henoch, Erlang Questions
On Tue, Aug 14, 2012 at 2:04 PM, Magnus Henoch
<magnus...@erlang-solutions.com> wrote:

> Zabrane Mickael <zabr...@gmail.com> writes:
>
> An advanced variant of that is to define a ?catch_for_dialyzer macro
> that expands to nothing for normal compilation, and to 'catch' when
> running Dialyzer.

Interesting. How do you know when you are running in dialyzer (i.e.
how would you define that macro)?

--
Motiejus Jakštys

Magnus Henoch

unread,
Aug 14, 2012, 8:06:06 AM8/14/12
to Motiejus Jakštys, Erlang Questions
Motiejus Jakštys <desir...@gmail.com> writes:

> On Tue, Aug 14, 2012 at 2:04 PM, Magnus Henoch
> <magnus...@erlang-solutions.com> wrote:
>> Zabrane Mickael <zabr...@gmail.com> writes:
>>
>> An advanced variant of that is to define a ?catch_for_dialyzer macro
>> that expands to nothing for normal compilation, and to 'catch' when
>> running Dialyzer.
>
> Interesting. How do you know when you are running in dialyzer (i.e.
> how would you define that macro)?

The only way I know is to have your build system pass different -D flags
for normal compilation and dialyzer.

Regards,
Magnus

Zabrane Mickael

unread,
Aug 14, 2012, 8:38:19 AM8/14/12
to Magnus Henoch, Erlang Questions
Following Magnus & Motiejus great suggestions, here it is:

%-------- put this marco somewhere (.hrl, top of your .erl)
-ifdef(DIALYZER_CATCH).
-define(CATCH_FOR_DIALYZER(X), catch X).
-else.
-define(CATCH_FOR_DIALYZER(X), X).
-endif.

%------- the new code
-spec http_uri_parse([byte()]) -> {ok, tuple()} | {error, atom()}.
http_uri_parse(URL) ->
case ?CATCH_FOR_DIALYZER(http_uri:parse(URL)) of
{ok,{_, _, _, _, _, _}} = Ret15 -> %% >=R15B
Ret15;
{_, _, _, _, _, _} = Ret14 -> %% =< R14B
{ok, Ret14};
Error ->
Error
end.

Add this flag "-DDIALYZER_CATCH=1" to your Dialyzer command line:
$ dialyzer --src src --plt /path ... -DDIALYZER_CATCH=1

Everything's perfect now.

Thanks for sharing these guys.
You saved my day.

Regards,
Zabrane
Reply all
Reply to author
Forward
0 new messages