user-defined operators
Richard A. O'Keefe
ok@REDACTED
Thu Apr 1 03:18:38 CEST 2004
I am now totally baffled:
Samuel Rivas <samuel@REDACTED> wrote:
1 > As you stress, a symbol that can represent different
1 > operations in different contexts is said to be "overloaded". +
1 > ++ and * are DIFFERENT operations, your definition says nothing
1 > about using the same function name to indicate those operations.
I replied:
2 > Nor does it say anything about the Arian controversy, bimetallism, or the
2 > interpretation of quantum mechanics. Why should one little definition have
2 > to deal with quite irrelevant matters?
Now Samuel Rivas <samuel@REDACTED> has replied to that:
3 > It should deal with function names if you want it to justify your
3 > assertion:
3 >
3 > By the definition I use, a symbol which is bound to a single
3 > definition is not overloaded, no matter how many types that definition
3 > applies to.
I am really confused by this.
My assertion is "The definition of overloading I use is '...'."
That's a fact about me. How could my definition of "the particular
kind of user-defined operator I propose for Erlang" have any possible
relevance to that?
The definition of overloading I use just *IS*
"a symbol (whether operator symbol of function symbol) is
overloaded if and only if it is bound to more than one
operation definition".
The only way anyone could challenge that is by watching my behaviour
for a couple of weeks and seeing whether I really do use "overloaded"
that way.
By that definition, C++ and Java have overloaded symbols (Java has
system-defined and user-defined overloaded method symbols and system-
defined but not user-defined operator symbols) and Haskell and Erlang
do not. They just don't. It really is beyond debate that *by THAT
definition*, they really don't. I don't have to justify this; anyone
who doesn't believe it can check for themselves.
I'm not proposing to change that. In this thread, I have nothing new
to say about Erlang functions. It is quite unreasonable for someone to
demand that my proposal for user-defined operators should say something
about function names when I have already said over and over and over that
I have nothing new to say about them.
> In Erlang, +, ++, and * are bound to different definitions.
> There is no proposal in this or any other thread to change that.
Where did I write there is a proposal to change these operators?
When you said that introducing user-defined operators would mean that
you didn't know what operators (and you specifically mentioned + ++ *)
meant any more.
> Erlang *already* permits the definition of a function which sometimes
> calls one, sometimes calls the other, of those operations. That function
> is nevertheless itself still ONE "operation".
So, is your f(X,Y) when integer(X) ... overloaded or not? In your
previous mail you said that is a *single* definition, which necessarily
lead us to the fact that an operator bound to f is not overloaded.
How many times do I have to say it?
f/2 in that example has ONE definition.
It is a CONFUSING function but not an OVERLOADED function.
Erlang simply doesn't have any mechanism for overloading functions.
Therefore an operator `f` referring to f can no more be overloaded
than f can.
> People seem to be arguing against user-defined operators on the grounds that
> operators have some kind of unique sacred character that makes them different
> from functions. But in EXISTING Erlang this is not so.
Agreed, that is not the point.
If it isn't the point, what the h*** WAS your point?
Erlang *with* user-defined operators will not have any problems
that Erlang *without* user-defined operators does not have right now.
If you agree with me, then you have no argument against user-defined
operators. If you don't, then that *IS* precisely the point.
> Currently you can have confusing functions, but the set of
> operators is well defined and (more or less) widely accepted (I
> really don't like the ++ operator since it's just the same as
> lists:concatenate and you have to know it because of
> optimisation issues).
>
> I don't know what is meant by "widely accepted" here. It is, of course,
This is meant everybody can assume +, *, ++, /, !, ... will do
what are supposed to do.
AND THEY STILL CAN.
I am not trying to say introducing user defined operators will
change the meaning of these built-in operators but that you can
find one operator that is not "universal" (and I trying to argue
in favour of this will be not a good thing)
Do you mean "CAN find" or "CAN'T find"? And what do you mean by
"universal"? I am really having great trouble understanding this
paragraph.
> accepted that the set of Erlang operators is what it is; since the
> language was first defined there can hardly ever have been a single day
> when it was widely accepted that it was what it should be. Right at the
> moment, Joe Armstrong has a proposal for an additional operator, !!,
> which is *not* well defined,
Perhaps "well defined" is not a good description. I meant "well
known".
In that case, so what? The proposal for user-defined operators
does not change the set of "well known" operators in any what whatsoever.
> Anyone who wants to pretend that + and * in Erlang do one and only one
> thing is living in fantasy land. And you cannot use Erlang for long
> without discovering that X!Y does different things depending on what X is.
> (Related things, yes. The same things, no.)
I still don't know where I wrote that.
It is a reasonable inference from what you wrote:
(A) You were attacking user-defined operators as bad.
(B) Specifically, you were attacking them on the grounds of "overloading".
(C) You implied that the existing set of operators was OK.
But if acting differently for different argument types is bad,
and any existing operators act differently for different argument types,'
then the existing set of operators (leaving aside ++ which you said you
didn't like, although oddly enough ++ and -- do NOT have this property)
cannot be good.
> "functions are bound to programmers skills"? I can make no sense of this.
> Perhaps that proves your point, whatever it is.
When you are reading a program written by someone you can't assume
all functions do what you suppose them to do.
Well, no. You as reader have a responsibility to read the internal
documentation. So what? WHY SHOULD OPERATORS BE EXEMPT FROM THAT RULE?
It is programmer responsibility to write his functions right.
However you can assume what operators will do if the set of
operators is defined by the language.
You should imagine me pounding the keyboard and screaming in
frustration here.
(1) When you are reading a program in any programming language,
you cannot assume that all operators do what you suppose them to do.
(For example, the arithmetic operations in Erlang do *not* treat
floating-point numbers in a way that I regard as tolerable, let
alone reasonable. This came as a rather nasty surprise).
You have the *SAME* obligation to read the documentation of
built-in operators that you have for any other kind of symbol.
(2) Built-in operators are in NO WAY different from built-in function
symbols. When I'm using <math.h> in C, I have the *same* (I really
do mean, according to the standardisers, *exactly* the same) right
to trust the behaviour of pow() as I have to trust the behaviour
of *, the fact that one is written in parenthesis-call form and the
other in operator form is WHOLLY IRRELEVANT. And I have the same
obligation to read the documentation.
(3) This applies quite generally. The things I have a right to trust
are the BUILT-IN things, not the things that are invoked via some
particular synyax. I have the SAME right to trust aString.length()
in Java that I have to trust aString+aString; both are equally
built-in. In Erlang, it isn't just the built-in OPERATORS that
you get to use and trust, it's the built-in FUNCTIONS as well.
There is no meaningful difference between ++ and length/1 here.
The distinction you are making between operators and functions
is not in fact the relevant distinction.
(4) What is relevant? Well, we can split operations into several
groups in several ways.
{language-defined, in standard library, from others' code, own}
x
{familiar, unfamiliar}
x
{conforms to documentation, sort of does, doesn't}
You are implying that if an operator is in the language definition,
it is familiar and conforms to its documentation. Neither of these
is necessarily true: Erlang has acquired several more operators since
the Erlang book was published, so even an experienced Erlang programmer
could find them unfamiliar, and there can be bugs anywhere. (For
example, I once had to work around a C compiler which implemented
<= as >= for unsigned integers. Strictly speaking, the compiler got
it right, the assembler was the real culprit.)
You are also implying that if a symbol is NOT a language-defined
operator, then it isn't familiar and correct. If that implication
does not hold, you have no argument. But it doesn't hold.
printf() is not an operator in C, but there can be few C programmers
who aren't familiar with it. length() is not an operator in Erlang,
but there can be few Erlang programmers who are not familiar with it.
An Erlang programmer should become very nearly as familiar with the
functions in Erlang's stdlib as with the built-in operators.
For reading, what counts is
(i) Can I tell what the operation *is*? (legibility)
(ii) Do I know what it means? (familiarity)
(iii) If I don't, how hard is it to find out? (accessibility of docs)
(iv) Does it actually do what it's supposed to? (correctness)
Familiarity is the key here, not the form of syntax used.
You can think reading an unknown operator is like reading an
unknown function. I will not argue against that, it is only a
personal point of view. I only want to point that, up to this
moment, opening the set of operators will add more complexity to
source code reading, and that can be worth doing it on not.
(5) In the proposal we are discussing, it is COMPLETELY OBVIOUS which
operators are built in (they don't have backquotes) and which are
not (they do). Reading a use of an unknown operator really IS
like reading a call of an unknown function, because it obviously
***IS*** a function call. If you "will not argue against that",
then you have no grounds whatsoever, I really mean *NONE*, for
your claim that this will add complexity to source code reading.
In the presence of user-defined operators: anything that looks like
a built-in operator has to *be* a built-in operator and is no less
readable, anything with backquotes around it has to be a function
call and is no less readable than any other function call (more so,
in many cases).
> Do you *REALLY* think that
>
> is_element(X, S) union(S1, S2) del_element(X, S) match(X, P)
>
> are better than
>
> X `in` S S1 `union` S2 S `without` X X `matches` P
If they are not better they are, at least, the same.
The () forms are quite clearly WORSE.
We could argue about the better match for mathematical notation,
we could argue about whether it is better for the words to be in
the order that you would really like to say them,
but it is not a matter of opinion that the operator forms have one
great virtue for decoding: you don't have to count the commas.
In C or Lisp or Haskell, you don't have to count arguments to figure
out which function is involved; a function name consists solely of an
identifier. But in Erlang it is not so. An Erlang function name
consists of an identifier and an arity. To determine which function
is involved in a call, you have to count the commas and add one.
f(A,B) and f(A,B,C) call unrelated functions.
When you see A `f` B, it can't possibly be a call to f/3.
Languages are designed with a certain operator precedence to avoid the
ambiguity, because infix notation IS ambiguous.
Ah, now I understand your form of argument.
Every man is a cripple, because if he didn't have his legs, he would
be a cripple.
Every system of infix operators is ambiguous, because if it didn't
have its system of precedence, it would be ambiguous.
This is a particularly dishonest way to attack user-defined operators,
because in fact the proposal under consideration ISN'T ambiguous; for
any given construct containing user-defined operators, there is only
one possible way they can be read.
Note, by the way, that it is entirely possible to have a notational
system in which there are infix operators, but absolutely no ambiguity,
even in the absence of any precedence. Anyone who wants to argue about
notational engineering should be familiar with such systems.
Yes, yes, my question was about the real meaning of /
Who knows what the real meaning of / is? I was there responding to
a claim about the operators taught in school, and at least in my
generation, / was NOT the operator used for division in school.
> I'm old enough to remember when 2/6 was half a crown,
> feature of PL/I.)
Oh! What function is supposed to be / then? (just curious, again)
It's a punctuation mark:
pounds/shillings/pence
day/month/year
I'm trying to set out my view, you can think I am a scaremonger
if you want. For me I'll keep thinking it's only I don't agree
with you like you don't agree with me.
You are saying that user-defined operators will make things bad.
You have no sound arguments for it,
and you have no empirical evidence for it.
That's scaremongering.
I _have_ empirical evidence (Haskell and Prolog experience) that it
doesn't make things bad, and sound arguments that it _can't_ make
things worse.
That's more than just disagreement.
It may be that the majority of Erlang programmers have some kind of
visual defect (or, more plausibly, horribly bad fonts) which will make
it impossible for them to read tokens containing backquotes. It may
be that their primary school teachers programmed them to get confused
when they see backquotes (I see the fnords!). It may be that Erlang
programmers just aren't as intelligent as Prolog or Haskell or Algol 68
programmers. So it's possible that empirical evidence could be found
discrediting `operators`. But I have a high opinion of Erlang
programmers and of primary school teachers.
More information about the erlang-questions
mailing list