[erlang-questions] eep: multiple patterns

Richard A. O'Keefe <>
Fri May 16 02:35:54 CEST 2008

On 15 May 2008, at 11:07 pm, Andras Georgy Bekes wrote:
>> Let's start with the pattern-match operator,
> It seems to me you also finished with the pattern-match operator.
> The other part of the eep (multiple patterns) is OK?

As I said later in that message, I decided that I had enough for
one message.  There are a number of unpleasant aspects to the
details of the multiple pattern proposal.  Amongst them, the fact
that "|" is already a very important symbol in Erlang with about
as different a meaning as you could imagine, and the fact that it
not merely perpetuates but expands a nasty hole in Erlang.  Let
me briefly explain that point.

	If a language allows a complex construction,
	it should let you *name* an abstraction of that
	construction and uses instances of it.

To give an example where this isn't done, consider Java 1.5.
You can have types like
	Map<String,Map<String,Vector<Long> > >
but you cannot *name* any of these; only classes can have names.
So when you see
	Vector<Long> x;
	Map<String,Vector<Long> > y;
	Map<String,Map<String,Vector<Long> > > z;
there is no immediately visible connection between these types.
It's enough to make you reach for dear old M4 so you can write

	define(Features, `Vector< Long >')
	define(Product_Name, `String')
	define(Catalogue, `Map< Product_Name, Features >')
	define(Company_Name, `String')
	define(Meta_Catalogue, `Map< Company_Name, Catalogue >')

	Features x;
	Catalogue y;
	Meta_Catalogue z;

In the same way, in Erlang at present we can write complicated
expressions, and we have abstractions of expressions, called
functions.  We have complicated patterns, BUT we have no named
abstractions of patterns.

The multiple pattern proposal makes patterns even MORE complicated,
without naming them, so a human being reading one has to do an
immense amount of decoding to figure out what the pattern *means*.
If there are several places where you need (basically) the same
complex pattern, too bad: you have to write the thing out in full
each time because you can't NAME it and use it more than once.
This is a disaster for maintenance, because it is far too easy to
change *some* of the occurrences of the pattern and not others.

Abstract patterns let you name patterns (simple, complex, or already
in the first proposal, MULTIPLE) and use them whenever you want.

While the multiple patterns proposal is not _technically_ flawed,
or at least, not obviously so, it is not good software engineering.

>> So instead of adding a new "crippled-bind" called ~=,
>> I suggest that it would be better to allow
>> Pattern = Expression as a guard.
> You can't negate it!

Who says?  According to the current on-line Erlang reference
manual, you can't negate *anything* in a guard, so this is nothing
new.  If you want to extend the syntax so that you *can* negate
things in a guard, then why shouldn't = be as negatable as
anything else?  As long as we stick with the idea that guards
are *NOT* things that evaluate to true or evaluate false, but
rather things that succeed or fail, it is clear that Pat=GdExp
can succeed or fail, so it makes just as much sense to negate
*that* as anything else in a guard.

> I've also written, I think the most important use of the ~= operator  
> was
> to express negated patterns, i.e. the ability to write a guard that
> fails if (some part of) the matched value matches a pattern. It seems
> you completely missed this point.

Not *addressing* a point isn't the same as *missing* it.
Here's what the proposal actually says:

... the most important use
     of the operator would be to extend pattern matching with negated
     patterns as in the following example pattern:

         PATTERN1 when not (PATTERN2 ~= Variable_bound_by_PATTERN1)

I'm sorry to have to point this out, but this is not an example.
It's a *schematic* example, that illustrates but does not exemplify.
Once again I want ACTUAL examples from real programs.

By the way, the syntactic operator '~=' includes a character that
is used for negation in many languages, not least including C,
C++, C#, and Java.  I'm used to reading "~=" as "not equals", so
to me "when not (Pat ~= GdExp)" looks like a double negation, and
I find myself wanting to simplify it to "when Pat = GdExp".
If you want to appeal to UNIX tradition for pattern matching
operators, the traditional UNIX symbol for this is a simple "~"
as in the AWK expression "$1 ~ /^fred/".

> Please propose a different construct that expresses negated patterns,
> and is easy to implement, understand and use.

I am very far from being convinced that negation in patterns is
at all a good idea.  In fact, I think it has the potential to be
very confusing indeed.  However, I have now explained that

  - allowing = in guards is *always* more powerful than adding ~=
  - there is no reason why = in a guard cannot be negated,
    if there is anything in a guard that can be negated.

Now I add

  - my proposal has no new construct, it just removes a restriction
    on the use of an existing construct, so it is at least as easy
    to use and understand as ~=

  - the implementation of ~= would be very nearly identical to the
    implementation of =; there seems to be no reason to believe that
    = is any harder to implement in guards than ~=

I also repeat what I've been saying all along, which is that
the abstract pattern proposal has been around for a long time, and
keeps on turning out to be just right for new problems.

Let's suppose you want to express

	when not {foo,_,27} = X

OK, so write

	#foo_response(ping) -> {foo,_,27});
	#foo_response(pong) -> {foo,_,42});
	#foo_response(pang) -> bar.

   ...   when #foo_response(Pung) = X, Pung /= ping

We really cannot discuss this much further without *concrete cases*
so that we can judge what might *actually* be written.

> I think I am not allowed to copy-paste code pieces from AXD301 here.
> Beleive me, I could.
> Do you want me to obfuscate and send a few?

Yes please.

>> Oh, and did I point out that abstract patterns can solve the
>> "multiple patterns" problem neatly and clearly?
> I accept your abstract patterns as useful and nice, but is quite a big
> change in the language. My proposal is a small change.

Your proposal adds TWO changes to the language:
"|" in clause heads, and "~=" in guards.
> Easy to learn,

Just because something is small does not mean it is easy to learn.
As I've argued above, both "|" and "~=" are as confusing as heck.
("|" otherwise means "cons", "~" can mean "not" in other languages.)
"~=" is riddled with special restrictions.

> easy to implement,
> easy to document, no compatibility issues.

Yes, but if one is changing a language, one may as well make ONE change
that solves LOTS of problems, rather than cluttering it up with dozens
of special-purpose kluges.

"I don't want to discuss evidence." -- Richard Dawkins, in an
interview with Rupert Sheldrake.  (Fortean times 232, p55.)

More information about the erlang-questions mailing list