[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

define -- a modest proposal



    Date: Fri, 30 May 86 10:40 EST
    From: MITCHELL WAND <WAND%northeastern.edu at CSNET-RELAY.ARPA>

    I think it is clear that we do not have a consensus on the semantics
    of internal DEFINE.  

This isn't clear to me.  I thought we had always agreed that internal
definitions were just sugar for LETREC (see Will's message of 11 November
84, excerpted below).

			 My understanding of the compromise reached at
    Brandeis was that lexically nested DEFINE would retain the MIT
    semantics, whereas the IU semantics could be obtained by using
    DEFINE! .  The current report does not appear to be compatible with
    that compromise, because it would appear necessary to do a

    (define foo 'hunoz)

    at top-level before one can legally do a set! on foo from an interior scope.

At first I thought that you had misremembered, but I just went back to
the archives, and you are right.  However, DEFINE! was later flushed --
without any liberalization of SET! .  The discussion was obviously
incomplete (as you can tell by reading it), and we're completing it now.
Will did the right thing since he flushed features that not everyone
wanted, namely (a) DEFINE! and (b) an environment in which SET! could
cause unbound variables to become bound.  See the Appendix to this
message for the exchange.

I was moderately happy with how that turned out and implicitly assumed
that if people had serious troubles with the RRRS they would have spoken
up ages ago.  My attempts to clarify things have apparently drawn
attention to issues which have been peacefully asleep for over a year.

    Analyzing this situation, there are two operations involved in a define:

    1.  Binding the identifier to some location.
    2.  Storing a value in that location.  

    The latter operation is clearly doable by set!, so the only issue is #1.
    The MIT semantics has DEFINE performing #1 on the current scope.  The 
    advantage of this proposal is that it is uniform on both "top-level" and 
    interior scopes.  The disadvantage is that it essentially creates a new scope 
    (region) in the program which is not delimited by parentheses.

This is true, the region is only the <body> of the LET or whatever
expression, not the entire expression, so the region isn't delimited by
left and right parentheses.  The region of a definition at top level of
a file is similarly not delimited by parentheses, although for a
slightly different reason.  I wouldn't say the definition creates the
scope, I'd say that the scope is created by the expression in whose body
the definition appears.  But what is so unusual about this?  The region
of a binding created by LET is also not delimited by parentheses; it's
not the entire LET expression.

    [Perhaps the 
    grammar could be fixed to recognize this new, non-list-structure phrase?].

What change do you suggest?  Why don't <body> and <program> foot the
bill?  A <body> is exactly the region of the bindings specified by
internal definitions which begin it.  A <program> (which, I suppose, is
the concatenation of all the files comprising a running Scheme program,
or something like that) is the region of bindings created by top level
definitions.

    This is an unpleasantness at the top level which I do not think we
    understand.

I guess I'm losing track of what you're saying.  I agree that there is
much unpleasantness, but to which one are you referring?

In Algol 60 a <program> is a <block> or a <compound expression>, so
Algol 60 has the property you want, that regions are always fully
parenthesized (by BEGIN ... END).  I always rationalized Scheme's lack
of "outermost parentheses" by the fact that there would be no point in
having them if you would always have to write them -- they would be
redundant.  I imagine that those parentheses are there, just outside the
edge of my files, providing a region for my files' top level bindings to
live in.  (The T compiler actually puts the parentheses there, treating
a file boundary as a sort of a macro.)

The main unpleasantness I see is the syntactic oddity that a <program>
is a sequence of intermixed <expression>s and <definition>s (it's very
important that <definition>s aren't <expression>s!), whereas a <body> is
a sequence of <definition>s followed by a sequence of <expression>s.  I
think I suggested fixing this a while ago (whether to people at MIT or
to RRRS-Authors I don't remember), so that <program>s and <body>s could
have the same syntax and semantics (if internal definitions were
supported at all, that is), but this suggestion was not well received.
This change would make Scheme like Algol 68, which also allows one to
intersperse statements and declarations within a "series" (the region
("range") of a declaration includes previous statements and declarations
in its "series").  The other way to resolve the inconsistency is to be
like Algol 60 and require that all the definitions in a program go at
the top, before any statements (expressions), but somehow I don't think
people would buy that.

    [Perhaps we should separate DEFINE into two procedures:

    (make-local-variable 'foo)
    (set! foo value)

A reasonable idea.  In MIT Scheme, (make-local-variable 'foo) is written
(define foo).  (Or do you really mean a procedure?)  If people like this
feature (which causes the variable to become bound but unassigned, like
in LETREC) I'd be happy to see it go into the report.  It is bothersome
that one has to specify an initial value, and this seems as good a way
as any to avoid having to do so.

    [Another, separate, argument against including internal define as an
    optional feature in the report is that, unlike the other optional
    features in the report, it requires pervasive modifications in many
    other sections of the report].

I agree that the presentation is bad.  This is a real problem which, as
I said in my message to Dan, I think I can fix, by going back to
something closer to Will's approach, which was much less intrusive.  I
take full responsibility for having screwed this up.

    What I will argue for is the following:

    An implementation may have a top level (initial, whatever) environment in 
    which every possible identifier is bound (though only some are initialized).

    This would allow programs in that implementation to do a set! on a global 
    variable (excuse me, a variable in the current top-level environment) 

[Can you define "current"?]
									  from an 
    internal scope without having to explicitly bind the variable in the initial 
    scope.  It would also allow MIT-style define to proceed, as it does not 
    require the existence of a distinguished global environment.

    I think this proposal retains the spirit of the Brandeis agreement on this 
    issue.

If people generally think it's OK if this is documented as an optional
language feature (as was DEFINE! previously), I don't have too much
problem with putting it in the report, if it's accompanied by some
mention of the fact that some implementations have principled reasons
for not having this feature.  (Dan has complained to me, however, that
he doesn't want the report to contain advertisements for random features
of various dialects, so I wouldn't know quite how to do this.)  My main
complaint is that it would be nice to be able to support as many as
possible of the report's non-essential features in T and MIT Scheme, and
it would be a substantial amount of work to implement this particular
feature in T and MIT Scheme; causing assigned variables to become bound
in an appropriate contour involves a bothersome non-local code
transformation.

The MIT Scheme and T designers have worked hard to implement truly
block-structured languages which, like Algol, have no distinguished
top-level environments.  (Algol 68's "standard prelude" and its
mechanism of "particular-programs" is block structure to the max -- can
someone tell me what would correspond to the proposed SET! extension in
Algol 68?)  Legitimizing binding-from-a-distance (or environments in
which all variables are bound, which amounts to the same thing) in the
Scheme report is a threat to the pedagogical and engineering effort
we've put in.  Of course, de-legitimizing unprepared SET!'s is
apparently a threat to your investment.  I thought the compromise in the
RRRS was a good one considering how different our world views were.

With apologies to you and Dan for the angry tone & the abundance of
parenthetical remarks.  I'm tired.

Jonathan.


------

APPENDIX.  Historical record of the DEFINE! and SET! debate.

Clinger, 11 Nov 84, preliminary report on the workshop:
    (DEFINE id expr) allows top-level definitions of variables.  Its
    semantics at top level are similar to the semantics of
    (SET! id expr).  The difference is that if id is not already
    bound to a location, then the DEFINE form binds id before
    performing the assignment, whereas it would be a mistake to
    perform a SET! on an unbound identifier.

    Optionally, (DEFINE! id expr) is equivalent to (DEFINE id expr)
    when typed at the top level.  Within code, (DEFINE! id expr) is
    equivalent to (SET! id expr) unless id is unbound, in which case
    the DEFINE! form creates a new top level binding for id before
    performing the assignment.

    Optionally, DEFINE may be used for internal definitions as in MIT
    Scheme and in the book by Abelson and Sussman.  If allowed at
    all, internal definitions are permitted only in the bodies of
    LAMBDA, LET, LETREC, and similar binding constructs.  Furthermore
    they must precede the rest of the body.  With these restrictions,
    the semantics of internal definitions can be explained in terms
    of LETREC.  For example, ...

Pitman, 6 Dec 84:
    The term "top-level binding" is ... completely vague in DEFINE!'s
    definition.

Rees, 14 March 85:
    ... And incidentally, I don't remember the rationale for having both
    DEFINE! and DEFINE.  I understand why DEFINE shouldn't have hairy
    syntax, but what does DEFINE! give you that the stripped-down DEFINE
    doesn't?

Clinger, 18 March 85, "final" draft of report:
    (define! var expr)                                   special form
    
    If var is bound, then the define! form is equivalent to the 
    corresponding set!.  If var is unbound, however, define! binds 
    var in the global environment before performing the assignment.  

Haynes and Friedman, 27 Mar 85:
    DEFINE!  and DEFREC!  should go away.  (Yes, We were among those who
    wanted them originally, but they aren't worth it.) We're not fond of
    DEFINE either and wish it could go the same way, or at least be
    optional.

Bartley, 29 March 85:
    I'm willing to lose DEFINE! and DEFREC!, as Chris and Dan suggest.

Rozas, 27 March 85:
    How am I supposed to define things if both DEFINE! and DEFINE 
    go away?

Haynes, 29 March 85, answering Rozas:
    With SET!, provided one assumes that all identifiers are initially bound in
    the global environment, or that SET!  can extend the global environment.
    With the exception of MIT's Scheme, this is what existing systems do.  If MIT
    is unwilling to change this, then we are reluctantly stuck with DEFINE.

Hanson, 30 March 85, answering Haynes:    
    This is a terrible idea.  It seems that the ability to have many
    different environments in which to perform incremental definitions has
    been consistently overlooked by almost everyone except MIT Scheme and
    T.  Anyone who has ever tried to program a BIG system, and by that I
    mean something over 500-1000 pages of code, knows that this kind of
    packaging is **ESSENTIAL**!!  So please don't try to take this away.

Haynes, 31 March 85, answering Hanson:
    We grant the importance of such a facility, and are not trying to take it
    way; but there is no concensus on how to provide such a facility, so it
    is too soon to standardize on one.  (Similarly, syntactic extensions
    are **ESSENTIAL** to the kind of thing we do here; but it is also too soon
    to standardize on a syntactic extension mechanism.)

    We were simply debating whether SET! should be required to extend the
    global environment if its identifier is unbound (or equivalently, have
    everything bound in the global environment to begin with).  This would
    make DEFINE unessential, though it might still be optional.  It has
    nothing to do with multiple environments for incremental definition,
    except that MIT uses DEFINE for both purposes.

Hanson, 2 April 85, answering Haynes:
    What I wanted to say was: if SET! extends the "global" environment,
    then that environment has become special in that it is the ONLY
    environment that can be extended by interactive definition.  This
    would seem to preclude the existence of many such environments.
    DEFINE eliminates the problem, because it specifies, very precisely,
    the environment in which the name is bound.

Clinger, 20 April 85:
    define! and defrec! will be flushed altogether.



Note: no one at Indiana replied to Hanson's message, even though it
isn't conclusive.  (I don't even think it's true; there could be
multiple "global" environments, and SET!'s could be associated with them
lexically.)  Did they assume that SET! would be changed?