Re: [Scheme-reports] set! and imported identifiers Aaron W. Hsu 14 Oct 2012 01:24 UTC

Dear Marc:

Thanks for this email, as reading through it has caused me to take a
closer look at EVAL and environments in the R5RS and R6RS standards. I
have currently come to some confusing conlusions regarding the state of
the R7RS draft which I hope to address, but let me at least address your
concerns here, which I believe I can do in the context of R5RS and R6RS,
while we settle the R7RS situation.

On Sat, 13 Oct 2012 16:56:53 -0400, Marc Feeley <feeley@iro.umontreal.ca>
wrote:

> To my dismay I have stumbled across this passage, which I seem to have
> skipped, or misunderstood, in my previous readings :
>
> "In a library declaration, it is an error to import the same identifier
> more than once with different bindings, or to redefine or mutate an
> imported binding with define, define-syntax or set!.  However, a REPL
> should permit these actions."
>
> I have a problem with the restriction on set!.  What is the rationale
> for preventing set! on imported identifiers?  This restricts the
> language and adds complexity (not all variables can be written to).  It
> prevents the definition and use of a "trace" macro, live code patching,
> etc.  These are features I expect of a dynamic language and Scheme.

There are a number of reasons for this. One, it aids compilation. Two,
most module systems that I have seen work like this, or it is at least the
preferred style. Three, it doesn't actually restrict the language much at
all.

Specifically, it does not prevent live code patching, nor does it prevent
the tracing of procedures, though it does prevent certain styles of
"trace" macros being used inside of libraries, but that's pretty much a
given anyways, as using trace macros inside of libraries is guaranteed to
be a bit of a troubling ball of wax; sticky wax at that. Trace macros can
be used quite readily in other places. If you want to trace a function in
a library body, then do it like this:

(trace-define x (lambda (...) ...))

Here, you can either trace the procedure x in the library where it is
defined, or if you do not have the source code to that library, you can
trace another procedure in the importing library:

(import (rename (blah) (x %x)))
(trace-define x (lambda args (apply %x args)))

Live code patching is also supported by using getter and setter
procedures, parameters, or macros such as identifier syntax to provide a
means of accessing hidden mutable state that is not exported through the
library export.

> Moreover, it is not clear what is meant by "a REPL should permit these
> actions".  Does "eval" count as "a REPL"?  Does it mean that it is only
> OK if the "set!" was entered at *the* REPL that comes with the system?
> Or it is always OK on Scheme systems with a REPL?  Is it OK if I load
> from the REPL a file which has a function which does the "set!"?  (this
> would be consistent with the abstraction principle)

There is no restriction on SET!. EVAL is a restricted beast in both R6RS
and R5RS, with R7RS' version being less restrictive. In particular, R5RS
and R6RS both disallow mutation of bindings in environments except for the
interaction environment. The R5 and R6 versions of EVAL both either make
it an error or leave it as an unspecified extension what happens with
definitions, and in both cases explicitly disallow the mutation or
definition of bindings that were already defined in environments other
than interaction-environment. In R7RS, you can use definitions provided
that the environment is mutable, and you can SET! all you want as long as
you assign mutable variables. If the binding is immutable, then you can't
SET!, but that's all.

> If there is a restriction on set!, then I can't implement a REPL with
> eval using portable code.  I can't write a portable "trace" macro.  I
> can't write a portable debugger.

You can do this in R7RS, but you could not do this in R6RS or R5RS, as
neither one allowed for someone to portably eval definitions. Neither was
SET! allowed to mutate immutable bindings. The only portable, mutable
environment that has existed since R5RS is interaction-environment. In
R67RS, you can consider interaction-environment to be a mutable copy of
the initial imported environment with all definitions shadowed by mutable
bindings to the same. There was no portable way to create a mutable
environment in R6RS from the environment created implicitly by a library,
but you could not portably mutate an environment in R6RS, either. In R5RS,
you did not even have libraries, much less the ability to create specific
special environments.

--
Aaron W. Hsu | arcfide@sacrideo.us | http://www.sacrideo.us
Programming is just another word for the Lost Art of Thinking.

_______________________________________________
Scheme-reports mailing list
Scheme-reports@scheme-reports.org
http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports