[eeps] EEP XXX: Pattern-test operator
Richard O'Keefe
ok@REDACTED
Fri Apr 13 02:46:47 CEST 2012
On 13/04/2012, at 11:51 AM, Erik Søe Sørensen wrote:
> <EEP-pattern_test_operator.md>
(0) Congratulations and thanks for providing a reference
implementation.
(1) PLEASE don't take the binary ~ operator; we need
that for frames, and we need frames URGENTLY.
The use of "~" is indeed backwards compatible
with respect to existing _code_ but not with
respect to existing _EEPS_.
(2) I don't understand why it is not sufficient to
allow <pattern> = <guard expression> as a guard
expression. That would be a simple change that
would increase the simplicity of the language
by removing a constraint; this change makes the
language *more* complex.
The argument near the end I find unconvincing in
the extreme: = isn't *supposed* to return booleans,
and guards should never have had 'and' 'or' 'andalso'
or 'orelse' in the first place but should have nested
the existing ',' and ';'. Guard tests drive control
NOT by returning true or false but by SUCCEEDING or
FAILING, and that's *exactly* what = does.
It is already a readability problem that = can appear
deeply nested inside expressions, and the proposed
inverted ~ worsens this amazingly: not only may
bindings be hidden deep inside surprising places,
they may be hidden in two opposing orders with
subtly different semantics.
(3) Since we have the syntax <pattern> = <expression>,
requiring <expression> ~ <pattern> is very nearly
unforgivable. The EEP confused me enormously
until I got my head around this inversion.
(4) case ... of
X when X ~ {ok,A}; X ~ [okay,A} -> ...A...
end
In "[okay,A}", is "[" a typo for "{"
or is "}" a typo for "]"? This can be handled
by a proposal I _think_ there is an EEP for to
allow
case ...
of {ok,A}
; {okay,A} -> ... A ...
end
the generalisation being that
<pattern> [when <guard>]
is replaced by
<pattern> [when <guard>] {; <pattern> [when <guard>]}...
That may have been one of the EEPs I could not write up
because there is no serious definition of .md syntax and
semantics.
case E0 ~ P of true -> E1; false -> E2 end
seems like a strange way to write
case E0
of P -> E1
; _ -> E2
end
(5) The "bindings are only accessible" part is not specified
precisely. In particular, consider
(X ~ {foo,A} orelse X ~ {bar,A} orelse X ~ {ugh,A})
andalso ... A ...
Is some binding for A accessible after andalso, and if
not, why not? If it were written
case X
of {foo,A}
; {bar,A}
; {ugh,A} -> ... A ...
end
the variables available at the arrow would clearly and
simply be the intersection of the variables available
after each pattern/guard.
(6) The EEP has very few examples that cannot be done as well
or better using Pattern = Guard_Expr in a guard and/or
the generalised case, both of which make disjunction of
pattern/guards readily expressible. The main novelty
seems to be "anything but this".
For example,
receive
X when ( F = {'$gen_cast',_} = X
orelse F = {'$gen_call',_} = X
orelse F = ok
) andalso F = ok ->
neatly handles the "not a {'$gen_cast',_} or {'$gen_call',_}"
example, and all it needs is to allow Pattern = Expression in
a context where people already expect it to be allowed.
In general, I must say that I have learned over the painful
years to loathe and dread "anything but <this>" matches in
whatever language they are found. If Erlang makes it hard
to express such proven bug-breeder, all the better for
Erlang.
The lack of negative patterns is a positive BENEFIT of the
way Erlang is now; sabotaging this aspect of Erlang would be
done at our peril.
All things considered, I think that the sharper the distinction
between pattern/guards and expressions the better; it helps to
keep Erlang readable in a way that anything-goes-anywhere doesn't.
(7) We keep on getting odd limited or dangerous proposals for
things that are neatly and simply solved by abstract patterns.
For example,
#int_point(X, Y)
when is_integer(X), is_integer(Y)
-> {X, Y}.
#two_int_points(X = #int_point(_,_),
Y = #int_point(_,_))
-> {X, Y}.
Yes, the abstract patterns EEP notes that allowing patterns in
guards is a prerequisite. That mean we ALREADY have an EEP that
proposes patterns in guards. But that meant the existing =
with the existing semantics; just a restriction removed.
This new proposal is far more elaborate than the abstract
patterns EEP requires, far more confusing, and far more dangerous.
Once we have abstract patterns, there would be little or no
reason to _use_ the inverted ~ in actual source code.
(8) The thing I don't get a feeling for is how _much_ of a problem
this EEP solves. When similar things have come up in the past
I have asked for concrete examples, and have generally been
able to show that it is possible to rewrite the real code in
existing Erlang with good clarity without new features.
(Or with abstract patterns as the only new feature.)
More information about the eeps
mailing list