[E-Lang] down with `define' (was: newbie syntax: picayune
points from a prejudiced programmer)
Mark S. Miller
markm@caplet.com
Sat, 03 Mar 2001 10:34:04 -0800
At 03:50 AM Saturday 3/3/01, Ka-Ping Yee wrote:
>> Waddaya think?
>
>In all, fantastic. Some of these simplifications are things i've
>wished for for a long time. The others all seem sensible.
Thanks!
>One note:
>
>> c) The thunk shorthand:
>>
>> _{ ... }
>
>Flagging a thunk with "_" is, in my opinion, just silly.
Agreed. We got there by a historical derivation that was sensible at the
time. (See "Lighter Weight Syntax for Anonymous Closures" in
http://www.eros-os.org/pipermail/e-lang/2001-January/004123.html .) I quote
the beginning of this section below to set context (but it's also good to go
back and read the original):
I wrote:
>Among lexical lambda languages, a controversial issue is the need for
>macros. Scheme provides very principled macros, and Scheme programmers find
>themselves needing to use and invent new macros all the time. Scheme
>without macros is considered painful.
>
>Java has no macros, but those who have experienced macros elsewhere find
>their lack a constant irritation, [...]
>
>Smalltalk also has no macros, and they aren't missed. There was a time in
>which I was switching between Smalltalk and a language with macros [...],
>Even then, I rarely felt the lack of macros in Smalltalk. [...]
>
>[...] Smalltalk ha[s] a significantly lighter weight closure syntax than
>Scheme, so Smalltalk programmers were willing to say, effectively, "lambda"
>when they needed to.
A concrete example in E is "require", which is like C's "assert" except to
switch turns it off. It is defined as:
def require0 {
to (cond, thunk) {
if (! cond) { throw(thunk()) }
}
to (cond) {
require0(cond, _{"required condition failed"})
}
}
(Don't worry about "require" vs "require0". This is needed to work around a
bootstrapping problem is seeding the universalScope.)
And it's used as
require(i >= j, _{`$i must be smaller than $j`})
If the condition is false, then the quasi-literal string expression is never
evaluated to an actual string. Similarly for more expensive expressions we
may write to give ourselves better diagnostics.
When we adapt Brian Marick's tracing system
http://www.erights.org/elib/Tracing.html for use from the E language, this
issue will be pervasive. In both cases, extra syntactic cost means either
fewer diagnostics, or diagnostics that are cheap when not computed.
For a completely different example, the new Kernel-E looping construct is as
naturally used:
loop( _{ expr })
as many user-defined looping constructs would now be.
>This should be explicit -- it should say
>
> thunk { ... }
>
>or -- in grand Scheme and Python tradition --
>
> lambda { ... }
That's why neither of these work for me, but...
>You could also consider "def { ... }", i suppose.
...might. It sounds silly, but the Scheme vs Smalltalk experience says
these extra characters might make the difference.
Although I seem to be contradicting myself, I don't much care about the
length difference between "def" and "_". My problem with using "def" for
this is simply that it does not define any names, and unlike "def _ ..." it's
not a name defining construct that you can look at and say "Ah, there's a
placeholder here instead of the name." Nevertheless, I still find it
plausible.
>This permits
>"def :any { ... }" etc. (No name, no arguments means -- no name,
>no arguments!)
This would make "def" a fatal choice, since its only required syntactically
lightweight use is a value-returning thunk used as a conditionally evaluated
value, as shown above for "require".
Consider also the security-useful variant:
once(_{ expr })
whose thunk-like value can be called at most once. Or the interesting
lazyPromise(_{ expr })
that returns a promise for the value of expr, but only evaluates expr
(once) should anyone send any messages to this promise. The promise would
then resolve to that value. If expr throws an exception, the promise
becomes a broken reference. All this can now be coded in unprivileged E.
There are probably a dozen other idioms in this same category that I haven't
thought of.
Therefore, we can't adopt a syntax that implies the usual ":void" default.
>As a side note, i'll mention that the "lambda" keyword in Python
>has finally come to really mean "lambda", pretty much.
Doesn't seem like a part of the design space that admits a "pretty much".
No smooth hills to climb, only scraggy cliffs, deep ravines, and telephone
poles. In what ways is Python's "lambda" still not lambda?
Cheers,
--MarkM