[E-Lang] Syntax change: reducing side-effects
Mark S. Miller
markm@caplet.com
Mon, 12 Feb 2001 01:00:36 -0800
At 07:39 PM Sunday 2/11/01, Dan Moniz wrote:
>I fully support anything that'll make my work easier, of course, and this,
>along with the new twine data type are welcome changes.
This change makes good compilation much easier. A win all around.
>Something I was thinking of the other day -- Eiffel-like Design by Contract
>in E. Doable?
I'll answer this first while pretending not to have read yet the rest of
your message, so I can start with the conventional interpretation of "Design
by Contract".
Yes and no, sorta kinda. There are several aspects to Eiffel's support for
design by contract. In a way, all it is is a fancy assertion management and
checking system for message pre-conditions & post-conditions, and
object-state invariants. In any language with the equivalent of C's assert,
you can simply assert pre-conditions at the beginning of your methods,
assert post-conditions at the end of your methods, and assert object-state
invariants at places after you have mutated state in the flow control
where the object is supposed to be consistent again, such as at the end of
public mutating methods.
There are many linguistic features that Eiffel adds to this, but to my mind
the most valuable addition is a notation (a conventional place to put the
checks), set of tools (which rewards your efforts), and a culture of
expectations (seeded by Meyer's many books, some quite good), that nudge the
programmer into actually putting such checks into their programs, and to
attempting to design abstractions that can be adequately checked by such
tools. This design for checkability may be more valuable than the actual
checking.
Looked at in this way, E isn't as good as Eiffel, but it ain't too shabby.
By generalizing type declarations to guard expressions, E allows arbitrary
user-defined correctness checks (and more) to be placed on parameter
variables (for variable-based pre-conditions), return values (for
post-conditions), instance variables (for variable-based invariants), and
on any other variables you have laying around. Dean reminded me that, unlike
Eiffel, I need the "variable-based" qualifier above because my guards
naturally only constrain each variable separately, rather than constraining
the incoming message or object state as a whole.
require() and the "_{ expr }" thunk syntax
E does have an assert-like construct named "require". In at least
stl-0.8.9k on, it's used like this:
require(x*y < 37, _{ `Product of $x and $y must be smaller` })
and implemented as
define require0 {
to (cond, thunk) {
if (! cond) { throw(thunk()) }
}
to (cond) {
require0(cond, _{"required condition failed"})
}
}
Recall that "_{ expr }" expands to "define _() :any { expr }".
(Don't worry about "require" vs "require0". It's a kludge to get around a
name-space bootstrapping issue.)
If the "cond" argument to require is false, it calls its thunk argument and
throws what the thunk returns. (The other clause just provides a default
problem report to throw.) This gives me an opportunity to follow up on an
earlier thread I let drop: Despite our earlier thread about dangerous
accidental return-value leakage, I defined "_{ expr }" to expand using
":any" rather than ":void" because I expect this syntax to be most often
used for calculate-on-demand expressions, as above. If the cond argument is
true, the thunk argument never gets called.
Ignoring the thunking of the second argument, this seems an awful lot like
an assert. However, it has one crucial difference which takes E farther
from Eiffel. An assert is an optional check. A require is a mandatory one.
Our guards also differ from Eiffel's checks in this way -- they also
express mandatory check. These checks are part of the semantics of the E
program. If you removed them from a correct E program, or somehow silently
turned them off, you would have a broken program. The removal is not
correctness preserving.
For invariants and post-conditions, this is probably a weakness of E
compared to Eiffel. For Eiffel's design goals, this inability to turn off
E's pre-condition checking would also be seen as a weakness. However, for
E's design goals, an object with *optional* preconditions checking is
probably a security hole. With such checking off, it "relies" on its
clients, and so is "delicate". While on rare occasions it is appropriate to
code a delicate object, capability style is to avoid these like the plague.
An object's correctness should almost never be at the mercy of the behavior
of its clients. The occasional delicate object should be painted in
blinking red neon polka dots, so no one forgets to handle it with care.
While E could probably be improved by importing more of Eiffel's virtues,
I'm more interested in annotations like the old "rely" and "suspect", that
are more directly targeted at the issues capability programmers need to
worry about. See also Marc Stiegler's rather amazing
http://www.skyhunter.com/marcs/trustrule.htm . We know it to have many
fatal flaws, but it points the way to something very important.
Contract vs Contract
>If so, here's a completely not-thought-out extrapolation:
>Smart Contracts in E that contract other E installations to build E
>programs. Self-generating mobile code (of a sort) designed by contract
>(complete with confinement, etc.).
>
>I have to run the idea through more particular paces, and see if there are
>any real places it would be valuable, but it seems, at first glance, to be
>interesting.
My first reaction to this was: Now wait a second. What the
Object/Eiffel/"Design by Contract" people mean by "Contract" has nothing to
do with what Smart Contracting people mean by "Contract". But then I
realized that they both have strong similarities with real world contracts,
from which both stole the term. While "similar to" isn't necessarily
transitive, it certainly make a connection plausible.
However, having realized a connection is possible, I still don't see one.
In any case, if I understand you, the harder issue above is the automatic
generation of an implementation from a specification. Although impressive
work on this has been done (back when people did that sort of thing), it's
so much harder than everything else we're doing put together that it's not
high on my agenda. That fruit hangs so high you need a spaceship to pick it.
Cheers,
--MarkM