Another bug in Erlang code

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

Another bug in Erlang code

Kostis Sagonas-3
  Another QUIZ inspired by bugs identified by the new type inference.


Who can spot the error in the following xmerl/src/xmerl.erl code?

============================================================================
%% @doc Exports simple XML content directly, without further context.

export_simple_content(Data, Callback) when atom(Callback) ->
    export_content(xmerl_lib:expand_content(Data),
                   callbacks(Callback));
export_simple_content(Data, Callbacks) when list(Callbacks) ->
    export_content(xmerl_lib:expand_element(Data), Callbacks).

%% @spec export_content(Content, Callbacks) -> term()
%%      Content = [Element]
%%      Callback = [atom()]
%% @doc Exports normal XML content directly, without further context.
export_content([#xmlText{value = Text} | Es], CBs) ->
    [apply_text_cb(CBs, Text) | export_content(Es, CBs)];
export_content([#xmlPI{} | Es], CBs) ->
    export_content(Es, CBs);
export_content([#xmlComment{} | Es], CBs) ->
    export_content(Es, CBs);
export_content([#xmlDecl{} | Es], CBs) ->
    export_content(Es, CBs);
export_content([E | Es], CBs) ->
    [export_element(E, CBs) | export_content(Es, CBs)];
export_content([], _CBs) ->
    [].
============================================================================

Hint: Just use your common sense from the information in function names.

Cheers,
Kostis

PS. The maintainer of xmerl might want to get in touch with me.
    I have a decently-sized list of discrepancies.



Reply | Threaded
Open this post in threaded view
|

Another bug in Erlang code

Richard Carlsson-4
Kostis Sagonas wrote:
>   Another QUIZ inspired by bugs identified by the new type inference.
>
> Who can spot the error in the following xmerl/src/xmerl.erl code?
>
> export_simple_content(Data, Callback) when atom(Callback) ->
>     export_content(xmerl_lib:expand_content(Data),
>                    callbacks(Callback));
> export_simple_content(Data, Callbacks) when list(Callbacks) ->
>     export_content(xmerl_lib:expand_element(Data), Callbacks).

Mea culpa. I guess nobody's ever called export_simple_content with
a list of callbacks, or this would have shown up. Just a copy/paste
error; cf. the function export_simple_element/2, some lines below.
Thanks for finding it. :-)

        /R


Reply | Threaded
Open this post in threaded view
|

Another bug in Erlang code

Luke Gorrie-3
In reply to this post by Kostis Sagonas-3
Kostis Sagonas <kostis> writes:

>   Another QUIZ inspired by bugs identified by the new type inference.
>
>
> Who can spot the error in the following xmerl/src/xmerl.erl code?

For fun I blindly transliterated this code into Lisp to see if CMUCL's
type inferencer would find the error. It did not, and the reason seems
to be that in Lisp you can't propagate type information nearly so much
as in Erlang and still get "no false positives". This suggests to me a
very bright future for Dialyzer :-)

The difference seems to be that in Erlang you can rely on individual
functions within a module to stay the same so it's safe to propagate
the inferred types of individual functions. In Lisp any single
function can change by itself so you never know if there will /really/
be an error at runtime.

The positive side for Lisp is that you still can propagate types that
are explicitly delcared, the type checker is built into the compiler
(used for optimization as well), and the user-interface is very
convenient.

If I add enough type declarations to my Lisp version to make the error
detectable (lame to have to, I admit) then it's able to underline the
offending expression the moment I compile the file:

  http://fresh.homeunix.net/~luke/misc/xx1.png

and if I put the mouse over that expression then it prints a
reasonably intelligible explanation at the bottom of the window:

  http://fresh.homeunix.net/~luke/misc/xx2.png

I would love to see Dialyzer similarly integrated into the normal
workflow (e.g. compiler) instead of being a separate linting tool.
That way I would use it all the time, the same way everyone uses
CMUCL's discrepency analyzer at all times.

I also posted to the CMUCL list in case they have some ideas for doing
more type propagation with this example as a motivation.

Cool stuff!

Cheers,
Luke