[erlang-questions] erlang sucks
Richard A. O'Keefe
ok@REDACTED
Fri Mar 14 06:16:55 CET 2008
I wrote that
>> the 'cond' proposal ... completely answers the claimed need for an
>> if
>> with user-defined functions callable in the guards.
>
On 14 Mar 2008, at 1:30 am, David Holz wrote:
> Claimed need?
Yes. CLAIMED need.
Remember, while guards resemble Erlang expressions, they are
fundamentally
different. Indeed, it is a real shame that new BIFs have been
introduced
that can be used in both guards and expressions; it would have been
better
to make the two sets of BIFs disjoint. It is also a real shame that
there
are alternatives to "," and ";" in guards borrowed from the expression
world. Again, the two should have been kept clearly distinct.
The differences really boil down to this:
guards are for INDEXING.
Just as a compiler is free to do unification in any order and to share
submatches across any number of clauses, so a compiler is free to do
guard
code in any order, to share guard tests across any number of
alternatives,
and to arbitrarily interleave matching and guard testing. For example,
I would hope a compiler to translate
p(X, "big hairy pattern") when integer(X), X > 0 -> ...
by testing the type and value of X before matching "big hairy pattern".
In order to freely reorder and share guard computations, the code must
be
known to be free of side effects, including input/output and message
passing.
To handle "exception = guard failure", it really pays to have
operations that
could raise exceptions where the index compiler can see them, not
hidden in
functions that do who knows what.
Haskell has it easier here, of course, because any side effects of a
function
must be revealed in its type.
Suppose we ha
cond E1 -> S1
; E2 -> S2
; En -> Sn
end
This can be handled pretty closely by
case E1 of true -> S1;
case E2 of true -> S2;
...
case En of true -> Sn
end ... end end
All that's really needed here is an equivalent of Algol 68's "ouse",
which was to 'case' as 'elif' was to 'if'. So add it!
case E1 of true -> S1
ouse E2 of true -> S2
...
ouse En of true -> Sn
end
"ouse" is pretty horrible (almost the only Algol 68 keyword I disliked;
what have cases got to do with the river Ouse?). Doubtless some better
keyword could be found. 'orca', perhaps? (Joke.)
> Predicate functions are absolutely necessary in handling dispatch
> decisions for any sort of system whose message vocabulary is
> upgraded over time, in my experience.
Just today I found that something I thought for *sure* was a Boolean
function actually needed to distinguish three cases. I have to agree
that *classification* functions are necessary; it is far from obvious
that they have to be Boolean. Again, in Haskell I often find that
something I originally thought of as returning a Boolean should return
a Maybe or Either instead.
Above I explained why changing 'if' to be 'cond' would be a bad idea.
We really do have good uses for something that acts the way 'if' does
now.
I have also mentioned the 'cond' proposal.
But I have now explained why 'cond' should normally be avoided even if
we
had it: it forces you to use Boolean results, which may seriously limit
your imagination.
Any time you have
cond p1(X) -> f(X, g1(X))
; p2(X) -> h(X, g2(X))
...
you should probably be using
case classify(X)
of {p1,G1} -> f(X, G1)
; {p2,G2) -> h(X, G2)
...
just as it is better to do
case X
of [H|T] ->
...
than
if is_cons(X) -> ... head(X) .. tail(X) ...
> Having to put the explicit matching specification any place where a
> message or data structure is handled (even for simple dispatch pass-
> through which doesn't do anything with the contents) instead of
> deferring to a predicate is a horrible violation of DRY,
I don't know what the acronym "DRY" stands for.
To the extent that I follow what you are saying here, I agree that you
shouldn't do that, but I deny that the absence of xif/cond makes you
do it.
The suggestion about something similar to C++ "constness" (really,
something
similar to what other declaration languages call "purity") is
something I
thought about back in 1988, and was actually writing up a proposal for
when
funs were introduced into the language and made it much more difficult.
C++ does it in the type system, and Erlang doesn't normally use a type
system,
because of the difficulties combining that with hot loading.
If you are generating Erlang code from a DSL, then why not just fix your
code generator?
As a matter of fact, the 'abstract patterns' proposal I put forward oh
so many
years ago would presumably solve your problem pretty much the way you
want to
solve it, because abstract patterns are sufficiently constrained that
they
CAN be safely used in guards.
f(Msg = #hello{}) -> ...
is necessarily safe, whereas
f(Msg) when strange_module:is_hello(Msg) ->
would not be.
I'm not sure whether to be gratified at how abstract patterns keep
solving
problems, or saddened...
More information about the erlang-questions
mailing list