[erlang-questions] http:request

Klas Johansson klas.johansson@REDACTED
Fri Apr 22 10:17:53 CEST 2011


On Fri, Apr 22, 2011 at 9:49 AM, Kostis Sagonas <kostis@REDACTED> wrote:
> Carlo Bertoldi wrote:
>>
>> Il 21/04/2011 17:10, Carlo Bertoldi ha scritto:
>>>
>>> Good afternoon,
>>>  I have a problem with http:request.
>>>
>> <snip>
>>>
>>> Result = http:request(get, {CompleteUrl, [{"User-Agent", "Erl-bot"}]},
>>> [], []),
>>> io:format("Result = ~p~n", [Result]).
>>>
>>> Occasionally I don't see Result printed, but a nice error:
>>> ** Reason for termination ==
>>> ** {{badmatch,{16,6,18}},
>>
>> Hello, I discovered the cause of the badmatch: it was due to the debug
>> macro I've defined.
>> Here it is:
>>
>> -define(DBG(Str, Args),
>>  {Year, Month, Day} = date(),
>>  {Hour, Min, Sec} = time(),
>>  io:format("~2.10.0B/~2.10.0B/~4B ~2.10.0B:~2.10.0B:~2.10.0B [~p:~p] - ",
>> [Day, Month,
>>       Year, Hour, Min, Sec, ?MODULE, ?LINE]), io:format(Str, Args)).
>>
>> Can someone explain me what I did wrong here? Why should I obtain a
>> badmatch on {Hour, Min, Sec} = time() ?
>
> A typical reason for this is if you used the macro in some context where
> variables named Hour, Min, and Sec already existed.  This is called name
> capture and is a typical problem of macros. You should carefully examine all
> places in the code where this macro is used.  Alternatively, you can try to
> minimize the risk of name capture by changing the macro to e.g.:
>
> -define(DBG(Str, Args),
>        {Year__, Month__, Day__} = date(),
>        {Hour__, Min__, Sec__} = time(),
>   io:format("~2.10.0B/~2.10.0B/~4B ~2.10.0B:~2.10.0B:~2.10.0B [~p:~p] -  ",
> [Day__, Month__, Year__, Hour__, Min__, Sec__, ?MODULE, ?LINE]),
> io:format(Str, Args)).

Perhaps you're using the same macro in multiple places in the same
scope (for example on two consecutive lines)?  Like this:

    some_function(...) ->
        ...
        ?DBG("foo ~p", [SomeVal1]),
        ...
        ?DBG("bar ~p", [SomeVal2]),
        ...

Now, the macro will be expanded during preprocessing:

    some_function(...) ->
        ...
        {Year__, Month__, Day__} = date(),
        {Hour__, Min__, Sec__} = time(),
        ...
        {Year__, Month__, Day__} = date(),
        {Hour__, Min__, Sec__} = time(),
        ...

Since time flies, seconds etc. change and will no longer match ==> badmatch.

I guess you could either write a function which prints the timestamp
(and takes ?LINE as a parameter) or use a trick like eunit uses for
its assert macros to bind variables in a new scope (it looks a bit
funny and you still need to take care to use unique variable names
like Kostis suggested):

    (fun() -> {Year__, Month__, Day__} = date(), ... end)()


    https://github.com/erlang/otp/blob/dev/lib/eunit/include/eunit.hrl#L141


Cheers,
Klas



More information about the erlang-questions mailing list