[mercury-users] Error detection rate in Mercury vs Other Languages (esp C++ and Python)

Chris King colanderman at gmail.com
Sat Dec 3 04:12:18 AEDT 2011


On Fri, Dec 2, 2011 at 12:40 AM, Peter Ross <pro at missioncriticalit.com> wrote:
> I do most of my development in Java and Mercury.  In Java it is much
> more likely for the program to compile, but much more likely to throw
> an exception the first time you run the program.

I'd like to chime in though that Mercury's failure model lets a
particularly pernicious class of bugs slip through easily; namely,
those bugs in which you expect a result from some predicate but
receive none, i.e., a predicate is failing for the wrong reason.  To
give a specific example:

% Set X -> Y in the map only if X < Y.
:- func set_mapping(int, int, map(int, int)) = map(int, int) is semidet.
set_mapping(X, Y, Map0) = map.insert(X, Y, Map0) :- X < Y.

set_mapping(3, 5) will spuriously fail in the event that 3 was already
in the map.  Obviously the programmer meant to use map.set (which
can't fail) instead of map.update (which can fail), but Mercury
doesn't catch this.  (Of course, one can use the declarative debugger
to easily track down the bug, but that requires that the bug be
caught, and failure bugs can be buried deep in a program and exhibit
themselves subtly.)

In Java and similar languages, where failure is often indicated by an
exception (or null result, which would trigger an exception), the
above error would be caught at compile time (assuming checked
exceptions) or produce a backtrace at runtime.  Of course, the
programmer could have wrapped the whole function in a try/catch which
ignores all exceptions, but this is explicit and a well-known code
smell.

Mercury *can* catch these errors at compile time, but it is up to the
programmer to declare more specific "det" modes (when possible),
annotate his code with "require_det" checks, or to break up his code
into smaller predicates and forgo use of mode inference.  e.g.:

set_mapping(X, Y, Map0) = Map :-
    X < Y,
    require_det Map = map.insert(X, Y, Map0).

Mercury would then catch the unintended use of map.insert instead of map.set.

This means that large "semidet" (or "nondet") procedures *without*
either at least one declared "det" (or "multi") mode or prolific
"require_det" checks should be considered a code smell in Mercury,
just like explicitly ignoring exceptions is considered a code smell in
Java.  Here I would say Java has a leg up on Mercury, because its code
smell is in the *presence* of certain code, while Mercury's is in the
*absence* of certain code.

Of course, this is a problem not just with Mercury, but with logic
languages in general.  Prolog is probably the worst offender, having
no notion of checked determinism.  Mercury at least provides the tools
for such compile-time error checking, which is a credit to its
developers!

- Chris

--------------------------------------------------------------------------
mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the users mailing list