From: MAEDA Atusi
Subject: Re: ISO/IEC CD 13816 -- ISLisp
Date: 
Message-ID: <MAD.95Dec14143551@tanzanite.math.keio.ac.jp>
>>>>> "ok" == Richard A O'Keefe <··@goanna.cs.rmit.EDU.AU> writes:
In article <··········@goanna.cs.rmit.EDU.AU> ··@goanna.cs.rmit.EDU.AU (Richard A. O'Keefe) writes:

    ok> Who precisely is helped by renaming RPLACA to SET-CAR

New users would find SET-CAR is easier to remember than some cryptic
six-char-limited name.

    ok> If you don't like the name RPLACA, just leave it out, (SETF (CAR ..) ..)
    ok> will do fine.

Maybe.  But many implementations would have something like that
anyway.  CMU CL has COMMON-LISP::%RPLACA, CLISP has SYSTEM::%RPLACA,
Allegro has EXCL::.INV-CAR, and so on.  Note that SET-CAR is
incompatible with RPLACA in its argument order and return value.  It
shares convention with other setter functions such as SET-PROPERTY,
SET-AREF, etc.  And it gives user a concrete idea of what SETF is
doing.  (CL's DEFINE-SETF-METHOD is a mess).

    [deleted...]
    ok> 2.  How easy is it to _implement_ something?
    [deleted..]

    ok>     I am not up to speed on current Lisp compilation techniques, but I
    ok>     really do get a strong impression that writing a really good compiler
    ok>     for ISlisp is not _significantly_ simpler than writing a really good
    ok>     compiler for Common Lisp.

I believe immutable binding for functions has significant impact on
the implementation techniques.  (We can't interactively redefine
functions anymore.  Shocking news, eh?).  Compiler of ISLisp can
always inline functions safely, or make a simple call instruction (as
in C).

Compare this with Scheme.  When executing procedure call (CAR
something), compiled Scheme code (without dangerous optimization) must
first fetch the value of the global variable CAR, check that it is a
procedure, and then invoke it.

This check can be omitted in Common Lisp (because of its separate
namespace for functions), but the call must be done indirectly to
retain redefinability.  Inlining functions loses redefinability in
Common Lisp. Compiled code with (DECLARE (INLINE FOO) can't reflect
later changes on FOO, for example.  This also defeats possibility of
interprocedural side-effect analysis.  Assuming function NULL is
side-effect free is as dangerous as inlining.

Local functions are easier to handle in Common Lisp, because they
cannot be redefined within their scope.  In Scheme, however,
LETREC-bound variables can be modified with SET!.  So compiler must
first prove that the value is a procedure at the time of invocation
before emitting direct call instruction.

    ok>     There is no call-with-current-continuation (so much for learning from
    ok>     Scheme).  Nor are there multiple values.  (Which _are_ in R5RS Scheme.)

CALL-WITH-CURRENT-CONTINUATION, aside from its implementation
difficulty per se, has some drawbacks.

* UNWIND-PROTECT no longer works with it.  The following code:
	(UNWIND-PROTECT
	  <some file processing>
	  (CLOSE FILE))
  looks okay.  But what will happen if someone captured continuation
  inside <some file processing> and try to resume processing later?

  Note that UNWIND-PROTECT is crucial in writing real-world
  applications.

* CALL/CC defeats some compiler optimizations.
  Without CALL/CC,
      (LET ((A ..) (B ..))
        ..
	(LET ((X (CONS A B)))
	  (FOO)
	  X) ..)
  can be safely transformed into:
       (LET ((A ..) (B ..))
        ..
	(PROGN
	  (FOO)
	  (CONS A B) ..)
  Here, A and B are lexical variables and FOO can't affect the values
  thereof.  With CALL/CC, the transformation above is not safe (if
  continuation is caputured in FOO and invoked many times, the former
  always returns identical cons cell but the latter doesn't).

  Similary,
    (LET ((A ..))
        ..
	(LET ((X A))
	  (FOO)
	  (SETQ X (+ X 1)))
        ..)
  cannot be transformed into:
    (LET ((A ..))
        ..
	(PROGN
	  (FOO)
	  (+ A 1))
        ..)
  in the presence of CALL/CC.

In summary, CALL/CC is way too general.  It's actually strictly more
general than GOTOs.  We need to restrict the usage of CALL/CC into
some structured way (i.e. only for non-local exit) until we find
better way to tame.

				--mad

From: Erik Naggum
Subject: Re: ISO/IEC CD 13816 -- ISLisp
Date: 
Message-ID: <19951215T014159Z@arcana.naggum.no>
[Atusi Maeda]

|   New users would find SET-CAR is easier to remember than some cryptic
|   six-char-limited name.

new users find FIRST and REST easier to remember and use than CAR and CDR.
if they could use SETF universally, that would also help them remember and
use Lisp correctly.  since RPLACA and SETCAR are already part of the Lisp
tradition, and FIRST and REST were adopted in Common Lisp, I find retention
of CAR and CDR while pretending to cater to "new users" somewhat specious.

|   (CL's DEFINE-SETF-METHOD is a mess).

could you elaborate on that?

|   I believe immutable binding for functions has significant impact on the
|   implementation techniques.  (We can't interactively redefine functions
|   anymore.  Shocking news, eh?)  Compiler of ISLisp can always inline
|   functions safely, or make a simple call instruction (as in C).

a Common Lisp compiler can do that with functions in COMMON-LISP, as well.
rather than throwing the baby (redefinition) out with the bathwater (lack
of static analysis), couldn't ISLisp have provided a facility to freeze
packages?  (oh, right, it doesn't have packages.)

|   Assuming function NULL is side-effect free is as dangerous as inlining.

assuming that function COMMON-LISP:NULL is side-effect free is perfectly
legitimate, as is inlining it.  Common Lisp has its good sides, although I
recognize the need for inventors of new dialects, especially political
creations such as International standards, to slam it.  (i.e., a new
dialect loses respect according as it is disrespectful of other dialects,
from which it should learn, not differ from in bitterness.)

|   In summary, CALL/CC is way too general.  It's actually strictly more
|   general than GOTOs.  We need to restrict the usage of CALL/CC into some
|   structured way (i.e. only for non-local exit) until we find better way
|   to tame.

is it meaningful to restrict a continuation to be the continuation of a
currently active activation?  i.e., not allow re-entry to a continuation
and no separate life of a continuation apart form the activation records?
this would once again make co-routines harder to implement, but that could
perhaps be another (related) concept?

I find ISLisp a depressing development.  it appears unnecessary, and it is
gratuitously different from Common Lisp.  have you failed to realize that
Lispers are facing people who want nothing stronger than to ridicule Lisp
because they don't understand it and so don't want to use it?  what better
weapon to give them than to point out that even Lispers don't want to talk
each others' languages?

#<Erik 3027980519>
-- 
suppose we actually were immortal...
what is the opposite of living your life as if every day were your last?
From: William D Clinger
Subject: Re: ISO/IEC CD 13816 -- ISLisp
Date: 
Message-ID: <4as2be$ckp@camelot.ccs.neu.edu>
While making several correct observations in article
<·················@tanzanite.math.keio.ac.jp>, ···@math.keio.ac.jp
(MAEDA Atusi) made several remarks that deserve clarification.

>Compare this with Scheme.  When executing procedure call (CAR
>something), compiled Scheme code (without dangerous optimization) must
>first fetch the value of the global variable CAR, check that it is a
>procedure, and then invoke it.

This would be true if, like Ada, it were illegal to extend Scheme.
In reality, the Scheme standards state that extensions are legal
so long as they don't conflict with the standards.  In particular,
it is legal to extend Scheme to allow the programmer to specify that
certain procedures should be inlined.  This is, of course, a very
common extension.  Since inlining is done only by permission of the
programmer, it is not a dangerous optimization.

Although Common Lisp differs from Scheme by forbidding redefinition
of CAR, it does allow the programmer to choose between inlining and
redefinition for programmer-defined procedures.

Not all languages give the programmer this choice.  MAEDA observed
that ISLISP does not.

>interprocedural side-effect analysis.  Assuming function NULL is
>side-effect free is as dangerous as inlining.

Since it is illegal to redefine NULL in Common Lisp, there is nothing
dangerous about assuming it has no side effects.

>cannot be redefined within their scope.  In Scheme, however,
>LETREC-bound variables can be modified with SET!.  So compiler must
>first prove that the value is a procedure at the time of invocation
>before emitting direct call instruction.

This is true.  It is also a very easy optimization to implement:
If a LETREC binds a variable to a procedure, and that variable
does not appear on the left hand side of a SET! within its scope,
then the compiler knows not only that that variable is a procedure
throughout its scope, but it also knows the code for the procedure.

This optimization has been in MacScheme since 1986.

>CALL-WITH-CURRENT-CONTINUATION, aside from its implementation
>difficulty per se, has some drawbacks.
>
>* UNWIND-PROTECT no longer works with it....
>
>  Note that UNWIND-PROTECT is crucial in writing real-world
>  applications.

UNWIND-PROTECT is a special case of DYNAMIC-WIND.  It is true that
UNWIND-PROTECT is not powerful enough to protect against all uses
of CALL-WITH-CURRENT-CONTINUATION.  That's why Scheme programmers
use DYNAMIC-WIND instead.

DYNAMIC-WIND is expressible in R4RS Scheme.  Portable code for
DYNAMIC-WIND is available from several sources, e.g. SLIB.

>* CALL/CC defeats some compiler optimizations.
>    (LET ((A ..))
>        ..
>	(LET ((X A))
>	  (FOO)
>	  (SETQ X (+ X 1)))
>        ..)
>  cannot be transformed into:
>    (LET ((A ..))
>        ..
>	(PROGN
>	  (FOO)
>	  (+ A 1))
>        ..)
>  in the presence of CALL/CC.

This is true, except that it isn't really CALL/CC that's to blame for
this.  It's the assignment.  To see why, consider the fact that

(let ((a ...))
  ...
  (let ((x a))
    (foo #'(lambda (v)
             (setq x (+ x 1)))))
  ...)

cannot be transformed into
           
(let ((a ...))
  ...
  (let ((x a))
    (foo #'(lambda (v)
             (+ a 1))))
  ...)

either, even in a language without CALL/CC.  My example is, of
course, equivalent to MAEDA's.

William D Clinger
From: Richard A. O'Keefe
Subject: Re: ISO/IEC CD 13816 -- ISLisp
Date: 
Message-ID: <4b35de$ilh@goanna.cs.rmit.EDU.AU>
···@math.keio.ac.jp (MAEDA Atusi) writes:

>>>>>> "ok" == Richard A O'Keefe <··@goanna.cs.rmit.EDU.AU> writes:
>In article <··········@goanna.cs.rmit.EDU.AU> ··@goanna.cs.rmit.EDU.AU (Richard A. O'Keefe) writes:

>    ok> Who precisely is helped by renaming RPLACA to SET-CAR

>New users would find SET-CAR is easier to remember than some cryptic
>six-char-limited name.

New users shouldn't be using it no matter _what_ it is called.
They should be writing
	(setf (car x) y)
instead.


>    ok> If you don't like the name RPLACA, just leave it out, (SETF (CAR ..) ..)
>    ok> will do fine.

>Maybe.  But many implementations would have something like that
>anyway.
Yes.  So what?  Using it shouldn't buy you anything that (setf (car -) -)
won't buy you.

I do appreciate the line of argument here, but it is precisely the
same kind of "nyaa nyaa ni nyaa nyaa i'm not gunna play with YOUR
language I'm gunna play with MY language" approach that nearly wrecked
the Prolog standard and quite certainly delayed it for more years than
is creditable.  We're talking about a situation where there was
 - one "Lisp" standard already official (Scheme)
   (and lots of free implementations including some great ones)
 - one "Lisp" standard in use by a large fraction of the community
   undergoing revision with the ANSI standard very close (CL)
   (and a KCL to name but one)
 - a rival "Lisp" standard under development with a freely evailable
   implementation and a lot of really neat ideas (EULisp)
and ISlisp is compatible with *none* of them, in broad or in detail.

>I believe immutable binding for functions has significant impact on
>the implementation techniques.  (We can't interactively redefine
>functions anymore.  Shocking news, eh?).  Compiler of ISLisp can
>always inline functions safely, or make a simple call instruction (as
>in C).

It would have been very easy to add something to one of the existing
standards in order to express this, without kicking compatibility (and
existing Lisp programmers) in the teeth.  Most of the Scheme implementations
I have manuals for have DEFINE-INTEGRABLE (or allow it to be defined; nothing
in any language standard I've seen _forces_ a compiler to take advantage of
things like this).

What's more, if you are talking about a batch compilation environment,
you are talking about a system where the compiler can find out that a
particular function _isn't_ redefined (even if it could have been).
I've recently been playing with Siskind's "Stalin" compiler which does
extensive global analysis and generates really winning code.

>Compare this with Scheme.  When executing procedure call (CAR
>something), compiled Scheme code (without dangerous optimization) must
>first fetch the value of the global variable CAR, check that it is a
>procedure, and then invoke it.

The claim that this _must_ be done is simply false.  What you _do_ need is
a good module system (which could certainly be added to Scheme without
breaking anything except a few reserved words; there are several proposals
around) so that the compiler can know when it is compiling a particular
module that every other module _can't_ assign to this variable and that this
module _doesn't_.  It's not even hard.

One thing I have learned to dislike is environments where the debugging
environment has different semantics from the production environment.  For
example, if functions _can_ be redefined somehow in the debugging
environment but not in the production environment, then you are debugging
a different language from the one your shipped application is written in.

Oh yes, the idea that function calls can _always_ be mapped to a simple
call instruction in C is quite a few years behind the times.  Windows,
OS/2, VMS, and modern UNIX systems, all have some form of dynamic linking.
It's even possible in OS/2, if I've read one of the manuals correctly, to
load a file, binding a function, then unload the file and load a different
one.  Certainly it's OS/2 PL/I, but if your language _can't_ do that, then
you can't take advantage of modern operating systems (or indeed the better
old ones).

>Local functions are easier to handle in Common Lisp, because they
>cannot be redefined within their scope.  In Scheme, however,
>LETREC-bound variables can be modified with SET!.  So compiler must
>first prove that the value is a procedure at the time of invocation
>before emitting direct call instruction.

This is, in practice, trivial.  You have
	(LET (... (id (lambda .. ...)) ...
or	(LET* (... (id (lambda . ...)) ...
or	(LETREC (... (id (lambda .. ...)) ...
or	(DEFINE id (lambda .. ...))
or	(DEFINE (id ..) ...)
You do a very cheap pass over the body governed by the declaration in
question, find that there are no instances of (SET! id ...), and in
O(n) time you know what you need to know.

>CALL-WITH-CURRENT-CONTINUATION, aside from its implementation
>difficulty per se, has some drawbacks.

>* UNWIND-PROTECT no longer works with it.  The following code:
>	(UNWIND-PROTECT
>	  <some file processing>
>	  (CLOSE FILE))
>  looks okay.  But what will happen if someone captured continuation
>  inside <some file processing> and try to resume processing later?

>  Note that UNWIND-PROTECT is crucial in writing real-world
>  applications.

Funny, I thought that problem had been solved by the introduction of
	(DYNAMIC-WIND before-thunk result-thunk after-thunk)
It is widely available, and does deal with the issue of CALL/CC exits
(after-thunk is called) and reentrances (before-thunk is recalled).

>* CALL/CC defeats some compiler optimizations.

Yes.  IF it is used.  Most escape handling methods in most programming
languages defeat some compiler optimisations, when they are used.

>In summary, CALL/CC is way too general.  It's actually strictly more
>general than GOTOs.  We need to restrict the usage of CALL/CC into
>some structured way (i.e. only for non-local exit) until we find
>better way to tame.

Actually, my argument against ISlisp was not based only on CALL/CC.
That was just one of several illustrations that the "spirit of
compatibility" claim in the ISlisp draft is purest flannel.

However, it is easily possible to have a dialect of Lisp which _restricts
the usage_ of call/cc to the "structured" case WITHOUT LOSING SCHEME
COMPATIBILITY.  It's called Elk.  (Whether you get full call/cc or cheap
call/cc depends on how much work the person did who ported Elk to your
machine.)  The result is that you can write code using call/cc in a
"structured" way in Elk, and run the _same_ code in another Scheme.

The major point remains:  there are differences between ISlisp and existing
Lisp standards or proposed standards which do nothing to address real-world
problems but merely suit someone's taste better.

Back in the days before the Prolog standard, our biggest barriers to
portability were not syntax, but system interface (file name, FFI) ones.
That the ISlisp current draft does not address these issues makes its
pretensions to consider the needs of "industray" sound insincere.

-- 
"conventional orthography is ... a near optimal system for the
 lexical representation of English words." Chomsky & Halle, S.P.E.
Richard A. O'Keefe; http://www.cs.rmit.edu.au/~ok; RMIT Comp.Sci.
From: MAEDA Atusi
Subject: Re: Immutable function bindings (was Re: ISO/IEC CD 13816 -- ISLisp)
Date: 
Message-ID: <MAD.96Jan8123523@tanzanite.math.keio.ac.jp>
In article <····················@cogsci.ed.ac.uk> ····@cogsci.ed.ac.uk (Jeff Dalton) writes:

    jeff> I am not convinced that ISLisp forbids implementations from allowing
    jeff> function redefinition.  What is your textual evidence from the ISLisp
    jeff> definition?

"For each namespace, defining forms can occur at most once for the
same name ..." (Working Draft 15.6; 4.4)

"The binding between function-name and the function object is
immutable." (4.8)

"It is a violation if there is attempt to change an immutable binding
(error-id. immutable-binding)." (1.7)

------------------------------------
Re possibility of ISLisp implementation that allows redefinition:

If an implementation provides read-eval-print loop as primary user
interface and if it allows mutation of immutable bindings, such
feature cannot be regarded as extension to the language.  Rather, it
looks more like an omitted check.  I think such an implementation is
non-conforming because it fails to detect violation.

"An ISLisp processor complying with the requirements of this document
shall ... reject any text that contains any textual usage which this
document explicitly defines to be a violation ..." (1.9)

Special debugger or switches to control the toplevel loop behavior
may be convenient, however.  (Like some C development environment which
allows incremental function redefinition).

				--mad
;;;  Keio University
;;;    Faculty of Science and Technology
;;;      Department of Math
;;;		MAEDA Atusi (MAEDA is my family name)
;;;		···@math.keio.ac.jp
From: Jeff Dalton
Subject: Re: Immutable function bindings (was Re: ISO/IEC CD 13816 -- ISLisp)
Date: 
Message-ID: <DKz4zA.4Ex.0.macbeth@cogsci.ed.ac.uk>
In article <················@tanzanite.math.keio.ac.jp> ···@math.keio.ac.jp writes:
>In article <····················@cogsci.ed.ac.uk> ····@cogsci.ed.ac.uk (Jeff Dalton) writes:
>
>    jeff> I am not convinced that ISLisp forbids implementations from allowing
>    jeff> function redefinition.  What is your textual evidence from the ISLisp
>    jeff> definition?
>
>"For each namespace, defining forms can occur at most once for the
>same name ..." (Working Draft 15.6; 4.4)
>
>"The binding between function-name and the function object is
>immutable." (4.8)
>
>"It is a violation if there is attempt to change an immutable binding
>(error-id. immutable-binding)." (1.7)

Ok, thanks.

>Re possibility of ISLisp implementation that allows redefinition:
>
>If an implementation provides read-eval-print loop as primary user
>interface and if it allows mutation of immutable bindings, such
>feature cannot be regarded as extension to the language.

How do you know?  And why does it matter?  Does the standard
even provide for read-eval-print loops.  Does it even contain
eval?

>Rather, it
>looks more like an omitted check.  I think such an implementation is
>non-conforming because it fails to detect violation.
>
>"An ISLisp processor complying with the requirements of this document
>shall ... reject any text that contains any textual usage which this
>document explicitly defines to be a violation ..." (1.9)

There's something weird going on here.  If it's supposed to reject
the text, why is there an error id?

>Special debugger or switches to control the toplevel loop behavior
>may be convenient, however.  (Like some C development environment which
>allows incremental function redefinition).

Just so.

-- jeff