Newsgroups: comp.lang.scheme
Path: cantaloupe.srv.cs.cmu.edu!das-news2.harvard.edu!news2.near.net!news.mathworks.com!hookup!news.sprintlink.net!siemens!princeton!news.princeton.edu!blume
From: blume@dynamic.cs.princeton.edu (Matthias Blume)
Subject: Re: call by value, again
In-Reply-To: bh@anarres.CS.Berkeley.EDU's message of 13 Nov 1994 16:22:07 GMT
Message-ID: <BLUME.94Nov13133704@dynamic.cs.princeton.edu>
Originator: news@hedgehog.Princeton.EDU
Sender: news@Princeton.EDU (USENET News System)
Nntp-Posting-Host: dynamic.cs.princeton.edu
Organization: Princeton University
References: <3a0mh8$prv@agate.berkeley.edu> <BLUME.94Nov11170247@dynamic.cs.princeton.edu>
	<3a5eff$k52@agate.berkeley.edu>
Date: Sun, 13 Nov 1994 18:37:04 GMT
Lines: 145

In article <3a5eff$k52@agate.berkeley.edu> bh@anarres.CS.Berkeley.EDU (Brian Harvey) writes:

   One's sense of what's interesting depends, of course, on what one is
   trying to do.  What you're trying to do, I gather, is work out how to
   get your formal model to handle, e.g., making sure a recursion bottoms
   out, without kludging it up with things like special forms.  What *I'm*
   trying to do is teach Scheme to someone who learned Pascal in high
   school, and who therefore believes that

	   In call by reference the called procedure can modify the
	   value belonging to the caller;

	   In call by value the called procedure cannot modify the
	   value belonging to the caller;

	   And that's the difference between them.

I.e. you are saying that you are trying to teach Scheme to someone who
doesn't even know Pascal, because the assertions above are not true --
not even for Pascal.

In the call-by-value case the callee can still alter the actual
argument (belonging to the caller), but this can't be done through
this argument itself.  (Global variables, variables passed as
reference parameters *and* as value parameters at the same time,
aliases, ...)

So far this is only talking about the value itself.  Assume that the
argument is a pointer, which is passed by value.  According to the
apparent misconception of what constitutes the ``value'' (which
wrongly considers the object pointed to by this pointer part of the
value) you can still (even in Pascal) alter the ``argument value''.

I agree that it is difficult to unlearn things.  The difficulties you
describe are not due to the added complications of Scheme over Pascal
but due to the fact that the student had a wrong impression of the
Pascal semantics to begin with.

   This hypothetical person has never even *heard* of call by name, not having
   been alive when the Algol 60 report came out.

Huh?  I've certainly heard of the concept of gravitation, even though
I haven't even been alive when Newton discovered the laws by which it is
governed.  Now, I acknowledge that call-by-name is not as pervasive a
concept as is gravitation, but the ``hasn't been alive'' argument is
no excuse for not knowing something.

   Now along comes Scheme, and
   this person is confronted with the bizarre fact that some kinds of
   modification do affect the caller's value, whereas other kinds
   don't.

The person must have had a very bad Pascal teacher, how else could
he/she not have been confronted with this ``bizarre'' fact before?!

   Such
   a person is not helped by being told that call by reference isn't
   interesting.

The dominant language nowadays seems to be C (unfortunately soon to be
replaced by C++ unless a miracle happens).  C always uses call-by-name
(just as Scheme does).  And everybody knows that you can simulate
call-by-reference using `&' and `*'.

   It's an open question, to me, whether such a person is helped
   by being told about environments and stores.

Maybe.  I was very surprised that this whole debate came up at all.
Speaking out of own experience I can say that I had a pretty good
mental picture of what's going on inside Scheme *before* I ever heard
of the terms ``environment'' and ``store'' (in this context).  What
you need to understand is that there is a *two*-level mapping
(name->location->value) instead of a one-level mapping (name->value).
You can get away with one level as long as you don't have any form of
mutation (no `xxx!' like set!, set-c[ad]r!, ...).

Some very good texts on programming (SICP comes to mind) take
precisely this road:  first make things easy, use a one-level mapping,
avoid all data mutation.  Only when you get to ``local state'' and
``object identity'' you need to go the next step, which is abandoning
the one-level paradigm in favor of a two-level paradigm.

   >``The variable x is bound to location L by the
   >environment U, which is then mapped to 3 by the store S. Therefore, by
   >definition, the value of x is 3.  U ("x") = L, S (L) = 3 ==> E("x") = 3.''

   Yes, this is very clear and precise.  But I can't imagine myself trying to
   teach it to a beginning programmer.  Are you suggesting that this is the only
   intellectually honest way to explain how Scheme works?  If not, I'd be
   grateful (truly -- I'm not being sarcastic) for a more accessible model.

Well, this is *a* correct model.  I would also venture to say that it
is (one of) the ``least complicated while still correct'' model(s),
but obviously I can't prove this (mainly due to the fact that I can't
define the ``less complicated'' relation for models :).

A totally different question is whether it is possible to present this
model in a more accessible way.  I don't know.

   For what it's worth, the following is quoted from the first (1981) edition
   of _LISP_ by Patrick Henry Winston and Berthold Klaus Paul Horn, p. 419:

   ----------------------------------------

   Note 2: LISP is Neither Call-by-reference nor Call-by-value

   Atoms and lists are the objects that LISP deals with.  They are passed as
   arguments to functions and returned as values.  In LISP we say that an atom
   may be *bound* to such an object.  Note that two atoms may be bound to the
   same object.  Each LISP object has its individual identity; that is, we can
   test (using EQ) whether two objects are in fact one and the same.  If two
   atoms are bound to the same object, changes in that object will affect both
   atoms.

   Most other languages deal with variables that have values.  Each variable
   can be in one of a number of different *states*.  In the case of a fixed
   point variable, the possible states correspond to those integers which can
   be represented.  We can ask whether two variables are in the same state.
   Changing the state of one variable does not cause a change of state in
   another variable.  In such programming languages there are two ways to pass
   an argument when a function is called:

       One can initialize the state of the function's parameter to be the same
       as the present state of the given argument.  This is termed *call by
       value*.

       One can use the parameter's name as an alias for the argument name.
       Changing the state of the function's parameter changes the state of
       the argument.  This is termed *call by reference*.

   Note that call by value may involve copying some information.  On the other
   hand, call by reference may lead to side effects on the variable used as the
   argument, possibly unexpectedly.

   Strictly speaking, LISP can be neither call by value nor call by reference
   because the notion of what a LISP variable is does not correspond exactly to
   the notion of variable for which call by value and call by reference have a
   natural meaning.

   ----------------------------------------

[I'm sitting here in tears...]

--
-Matthias
