A programming convention

Richard Carlsson richardc@REDACTED
Tue Jun 11 10:36:54 CEST 2002

On Tue, 11 Jun 2002, Joe Armstrong wrote:

> find violates the "principle of least surprise" and
> should have returned {ok, V} |{error, Why}>>
> [...]
> Now the convention. We always provide a *pair* of interface functions:
> 	lookup(Key, Dict)   -> Value | exit(Why)
> 	lookupQ(Key, Value) -> {ok, Value} | {error, Why}

I don't think {error, Why} is a good idea in cases like this.
First, let me say that I really do advocate a standardised maybe()
type for Erlang programs. However I don't think it should be mixed
with error descriptors. If it _is_ an error, then let it remain an
exception. If it is expected behaviour, then the "Why" part is
not relevant: typically (if you program with the maybe() pattern),
there is exactly one reason for "error", and any other exceptions
that may be raised during execution are _real_ errors. Suppose for
instance that you have a bug in your dictionary implementation which
suddenly triggers - do you want this to be transformed into a term
{error, Why}? (Probably, the application will then just toss away the
Why part and continue as if the key was not present. Bad thing.)

I usually use:

	maybe() ::= {value, X} | none

which I think has a more neutral look-and-feel than "ok" and "error",
even though "value" is 3 chars longer than "ok". :-]

For instance, it makes it look less weird to store a maybe() type in
a record field or similar:

	X#foo{a = {value, 42}, b = none, c = lookupQ(Key, Dict)}

("ok" and "error" would definitely seem strange here.)

In dictionary-like functions, I myself generally use "lookup" for the
maybe()-version, and "get" for the exception-raising version.
A naming convention for indicating that a function returns a maybe()
type might or might not be a good thing; I don't feel so sure that it
applies to other cases than dictionary lookup. In many cases you
might want to write functions that do return a maybe() type, but
which don't really have (or need) an exception-raising version. Should
you still feel obliged to name the function "fooQ" although there will
never be a "foo"?

> 	lookup(Key, Dict) ->
> 	    case (catch lookupQ(Key, Dict)) of

As a final comment regarding efficiency: Yes, exceptions are supposed to
be exceptional, but not extremely so. Even if you change to zero-cost
setup (which I believe that we have in HiPE these days), it must still
remain feasible to use "throw" for nonlocal returns - being able to do
so is part of the programming model.


Richard Carlsson (richardc@REDACTED)   (This space intentionally left blank.)
E-mail: Richard.Carlsson@REDACTED	WWW: http://www.csd.uu.se/~richardc/
 "Having users is like optimization: the wise course is to delay it."
   -- Paul Graham

More information about the erlang-questions mailing list