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
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