From: Robert Posey
Subject: Question Of Scope
Date: 
Message-ID: <38B1B181.CB90CC94@raytheon.com>
Dear Gentle Persons and Eric,

I posted a question of how to have side effects on variables at the calling 
level.

For example

  (setf x '(my list))

  (my_func x)

(defun my_func (list_in)
 Position based operations

)

x now has a new value.  Since LISP is call by value, this should be impossible.
However, it is not.  You can change the value of X all you want, or don't want
if you access the elements of list_in by position as in:

 (setf (first list_in) 'whatever)


For the Homework assignment, this was the required method, but normally you
don't
want this to happen.  How do you prevent it from happening?  One method I used
is to call the function thusly (my_func (copy-list x)), which worked for the
cases I tried.  Is there a cleaner method to avoid undesired side effects?  This
seems to be something that has to be understood to do very much.  It is Similar
to
C's lovely Pointer problems.  Does anyone have a general method to avoid this
issue.

Muddy

From: Joe Marshall
Subject: Re: Question Of Scope
Date: 
Message-ID: <B1js4.50475$vi4.119590@dfw-read.news.verio.net>
Robert Posey <·····@raytheon.com> wrote in message
······················@raytheon.com...
> Dear Gentle Persons and Eric,
>
> I posted a question of how to have side effects on variables at the
calling
> level.
>
> For example
>
>   (setf x '(my list))
>
>   (my_func x)
>
> (defun my_func (list_in)
>  Position based operations
>
> )
>
> x now has a new value.

No, the value of X has not changed.  Try this:

(defun my-func (y)
  <whatever code you want here>
  )

(let ((x 42)) (my-func x) (format t "X is now ~d" x))

This will *always* print out "X is now 42".  There is *no way* within
my-func to change the value of x in the LET statement.

> Since LISP is call by value, this should be impossible.

It is impossible.

> However, it is not.  You can change the value of X all you want, or don't
want
> if you access the elements of list_in by position as in:
>
>  (setf (first list_in) 'whatever)

This does not change the value of X.  It changes the contents of the
container that
X points at.  This is an important distinction.

>
> For the Homework assignment, this was the required method, but normally
you
> don't
> want this to happen.  How do you prevent it from happening?

Eschew side effects.

> One method I used
> is to call the function thusly (my_func (copy-list x)), which worked for
the
> cases I tried.

That won't work in the general case because it only copies the top-level
list
structure.

> Is there a cleaner method to avoid undesired side effects?

Just don't use side effects!  It's easy to write code that doesn't muck
around with
the data structures that it receives.

You can also arrange for any new classes you define to not have mutation
functions.
From: rposey
Subject: Re: Question Of Scope
Date: 
Message-ID: <88slua$3bl$1@flash.seas.smu.edu>
> Eschew side effects.
>
> > One method I used
> > is to call the function thusly (my_func (copy-list x)), which worked for
> the
> > cases I tried.
>
> That won't work in the general case because it only copies the top-level
> list  structure

The copy-list function doesn't actually create a new copy?.
Does anyone have any code, or another function that actually creates an
independent
copy?

> > Is there a cleaner method to avoid undesired side effects?
>
> Just don't use side effects!  It's easy to write code that doesn't muck
> around with  the data structures that it receives.
>
> You can also arrange for any new classes you define to not have mutation
> functions.
>
How do you do this?  I tried

(setf x1 '(list elements))
(setf x2 x1)
:
:
(setf xn  xn-1)

And if you access the elements by position all the X1-Xn values will change,
or
at least it happens for sure for x1 and x2.  How do you avoid this? It seems
that
you have to avoid (setf position 'whatever) altogether.  Is this what you
mean by
side effects?  What is this "Feature" in a mostly functional language for
anyway,
it seems to be a little strange that

(setf (first list_in) 'whatever) ; Changes the top level, but

(setf list_in 'whatever) ; Does Nothing.

Does anyone have a reference that explains how you tell when this might
occur?



BTW what is a Mutation function, that a term I haven't heard before.

Muddy

>
>
From: Paolo Amoroso
Subject: Re: Question Of Scope
Date: 
Message-ID: <6VeyOF=24qYs7XQck6qDbUiw0n00@4ax.com>
On Mon, 21 Feb 2000 18:38:22 -0600, "rposey"
<············@worldnet.att.net> wrote:

> Does anyone have any code, or another function that actually creates an
> independent
> copy?

What about COPY-TREE?


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/
From: Joe Marshall
Subject: Re: Question Of Scope
Date: 
Message-ID: <eAxs4.58255$vi4.123238@dfw-read.news.verio.net>
rposey <············@worldnet.att.net> wrote in message
·················@flash.seas.smu.edu...
> > Eschew side effects.
> >
> > > One method I used
> > > is to call the function thusly (my_func (copy-list x)), which worked
for
> > the
> > > cases I tried.
> >
> > That won't work in the general case because it only copies the top-level
> > list  structure
>
> The copy-list function doesn't actually create a new copy?.

Copy-list only recurs down the CDRs of the list, so it only copies the
`backbone'.

> Does anyone have any code, or another function that actually creates an
> independent
> copy?

COPY-TREE

>
> > > Is there a cleaner method to avoid undesired side effects?
> >
> > Just don't use side effects!  It's easy to write code that doesn't muck
> > around with  the data structures that it receives.
> >
> > You can also arrange for any new classes you define to not have mutation
> > functions.
> >
> How do you do this?  I tried
>
> (setf x1 '(list elements))
> (setf x2 x1)
> :
> :
> (setf xn  xn-1)

First, define an abstract data type.  Suppose I want to represent people
and their birth days.  Because you can't change when you are born, I don't
want to make that ability available.  So I define the following functions:

make-person <name> <bday>
person-name <person>
person-bday <person>

And that's it.  If you have the discipline to only use the functions I
defined in a `black-box' manner, you simply cannot change the
birthday associated with a person: there's no function to call that
does that.

I could *implement* make-person with CONS and PERSON-NAME
would be CAR and PERSON-BDAY would be CDR.  Someone could
call (SETF (CAR  )), but that would be a violation of abstraction.

If I were worried about that, I could do the following:
(defstruct person
  (name nil :read-only t)
  (bday  nil :read-only t))

Now someone wanting to violate the abstraction would have to
figure out how the compiler generates structure mutators, because
I've told the compiler not to.

> It seems that you have to avoid (setf position 'whatever)
> altogether.  Is this what you mean by side effects?

Yes.

> What is this "Feature" in a mostly functional language for
> anyway?

If you are modeling things that change state, this is a very
direct way of implementing the model.

> Does anyone have a reference that explains how you tell when this might
> occur?

You have to understand the distinction between containers and values.
Once you have that down, the rest is obvious.

> BTW what is a Mutation function, that a term I haven't heard before.

A mutation function is one that modifies the contents of a container.
From: Tim Bradshaw
Subject: Re: Question Of Scope
Date: 
Message-ID: <ey34sb2cdvd.fsf@cley.com>
* Robert Posey wrote:
> For the Homework assignment, this was the required method, but
> normally you don't want this to happen.  How do you prevent it from
> happening?  One method I used is to call the function thusly
> (my_func (copy-list x)), which worked for the cases I tried.  Is
> there a cleaner method to avoid undesired side effects?  This seems
> to be something that has to be understood to do very much.  It is
> Similar to C's lovely Pointer problems.  Does anyone have a general
> method to avoid this issue.

In a language which allows destructive modifications to its data
objects, then you really are doomed to this problem -- this is not a
Lisp problem.  As you say, it is kind of like C's pointer issues,
with the (very important) restriction that you can't `fall off the
edge of the world' in Lisp like you can so easily in C, because so
long as you have a handle on something the system will not delete it
from under you, and you can't get `handles' on unallocated memory.

Assuming you are not willing to write purely functional programs,
there are approaches which help, but the ultimate solution is careful
design.

Careful design of interfaces to data structures is one place where you
can make things less bad.  For instance if you have an object which
has children in some sense, it's tempting to provide an interface like
(foo-children x) which returns a list of the children.  But then you
need to know if this list is part of the object (so modifying it
modifies the object), and if it's not, then how expensive was it to
create.  A better (I think) interface is often to work out what people
actually need to *do* to the object, and provide that, typically by a
mapping interface.  For instance you might provide:

	(map-foo-children fn foo)

and 

	(find-foo-child-named foo name)

which avoids ever exposing the actual list of children of the object
(if it even has one -- the second function above was meant to imply
that some hashtable-based implementation might be being used).

If you care obsessively about efficiency then the MAP-FOO-CHILDREN
interface can be converted into very good code for common cases by
compiler macros (and perhaps automatically by compilers).

I don't claim that things like this are silver bullets -- in fact I
claim that there is no silver bullet which doesn't have nasty
side-effects -- but they can make life better, I think.

--tim
From: Jeff Dalton
Subject: Re: Question Of Scope
Date: 
Message-ID: <x2em9xwav2.fsf@todday.aiai.ed.ac.uk>
Tim Bradshaw <···@cley.com> writes:

> Careful design of interfaces to data structures is one place where you
> can make things less bad.  For instance if you have an object which
> has children in some sense, it's tempting to provide an interface like
> (foo-children x) which returns a list of the children.  But then you
> need to know if this list is part of the object (so modifying it
> modifies the object), and if it's not, then how expensive was it to
> create.  A better (I think) interface is often to work out what people
> actually need to *do* to the object, and provide that, typically by a
> mapping interface.  For instance you might provide:
> 
> 	(map-foo-children fn foo)
> 
> and 
> 
> 	(find-foo-child-named foo name)
> 
> which avoids ever exposing the actual list of children of the object
> (if it even has one -- the second function above was meant to imply
> that some hashtable-based implementation might be being used).

What if you want to iterate over two sets at once?

And advantage of using lists is that any number of iteration forms
can then be used; and then there's the Perlis (I think) point from the
intro to SICP that it's better to have one data structure and lots of
algorithms ...

I think this is a case where the best is enemy of the good.  Sure,
using lists isn't perfect - but that's not a good enough reason not
to use them.  (I the Lisp world, I guess we say "worse is better"
instead.)

-- jd
From: Tim Bradshaw
Subject: Re: Question Of Scope
Date: 
Message-ID: <ey3k8jpp7pn.fsf@cley.com>
* Jeff Dalton wrote:

> What if you want to iterate over two sets at once?

I think (for the data structure I wrote this about), I'd provide some
kind of iterator-type thing.  That might even *be* a list of course,
but more likely a closure. (The particular objects in question not
only weren't necessarily internally listy but could flip
representation on the fly).

But that's a good point.  I think that someone (Henry Baker?) has some
paper describing tricks to do this kind of thing, which I've probably
only partly understood.

--tim
From: Vebjorn Ljosa
Subject: Re: Question Of Scope
Date: 
Message-ID: <cy3u2is4li0.fsf@verden.pvv.ntnu.no>
Tim Bradshaw <···@cley.com> writes:

> * Jeff Dalton wrote:
> 
> > What if you want to iterate over two sets at once?
> 
> I think (for the data structure I wrote this about), I'd provide some
> kind of iterator-type thing.  That might even *be* a list of course,
> but more likely a closure. (The particular objects in question not
> only weren't necessarily internally listy but could flip
> representation on the fly).
> 
> But that's a good point.  I think that someone (Henry Baker?) has some
> paper describing tricks to do this kind of thing, which I've probably
> only partly understood.

perhaps your're thinking of this one:

Baker, Henry G: "Iterators: Signs of Weaknesses in Object-Oriented
Languages", ACM OOPS Messenger 4.3 (July 1993), pp. 18--25.

<URL:ftp://ftp.netcom.com/pub/hb/hbaker/Iterator.html>
<URL:ftp://ftp.netcom.com/pub/hb/hbaker/Iterator.ps.Z>

-- 
Vebjorn