[E-Lang] Hydro & E operator expansions

Mark S. Miller markm@caplet.com
Tue, 20 Mar 2001 15:34:20 -0800


The most concrete issue in integrating Hydro & E is syntax, which is mostly 
a matter of deciding what the operators expand to, and what these expansions 
mean.  

The following are some proposed changes to the expansion from Tyler, which I 
believe are the same as those he proposed in the earlier Hydro discussion on 
the list.  I don't believe I'd responded then.  The following are my 
initial responses.  At the bottom of this message are thoughts since this 
back-and-forth with Tyler.



Tyler wrote:
>Following are the operator renamings:
>
>Unary Operators         E with Hydro         E as it is
>---------------         ------------         -----------
>()                      evaluate()           run()

"evaluate" is simply wrong.  An expression evaluates in a scope to a value. 
In the old eval/apply duality, this is closer to apply.  A lambda expression 
evaluates to a function, and a function is applied to arguments.  But 
"apply" would be a lousy name as a message to a function with the arguments 
as arguments, since it is the function being applied to the arguments, not 
the other way around.  And I won't call it "applyYourselfTo".

What's wrong with "run"?  It's what java.lang.Runnable uses.


>!                       isEmpty()            not()

"isEmpty" sounds specific to collections.  When "b" is a boolean, the expression 
"!b" would expand to "b isEmpty()".  It is perverse to think about testing 
whether a boolean is empty of truth.


>~                       inverted()           complement()

I don't currently have a strong reaction, but what's wrong with "complement"?


>-                       reversed()           negate()

Same objection as with isEmpty().  Having "-i" expand to "i reversed()" is 
just too strange.  In what sense can we think of negating an integer as 
reversing it?


>Binary Operators
>----------------
>+                       with()               add()

It's strange for "3 + 5" to expand to "3 with(5)" in order to mean the sum 
of 3 and 5, but I might be able to live with it if there were compelling 
reasons to.

However, to have "[1, 2] + [3, 4]" evaluate to "[1, 2, [3, 4]]" destroys the 
"+" operator.  My generalized sense of "+" is that if it's two operands are 
both of type T, then the result is of type T.  If the operands are of 
different types, then one or both are coerced to reduce it to the first 
case.  The computation performed by this first case should be associative 
(modulo roundoff errors).  Arithmetic addition and sequence concatenation 
both satisfy this general sense of "+".  Using this general sense of "+", 
the equivalent of your

    [1, 2] with(3)   # which evaluates to  [1, 2, 3]

could sensibly be written as

    [1, 2] + [3]   # which doesn't expand to "with", but has the same effect

but not

    [1, 2] + 3


>-                       without()            subtract()

Same objection as with "+".


>/                       divide()             approxDivide()

This may be a good idea.  But what would you have divide() do on integers?


>[]                      search()             get()

Why?  What's wrong with "get"?


>Composite Operators
>-------------------
>&~                     mask()               currently uses &! for butNot()

I think "mask" is plausible either as a replacement for the name "butNot", 
or, if we need both operations (I hope not), then "mask" is a fine expansion 
of "&~", while "butNot" can remain the expansion of "&!".

As to whether "&~" should replace "&!", this is also plausible.  I remember 
thinking about this and choosing "&!" rather than "&~" for a reason, but I 
don't currently recall it.  If I continue to fail to recall it, I'll assume the 
old reason no longer applies.


-----------------------------------

After this message, Dean pointed out Python's convention of naming the 
operator expansions in a distinct fashion.  So instead of expanding "a + b" 
to "a add(b)" as we now do, or "a with(b)" as Tyler proposes above, we could 
instead expand to "a op__plus(b)" or some such.  The method name "op__plus" 
is clearly not primarily making a statement about semantics, but instead 
makes it clear that it's participating in the expansion of an operator.  
This should help de-couple language design from library design, which is a 
good thing.  Of course, we still need common agreement on what "+" means 
when applied to a primitive datatype that's considered part of the language, 
so most of the original problem remains.

Does anyone object to this Python-like style of naming operator expansions?


        Cheers,
        --MarkM