From: Q
Subject: copying arrays
Date: 
Message-ID: <1177816575.973440.105620@l77g2000hsb.googlegroups.com>
Hi all,

Simple question:

CL-USER 37 > (setf a (make-array 5 :initial-element 7))
#(7 7 7 7 7)

CL-USER 38 > (setf b a)
#(7 7 7 7 7)

CL-USER 39 > (eq a b)
T

CL-USER 40 > (setf (aref a 0) 9)
9

CL-USER 41 > a
#(9 7 7 7 7)

CL-USER 42 > b
#(9 7 7 7 7)

How do I pass copies of the array around, instead of the array
itself?  I don't want them to be eq.  But, it'd be nice if they were
equal :)

From: Alan Manuel K. Gloria
Subject: Re: copying arrays
Date: 
Message-ID: <1177822634.741601.278530@h2g2000hsg.googlegroups.com>
On Apr 29, 11:16 am, Q <······@gmail.com> wrote:
> Hi all,
>
> Simple question:
>
> CL-USER 37 > (setf a (make-array 5 :initial-element 7))
> #(7 7 7 7 7)
>
> CL-USER 38 > (setf b a)
> #(7 7 7 7 7)
>
> CL-USER 39 > (eq a b)
> T
>
> CL-USER 40 > (setf (aref a 0) 9)
> 9
>
> CL-USER 41 > a
> #(9 7 7 7 7)
>
> CL-USER 42 > b
> #(9 7 7 7 7)
>
> How do I pass copies of the array around, instead of the array
> itself?  I don't want them to be eq.  But, it'd be nice if they were
> equal :)
And then there's the problem - what if the array contains instances of
other arrays (or lists, or hashtables, or what not for that matter)?
Do you want to copy the member arrays?  Or use the member array
directly?  What if we have two arrays that happen to contain each
other?

In my experience it's quite rare to have to have to *copy* a
sequence.  If you're manipulating an array, why would you want to
retain the previous version?  What is it that you are trying to do?
In general, it is usually very rare that you have to actually copy the
sequence.
From: Dan Bensen
Subject: Re: copying arrays
Date: 
Message-ID: <f11dac$hsn$1@wildfire.prairienet.org>
Alan Manuel K. Gloria wrote:
> In my experience it's quite rare to have to have to *copy* a
> sequence.  If you're manipulating an array, why would you want to
> retain the previous version? 

In a game, you might want to pass the state of the game
(e.g. the board in a board game) to a computer player
so it can decide what it wants to do.  The safe way to do that
would be to pass the player a copy, so the player doesn't
corrupt the game.  Often the player will destructively modify
the board, but undo all its changes at the end.  With a copy,
you can also check the player for correctness by comparing
the final state of the player's copy with the original board.

-- 
Dan
www.prairienet.org/~dsb/
From: Kent M Pitman
Subject: Re: copying arrays
Date: 
Message-ID: <uzm4run2d.fsf@nhplace.com>
Warning: The "rant" below might or might not be relevant to Dan's remarks
 directly.  So don't take this as necessarily responding to his particular
 situation.  I'm pretty sure my remarks below need to be said to SOMEONE,
 and I'm somewhat opportunistically (and hence possibly slightly unfairly)
 dumping on Dan's remarks here... I really just wanted to be pro-active,
 a bit, rather than reactive, and to address a common behavior at a time
 when we're dancing around a common set of misconceptions.  So if you're
 still game, read on...

Dan Bensen <··········@cyberspace.net> writes:

> > Alan Manuel K. Gloria wrote:
> > In my experience it's quite rare to have to have to *copy* a
> > sequence.  If you're manipulating an array, why would you want to
> > retain the previous version?
>
> In a game, you might want to pass the state of the game
> (e.g. the board in a board game) to a computer player
> so it can decide what it wants to do.

I've seen this argument made many times in my career and I really have
to say that I personally cringe at this use of "safe".  While indeed
one must use care in setting up one's programs so that things
cooperate, it's no "more safe" to call a function that's supposed to
add 1 to a number only to find that it subtracts 1.  A program that does
not understand its contract is unsafe.  If a program does understand its
contract, it can use side-effects safely.

Yes, it's true, there are cases where you give a piece of structure to
a program that is supposed to do some computation, and it's true that
it can accidentally do a side-effect if the programmer is not aware that
they are receiving shared structure.  But there's a strong question of 
whether this is a bug in the use of operators or in the definition of
protocol.

The fact that this word "safe" is used in relation to destructive
operators that people simply learn badly and use badly suggests that
it is just code for talking about another attribute of people because
they are uncomfortable talking directly to the issue of programmer
competence.  I'd rather teach people to be competent than pamper them
in this way.  I've seen people who purport to be serious programmers
stare at programs and say out loud "what if we replace these
destructive operators with non-destructive ones, does that fix it?"

It reminds me of when I first got in-range of solving Rubik's cube.  I
could get it to what seemed to me like a 1 in 4 (or maybe 1 in 3)
chance of accidentally working, because I couldn't spin some corners.
Rather than learn how to complete the thing right, I was so
exasperated that I learned to just randomize the cube and re-do it
(which took me only a minute and a half).  After a handful (so to
speak) of iterations, it would naturally end up that I got to the end
without needing to spin the corners, and I'd win... But there was no
real substitute for actually learning the transforms needed, and I was
being ridiculous by just treating randomization as an actual design
choice, even though it could be shown... while it can probably be
shown theoretically to converge, it gives up control of when and how
convergence will happen to probabilities in a place where there's no
need to give up that control.

I feel the same about yielding up the control of protocol design to the
chance sense that someone might not make or read a protocol definition.

> The safe way to do that would be to pass the player a copy, so the
> player doesn't corrupt the game.

Safe is relative.  What if safety is based on space as a criterion?
Running out of space in a lot of cases will swamp a program just as
quickly as a program error, and the idea of copying a large game board
an a possibly-exponential number of times seems destined to do badly
in terms of space (and even if not, the amount of time needed to copy
and reclaim all those copies).  [This is the place where someone will
trot out some proof that this doesn't always lose, but let me just say
preemptively say that wouldn't refute my point.  I'm not saying you
can't win that way.  I'm saying you can't know you're going to win
unless you've studied the issue.  Studying the issue requires a quite
carefully coordinated design and implementation.  And if you're going 
to do that level of design, why not just factor in the notion that side
effects will be competently included and implemented.]

> Often the player will destructively modify the board, but undo all
> its changes at the end.

Ownership is something everyone should understand, whether it's
something in the real world or something in the imaginary world.
People need to know what they can modify and what they can't.  This is
as fundamental as "caller saves vs callee saves", and cannot be left
to chance.  You're talking like people can independently choose their
favorites, and I'm not sure I see that's so.

Indeed, you can create a convention in which this statement is true,
but please do not presuppose that this convention is a natural truth
and that there is no alternative.  I think, in fact, the default state
of Lisp is just the opposite.  Lisp, as a natural set of operations, 
assumes callee-saves, since it assumes that pointer-passing is the
efficient way.  It is therefore incumbent on someone who writes a 
function, any function, that plans a side effect to advertise the fact
of that side effect.  And surely, then, it's incumbent upon the caller
to take note of that fact.

There are also issues of multiprocessing and synchronized access, but 
again it is a myth to think that the answer to multiprocessing and
synchronized access is that no one should ever do a side effect just
in case someone replaces mapcar with parallel-mapcar and "breaks things".
Any replacement of any operator with another operator that does not
respect the contract of the program will break things, but somehow only
side-effects get this shabby treatment of saying that somehow the world
should be specially prepared in advance of a change of protocol so that
the protocol change can be injected without cost.

> With a copy, you can also check the player for correctness by
> comparing the final state of the player's copy with the original
> board.

This statement isn't just a statement by itself but is offered in a context
where it has increased importance.  It's in a situation where it's defending
not just making a copy, but making one often.  I infer that it's on each
call that we're talking.  And my point is that this is a reasoned choice,
based on domain knowledge, not an obvious truth.  You could make a
(defun set-array-element-returning-array (value array &rest indices) 
  (let ((copy (copy-array array))) ;for some definition of copy-array
    (setf (apply #'aref copy indices) value)
    copy))
and you could then easily use this operation, but the creation of such an
operation would make it easier to accidentally make lots of needless copies,
when in fact even in the situation you're describing, you might want to do
three modifies in a row, and why would you do
  (defun foo (a i j x) ;just a randomly chosen example
    (set-array-element-returning-array x
      (set-array-element-returning-array x a i)
      j))
which makes a needless copy, when you could just as well do
  (defun foo (a i j x)
    (let ((copy (copy-array a)))
      (setf (aref copy i) x)
      (setf (aref copy j) x)
      copy))
and get the same effect, leaving around half as much garbage?  Lisp doesn't
provide an easy way to do that, in part, because the array datatype exists
specifically for data so large that it has to be direct accessed.  (For lists
known to never grow bigger than two or three in length, the functions first
and second and third, even though they chain through list links, are probably
faster in many if not all implementations than an array access because they 
don't have to do type and bounds checking, dimension decoding, etc.)
And we teach people to be thoughtful about when a copy would help and when not.
Certainly we copy things.  But we don't think to copying as so important that
it should be done by default all the time; just the opposite, we think object
identity is central and we should think carefully about when to risk a 
separation of identity.

In the case of a game, for example, comparing initial and final states requires
a separation of identity, so of course a copy is warranted.  But there's a
subtext of your remarks that seems to imply you can get from there to 
"copies are good, and it's non-copies that are a danger", and I don't think
any such sweeping claim (if it's intended by you, or would be intended by 
others reading this discussion) is warranted.  

One can always save a copy when one needs it.  I take Alan's point not
to be why would one ever copy, but rather, why would one be surprised
that copying was something that was left to the user to decide.

And, incidentally, copying is not a canonically-defined concept.  Copying is
something that can only be done with due regard to the semantics of the
components.  A copy of a cons and a copy of a list are different, yet
a cons is a list, and Lisp is dynamically typed, so the intent of the one
is indistinguishable from the intent of the other.  [See my article
 http://www.nhplace.com/kent/PS/EQUAL.html
for details on this.  It treats EQUAL, not COPY, but it notes and I continue
to believe that the philosophical issues are the same.]  

[There's perhaps, too, a hidden assumption that arrays are homogenous, 
 and somehow easier to copy safely than other types.  But that's just 
 not true.  Lisp arrays are often homogenous, but there's no requirement.
 So some elements might need deep copying and others not... indeed, if 
 one of the cells is a domain-managed reference count, a proper "copy" 
 of that data structure might not even copy all of the top level items 
 in it, since otherwise you'd be lying about how many domain-managed
 objects were pointing to the copy.  You might wish Lisp had a matrix 
 datatype like mathematics uses, but then you're asking for a new
 representational type, or you'd never be able to detect it.  And that
 just reaffirms my point, which is that copies in Lisp must be made based
 on what the programmer knows about his application, not on the basis of
 whim and in contradiction of domain-specific, carefully worked out and
 agreed-upon protocol specs.]

I'll stop there for now.  Thanks for listening.
From: Richard M Kreuter
Subject: Re: copying arrays
Date: 
Message-ID: <87zm4qan21.fsf@tan-ru.localdomain>
Kent M Pitman <······@nhplace.com> writes:

> ... we teach people to be thoughtful about when a copy would help
> and when not.  Certainly we copy things.  But we don't think to
> copying as so important that it should be done by default all the
> time; just the opposite, we think object identity is central and we
> should think carefully about when to risk a separation of identity.

The OP seems to have expected (or at least wanted) SETF to make a copy
of the array.  This might suggest a background in a language like Perl
or PHP, where the thing that looks like assignment actually does
something resembling a shallow copy (most of the time: sometimes it
does a CLRHASH or something like emptying a ring buffer).  For a
variety of reasons, in these languages you often care only about how
things print, and so that kind of equivalence is usually more
important than object identity.  Since EQUAL-but-not-EQ objects are
generally sufficient, and since these languages' libraries are mostly
full of destructive operations, it's idiomatic in these languages to
copy things literally all the time.  That's not an argument for the
goodness of copying; it's just a comment about the expectations of
people with some sorts of background, and so about how Lisp would seem
strange to someone coming from those languages.

--
RmK
From: Dan Bensen
Subject: Re: copying arrays
Date: 
Message-ID: <f144bf$sm6$1@wildfire.prairienet.org>
Alan Manuel K. Gloria wrote:
 > In my experience it's quite rare to have to have to *copy* a
 > sequence.  If you're manipulating an array, why would you want to
 > retain the previous version?  What is it that you are trying to do?
 > In general, it is usually very rare that you have to actually copy
 > the sequence.

Dan Bensen wrote:
 > In a game, you might want to pass the state of the game
 > (e.g. the board in a board game) to a computer player
 > so it can decide what it wants to do.  The safe way to do that
 > would be to pass the player a copy, so the player doesn't
 > corrupt the game.  Often the player will destructively modify
 > the board, but undo all its changes at the end.  With a copy,
 > you can also check the player for correctness by comparing
 > the final state of the player's copy with the original board.

Kent M Pitman wrote:
 > Warning: The "rant" below might or might not be relevant to Dan's
 > remarks directly.  So don't take this as necessarily responding to
 > his particular situation.
With all due respect, Kent, that's exactly how I take it.
You directly addressed me and my comments in a highly critical way.

 > it's no "more safe" to call a function that's supposed to
 > add 1 to a number only to find that it subtracts 1.
This is ridiculous.  In many cases, one glance at (incf x)
will be enough to determine whether it's correct.
The same cannot be said for dozens or hundreds of lines
of tree-searching code.

 > A program that does not understand its contract is unsafe.
 > If a program does understand its
 > contract, it can use side-effects safely.
A buggy program is also unsafe, even if it understands its contract.

 > Yes, it's true, there are cases where you give a piece of structure to
 > a program that is supposed to do some computation, and it's true that
 > it can accidentally do a side-effect if the programmer is not aware
 > that they are receiving shared structure.  But there's a strong
 > question of whether this is a bug in the use of operators or in
 > the definition of protocol.

There's also a strong question of whether human programmers are
infallible and whether bugs should be guarded against in a modular way.

 > The fact that this word "safe" is used in relation to destructive
 > operators that people simply learn badly and use badly suggests that
 > it is just code for talking about another attribute of people because
 > they are uncomfortable talking directly to the issue of programmer
 > competence.
 > I'd rather teach people to be competent than pamper them in this way.

I don't think it's code, I think it's a simple fact.  You can't teach
people to be perfect.  If your code is in production use, it may be
safer for it to fail gracefully instead of blindly allowing
every part of the program to change important data.

 > I've seen people who purport to be serious programmers
 > stare at programs and say out loud "what if we replace these
 > destructive operators with non-destructive ones, does that fix it?"
 > It reminds me of when I first got in-range of solving Rubik's cube.
 > I feel the same about yielding up the control of protocol design to
 > the chance sense that someone might not make or read a protocol
 > definition.

With all due respect, neither of those subjects has anything to do
with this thread, and I really don't appreciate being the person
whose post you use in discussing bad programmers.

 >> The safe way to do that would be to pass the player a copy,
 >> so the player doesn't corrupt the game.
 > Safe is relative.  What if safety is based on space as a criterion?
 > Running out of space in a lot of cases will swamp a program just as
 > quickly as a program error, and the idea of copying a large game board
 > an a possibly-exponential number of times seems destined to do badly

Also in the most polite terms I can muster, you're knocking down
a straw man, and not even a clever one.  Avoiding exponential copying
is precisely the point of a destructive search, so obviously that
can't be what we're talking about.  All I said was that it might help
to make a copy at the root of the search.

 >> Often the player will destructively modify the board,
 >> but undo all its changes at the end.
 > Ownership is something everyone should understand, whether it's
 > something in the real world or something in the imaginary world.
 > People need to know what they can modify and what they can't.
 > This is as fundamental as "caller saves vs callee saves",
 > and cannot be left to chance.

Actually, what I had in mind is a search that's called only for
its return value, even though it searches destructively for
performance reasons.  The callee doesn't save in that protocol
becuase that's not its job.  It doesn't make sense to give the
callee access to the original copy of the data if it's not being
called for side effects.

 > You're talking like people can independently choose their
 > favorites, and I'm not sure I see that's so.
I have no idea what that means.

 > Lisp, as a natural set of operations,  assumes callee-saves,
 > since it assumes that pointer-passing is the efficient way.
That sounds like a bad idea if it's not necessary.  In the real,
imperfect world that we all live in, it's safer to minimize the
amount of code that can potentially corrupt important data.

 > This statement isn't just a statement by itself but is offered in
 > a context where it has increased importance.  It's in a situation
 > where it's defending not just making a copy, but making one often.
Again, you're just making stuff up.  I never suggested any such thing.

 > I infer that it's on each call that we're talking.
You infer incorrectly.  I would make a copy on each call
to the entry point at the root of the search tree,
not at every node.

 > But there's a subtext of your remarks that seems to imply you can get
 > from there to "copies are good, and it's non-copies that are a danger"

No, there is no such subtext.  But as long as we're discussing subtext,
is it just a coincidence that this post of yours occurred only days
after I made a technical criticism of the HS?  Just wondering.

-- 
Dan
www.prairienet.org/~dsb/
From: Kent M Pitman
Subject: Re: copying arrays
Date: 
Message-ID: <uwszub97f.fsf@nhplace.com>
[This post is just to clarify some interpersonal confusion.  Not a heap
 of technical content below. -kmp]

Dan Bensen <··········@cyberspace.net> writes:

> Kent M Pitman wrote:
>  > Warning: The "rant" below might or might not be relevant to Dan's
>  > remarks directly.  So don't take this as necessarily responding to
>  > his particular situation.
> With all due respect, Kent, that's exactly how I take it.
> You directly addressed me and my comments in a highly critical way.

As the disclaimer intended to make clear, I wrote the text, looked it
over, and decided that I was probably making assumptions that might or
might not be valid about you specifically.  But I still liked the
general technical remarks I was making because I've had a chance to
make those same observations about others.  Since I didn't have the
time or energy to rewrite my post, I added a disclaimer.  I suppose
it's your right to not take my words at face value, but that's up to
you.  I'm saddened that you felt any personal negativity from me.

However, I stand by the technical content and focus of my post, that
is, that this issue of side-effect is often given undue weight.  I
take it from your reply that you disagree.  That's ok.  I can cope
with a world in which people disagree.  I'll be interested to hear
what others have to say. (Though I emphasize that I don't take it as a
vote, so whether they agree with me or you, I think there's no reason
for either of us to chagne our position just based on numbers of voices.)

>  > But there's a subtext of your remarks that seems to imply you can get
>  > from there to "copies are good, and it's non-copies that are a danger"
> 
> No, there is no such subtext.

People often accuse me (perhaps rightly on many occasions) of being overly
verbose.  One particular issue that comes up a lot is that I choose wordy
phrases like "you appear to think x" rather thank "you think x".  I find
the extra indirection to better express how I think.  Here I failed to be
my usual verbose self and see what it gets me? :)  I should have said
"There seems to be a subtext...".  I did seem that way to me.  But I accept
your statement that you don't think there is.  Even so, my overriding point
in the post was to say that I believe some people do carry that banner.

> But as long as we're discussing subtext, is it just a coincidence
> that this post of yours occurred only days after I made a technical
> criticism of the HS?  Just wondering.

I had to go back and research what you were even talking about, so the
answer is pretty clearly yes, it is just pure coincidence.  While I
did, upon seeing the other post, remember writing it, I hadn't
recalled it was to you.  (I'm assuming we're talking about the
discussion of the meaning of the term variable.  By the way, I had
assumed that was just a request for clarification, which I thought I
had helpfully provided--I didn't even read it as a criticism.
Cognitive dissonance on my part, I suppose.  But for whatever reason, if
I was meant to feel criticized, it sailed right past me.)

In any case, though, I'm quite comfortable with people criticizing the
HyperSpec.  There's a great deal I wish I'd had time to do better and
it's got plenty to poke at.  But at the same time, I'm also
comfortable that I did a passable job given the complexity of the task
and the limits of budget.  So I don't take remarks about it
personally.

I do defend both the HyperSpec and CL itself, but not because I can't
bear to see it criticized.  Rather, because I think its goodness or
badness should be judged in the context of its goals and the various
complicated constraints on it.  I think debate should be impersonal
and respectful and thoughtful, and I try to set a model for that.
I've made no attempt to be disrespectful to you.  I am passionate
about my thoughts on technical issues, and I try to provoke thought
and discussion, but I have no special interest in making someone angry
and I do what I can to avoid it.

I also work hard to make sure the group here is informed, so that
people aren't at a disadvantage in discussing it.  I do not believe a
language should be an ivory tower phenomenon that excludes the public,
but neither do I thnk being inclusive means that every comment someone
makes is automatically as serious a concern as every other.  I think
some issues are important and some less so, and in that that
discussion I was merely stating my personal belief.  I am careful to
try to say I'm just one opinion so that newbies don't read too much
into my words.
From: Ken Tilton
Subject: Re: copying arrays
Date: 
Message-ID: <pnnZh.463$dC1.414@newsfe12.lga>
Dan Bensen wrote:
> Alan Manuel K. Gloria wrote:
>  > In my experience it's quite rare to have to have to *copy* a
>  > sequence.  If you're manipulating an array, why would you want to
>  > retain the previous version?  What is it that you are trying to do?
>  > In general, it is usually very rare that you have to actually copy
>  > the sequence.
> 
> Dan Bensen wrote:
>  > In a game, you might want to pass the state of the game
>  > (e.g. the board in a board game) to a computer player
>  > so it can decide what it wants to do.  The safe way to do that
>  > would be to pass the player a copy, so the player doesn't
>  > corrupt the game.  Often the player will destructively modify
>  > the board, but undo all its changes at the end.  With a copy,
>  > you can also check the player for correctness by comparing
>  > the final state of the player's copy with the original board.
> 
> Kent M Pitman wrote:
>  > Warning: The "rant" below might or might not be relevant to Dan's
>  > remarks directly.  So don't take this as necessarily responding to
>  > his particular situation.
> With all due respect, Kent, that's exactly how I take it.
> You directly addressed me and my comments in a highly critical way.

That reaction is understandable given the use of the "u"-word, but if 
one thinks on it, a public forum invites public rants and ruminations 
merely triggered by one's actual question or comment so one might not in 
fact want to take the "u"-word literally. When coupled with an explicit 
and it turns out precisely accurate disclaimer not to take the "u"-word 
personally, methinks a simple "nice rant, but as you so graciously 
allowed, not relevant to my requirements" would suffice.

We call these things "articles". What if we never used the words "you" 
or "I"? I have gone back and re-edited to get those words out and was 
impressed at how much less inflammatory the same content seemed. Of 
course my general intent here on c.l.l is to kick off entertaining flame 
wars, so...


> 
>  > it's no "more safe" to call a function that's supposed to
>  > add 1 to a number only to find that it subtracts 1.
> This is ridiculous.  In many cases, one glance at (incf x)
> will be enough to determine whether it's correct.
> The same cannot be said for dozens or hundreds of lines
> of tree-searching code.
> 
>  > A program that does not understand its contract is unsafe.
>  > If a program does understand its
>  > contract, it can use side-effects safely.
> A buggy program is also unsafe, even if it understands its contract.

...and...

> There's also a strong question of whether human programmers are
> infallible and whether bugs should be guarded against in a modular way.

...and...

> I don't think it's code, I think it's a simple fact.  You can't teach
> people to be perfect.  If your code is in production use, it may be
> safer for it to fail gracefully instead of blindly allowing
> every part of the program to change important data.

I won't bother with the disclaimer. I see a gray area, and I am not just 
bullsh*tting as usual, this came up in code reviews on projects in Tall 
Buildings, and it addresses what I heard Kent saying, which of course 
did not apply to anyone's actual situation as Kent guessed was possible. 
Where was I? Oh, the gray area.

Correctimundo, defensive programming (DP), folks (esp. moi) screw up. 
But then we have paranoid programming (PP), referring of course to 
Kent's straw man, not anyone's particular situation. I'll be using DP 
and PP to keep down the message length, necessary because I will be 
continually reiterating that nothing I am saying or have ever or will 
say relates to anything else. So...

The problem with PP is that, if our assumption is that people cannot 
program, then we cannot program. It is one of those complexity deals. 
That's wrong, let me try again: we cannot /in our programming/ make 
allowances for programmer fallibility. It's a slippery slope. Once we 
make that bet, er, hedge, where do we stop? If we want to say this bit 
of code might be flawed or this programmer might be a loose cannon, 
where does the descent into paranoia halt?

The whole TDD thing (test-driven development) says, right, we screw up a 
lot, but let's work out a way that we can code with confidence anyway -- 
we'll add a fixed percentage of development time to produce a great 
honking regression test and bank on that.

But it is a gray area. I do a /lot/ of defensive programming, but more 
in the sense of embedding TDD in the form of assertions to flush out 
likely faults. If a TDD-based system completes a test run it is correct, 
if my programs run at all they are correct. If the latter ever happens, 
man am I going to party.

Note that assertion-sprinkling does not mean I am /programming for 
incompetence/, tho of course (assert nil) is code. I am talking about 
the functional algorithm having code that reflects the fact that I might 
have screwed up. There's an infinite recursion if I ever saw one.

Note again that this rant was merely triggered by the comment about 
programmer fallability, and in no way ... ah, f*ck it, this is Usenet. 
(Yes, the espresso just cut in.)

kt

-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Pascal Bourguignon
Subject: Re: copying arrays
Date: 
Message-ID: <878xc9dcnc.fsf@thalassa.lan.informatimago.com>
Ken Tilton <···@theoryyalgebra.com> writes:
> [...]
> The problem with PP is that, if our assumption is that people cannot
> program, then we cannot program. It is one of those complexity
> deals. That's wrong, let me try again: we cannot /in our programming/
> make allowances for programmer fallibility. It's a slippery
> slope. Once we make that bet, er, hedge, where do we stop? If we want
> to say this bit of code might be flawed or this programmer might be a
> loose cannon, where does the descent into paranoia halt?

In a way, and language specified error signaling is defensive programming.

Why should (/ 1 0) signal an error? It's obvious to everybody that you
should never try to divide 1 by 0.  So there's no need to consider
this case in the code of /.


My point would be that DP or PP might be good ideas in some
circumstances and in some places, like near "interfaces".


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Small brave carnivores
Kill pine cones and mosquitoes
Fear vacuum cleaner
From: Ken Tilton
Subject: Re: copying arrays
Date: 
Message-ID: <_1qZh.991$eH4.55@newsfe12.lga>
Pascal Bourguignon wrote:
> Ken Tilton <···@theoryyalgebra.com> writes:
> 
>>[...]
>>The problem with PP is that, if our assumption is that people cannot
>>program, then we cannot program. It is one of those complexity
>>deals. That's wrong, let me try again: we cannot /in our programming/
>>make allowances for programmer fallibility. It's a slippery
>>slope. Once we make that bet, er, hedge, where do we stop? If we want
>>to say this bit of code might be flawed or this programmer might be a
>>loose cannon, where does the descent into paranoia halt?
> 
> 
> In a way, and language specified error signaling is defensive programming.
> 
> Why should (/ 1 0) signal an error? It's obvious to everybody that you
> should never try to divide 1 by 0.  So there's no need to consider
> this case in the code of /.

That is not paranoia, that is completeness. One has to consider (handle) 
zero as a denominator once one decides to have the / operator at all, 
and since by the definition of that operator no value can be returned as 
a result of division by zero, the API needs to include "...and watch out 
for this error...".

> 
> 
> My point would be that DP or PP might be good ideas in some
> circumstances and in some places, like ...

Like I said, it is a gray area. I comes down to cases. Come to think of 
it, this is one of those useless rules, because the hard part is knowing 
where in the gray some case falls.

kt

-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Ken Tilton
Subject: Re: copying arrays
Date: 
Message-ID: <2kqZh.992$eH4.70@newsfe12.lga>
Ken Tilton wrote:
> 
> 
> Pascal Bourguignon wrote:
> 
>> Ken Tilton <···@theoryyalgebra.com> writes:
>>
>>> [...]
>>> The problem with PP is that, if our assumption is that people cannot
>>> program, then we cannot program. It is one of those complexity
>>> deals. That's wrong, let me try again: we cannot /in our programming/
>>> make allowances for programmer fallibility. It's a slippery
>>> slope. Once we make that bet, er, hedge, where do we stop? If we want
>>> to say this bit of code might be flawed or this programmer might be a
>>> loose cannon, where does the descent into paranoia halt?
>>
>>
>>
>> In a way, and language specified error signaling is defensive 
>> programming.
>>
>> Why should (/ 1 0) signal an error? It's obvious to everybody that you
>> should never try to divide 1 by 0.  So there's no need to consider
>> this case in the code of /.
> 
> 
> That is not paranoia, that is completeness. One has to consider (handle) 
> zero as a denominator once one decides to have the / operator at all, 
> and since by the definition of that operator no value can be returned as 
> a result of division by zero, the API needs to include "...and watch out 
> for this error...".

No, that's not the point. The point is that throwing an error is not 
"programming for mistakes". Probably many of you have never even heard 
such a thing proposed, so will have a hard time understanding the 
distinction. I am not talking about (assert (not (zerop n)), I am 
talking about extending oneself in interesting ways because "someone 
might X". The key quality of "interesting" not held by ASSERT is that it 
has a cost to develop and itself is complex enough to go wrong. Another 
likely quality is that, once built in, not easily yanked.

It is just as easy to code after (when (zerop denominator)...) (break 
"div by zero dude") as it would be (return 42).

kt


-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Dan Bensen
Subject: Re: copying arrays
Date: 
Message-ID: <f16anb$lkv$1@wildfire.prairienet.org>
Ken Tilton wrote:
> if one thinks on it, a public forum invites public rants and ruminations 
> merely triggered by one's actual question or comment so one might not in 
> fact want to take the "u"-word literally.
Public forums encourage participation.  Consider my participation
another rant. :)

 > this came up in code reviews on projects in Tall
 > Buildings, and it addresses what I heard Kent saying
I'm sure many things come up in code reviews.  There's a lot of
horrific code out there, and "programmers" writing more of it.

 > Correctimundo, defensive programming (DP), folks (esp. moi) screw up.
Now don't be shy, Ken.  We all know that fault-free code flows
effortlessly from your fingertips to the keyboard, as it has
from the day you were born :)

 > But then we have paranoid programming (PP), referring of course to
 > Kent's straw man, not anyone's particular situation. ... we cannot
 > /in our programming/ make allowances for programmer fallibility.
 > It's a slippery slope. Once we make that bet, er, hedge, where do
 > we stop?  If we want to say this bit of code might be flawed or
 > this programmer might be a loose cannon, where does the descent
 > into paranoia halt?

That's a life-as-mathematical-equations argument.  The descent halts
when we stop looking for simple universal formulas and start using
a little experience, intuition, judgement, etc..  I don't think
the slope is so slippery if you approach the subject pragmatically.
There are also books out there with rules of thumb and whatnot.

-- 
Dan
www.prairienet.org/~dsb/
From: Ken Tilton
Subject: Re: copying arrays
Date: 
Message-ID: <1VAZh.11355$eH4.4430@newsfe12.lga>
Dan Bensen wrote:
> Ken Tilton wrote:
> 
>> if one thinks on it, a public forum invites public rants and 
>> ruminations merely triggered by one's actual question or comment so 
>> one might not in fact want to take the "u"-word literally.
> 
> Public forums encourage participation.  Consider my participation
> another rant. :)
> 
>  > this came up in code reviews on projects in Tall
>  > Buildings, and it addresses what I heard Kent saying
> I'm sure many things come up in code reviews.  There's a lot of
> horrific code out there, and "programmers" writing more of it.

Never been to a code review, have you? You are blessed. The worst crap 
in the world gets protected by the manager because he is the only person 
in the room more clueless than the author of the crap and dies when the 
author dies because the author is in effect a buoyancy device for the in 
effect non-swimmer manager. But I digress.

I am talking about the good code that gets rejected because someone 
might write it wrong. Come to think of it, we just defined Java, an 
entire language devoid of things ever known in the past to have been a 
source of bugs.

> 
>  > Correctimundo, defensive programming (DP), folks (esp. moi) screw up.
> Now don't be shy, Ken.  We all know that fault-free code flows
> effortlessly from your fingertips to the keyboard, as it has
> from the day you were born :)

New here, eh? Go study up on me so with all the facts in place your 
intellect will be the only drag on this discussion.

I cannot write correct code to save my life, I just throw out any bad 
code. Only trick there is to distract the author with a banana while 
deleting their code.


> 
>  > But then we have paranoid programming (PP), referring of course to
>  > Kent's straw man, not anyone's particular situation. ... we cannot
>  > /in our programming/ make allowances for programmer fallibility.
>  > It's a slippery slope. Once we make that bet, er, hedge, where do
>  > we stop?  If we want to say this bit of code might be flawed or
>  > this programmer might be a loose cannon, where does the descent
>  > into paranoia halt?
> 
> That's a life-as-mathematical-equations argument.  The descent halts
> when we stop looking for simple universal formulas and start...

... listening instead of yapping? Read my frickin lips: I am talking 
about actual tall-office design reviews in which well-paid engineers...

  using
> a little experience, intuition, judgement, etc..  I don't think
> the slope is so slippery if you approach the subject pragmatically.

... pragmatically suggested design disasters because they objected to 
anything a pet rock (sorry, Rockie) could not code.

> There are also books out there with rules of thumb and whatnot.
> 

Yourdon's "Death March"? Glass's "Software Runaways: Monumental Software 
  Disaster"?

kzo

-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Alan Manuel K. Gloria
Subject: Re: copying arrays
Date: 
Message-ID: <1178029111.904868.199450@e65g2000hsc.googlegroups.com>
On Apr 29, 2:22 pm, Dan Bensen <··········@cyberspace.net> wrote:
> Alan Manuel K. Gloria wrote:
>
> > In my experience it's quite rare to have to have to *copy* a
> > sequence.  If you're manipulating an array, why would you want to
> > retain the previous version?
>
> In a game, you might want to pass the state of the game
> (e.g. the board in a board game) to a computer player
> so it can decide what it wants to do.  The safe way to do that
> would be to pass the player a copy, so the player doesn't
> corrupt the game.  Often the player will destructively modify
> the board, but undo all its changes at the end.  With a copy,
> you can also check the player for correctness by comparing
> the final state of the player's copy with the original board.
My approach is more of a functional paradigm rather than imperative.
The imperative paradigm would view it as copying the board and
modifying what it wants to modify.  The functional paradigm would view
it as *creating* a new board, and generating the potential move.  In
fact, the functional paradigm would actually be *closer* to what the
computer does in this case: you create a new board by allocating it,
and fill in the new board with the values for the move.

Basically, I'd create a new subfunction which, given the board piece
at a particular board position, would figure out a potential move to a
potential new board position.  This inner subfunction would be called
to determine all possible moves, from which I would figure out the
best one.

The imperative style of copying the game board for use as a scratch
pad would be the eventual result of optimizing the original function
style, but while thinking about the problem I'd rather use the
functional style, and imperativy it only if it really is too slow/big
that way.

So yes, let me re-ask the question: are you *sure* you want a copy, or
do you want a new sequence that is almost like, but not the same, as
the original?  A mapcar- or filter-type solution would be more succint
than a copy-seq/loop solution.
From: Dan Bensen
Subject: Re: copying arrays
Date: 
Message-ID: <f186ni$8q9$1@wildfire.prairienet.org>
Alan Manuel K. Gloria wrote:
 > The imperative paradigm would view it as copying the board and
 > modifying what it wants to modify.  The functional paradigm would view
 > it as *creating* a new board, and generating the potential move.

I'm not sure the OP cares what paradigm we use, as long as he
gets a copy.

 > In fact, the functional paradigm would actually be *closer* to what
 > the computer does in this case: you create a new board by allocating
 > it, and fill in the new board with the values for the move.

I think you're conflating different function calls, at least
in what I had in mind.  I have a referee calling the player,
which recieves a board, but returns a move rather than a new board.
All changes to the official board are made by the referee, so
there's no need to worry about what the player does with its copy.

 > The imperative style of copying the game board for use as a scratch
 > pad would be the eventual result of optimizing the original function
 > style, but while thinking about the problem I'd rather use the
 > functional style, and imperativy it only if it really is too slow/big
 > that way.

"too slow/big" sounds like you want to make a copy at every node of
the move search, which is what Kent was ranting about.
Even at the root node, a functional style can be maintained by
making the copy directly in the call to the player:
   (let ((next-move (find-move (copy-board board)))) ...

But that's still different from using the original and hoping
that find-move doesn't mess it up.

 > So yes, let me re-ask the question: are you *sure* you want a copy, or
 > do you want a new sequence that is almost like, but not the same, as
 > the original?

I definitely want to pass an exact copy to the computer player,
because that's the state it has to deal with.  This would also apply
to software that does any other kind of searching or planning.
I would allow speculative branches of the code to use copies
as scratchpads, while the central control function retains
and updates the original only when it's ready to commit a change.

-- 
Dan
www.prairienet.org/~dsb/
From: Ken Tilton
Subject: Re: copying arrays
Date: 
Message-ID: <5KUYh.82$y25.14@newsfe12.lga>
Q wrote:
> Hi all,
> 
> Simple question:
> 
> CL-USER 37 > (setf a (make-array 5 :initial-element 7))
> #(7 7 7 7 7)
> 
> CL-USER 38 > (setf b a)
> #(7 7 7 7 7)
> 
> CL-USER 39 > (eq a b)
> T
> 
> CL-USER 40 > (setf (aref a 0) 9)
> 9
> 
> CL-USER 41 > a
> #(9 7 7 7 7)
> 
> CL-USER 42 > b
> #(9 7 7 7 7)
> 
> How do I pass copies of the array around, instead of the array
> itself?  I don't want them to be eq.  But, it'd be nice if they were
> equal :)
> 

copy-seq?

kt

-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Frank Buss
Subject: Re: copying arrays
Date: 
Message-ID: <f9e4ylkv2r72$.ouwy2dtcla76.dlg@40tude.net>
Q wrote:

> CL-USER 37 > (setf a (make-array 5 :initial-element 7))
> #(7 7 7 7 7)

You should use defparameter or defvar, if you didn't bound "a" before.

> How do I pass copies of the array around, instead of the array
> itself?  I don't want them to be eq.  But, it'd be nice if they were
> equal :)

http://www.cliki.net/SHALLOW-COPY-ARRAY

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Espen Vestre
Subject: Re: copying arrays
Date: 
Message-ID: <m1odl7zfbm.fsf@gazonk.netfonds.no>
Q <······@gmail.com> writes:

> How do I pass copies of the array around, instead of the array
> itself?  I don't want them to be eq.  But, it'd be nice if they were
> equal :)

I use copy-seq, but note that copy-seq always makes a simple-array
(which is something I discovered just last week... I needed a fill-
pointer in both the original and the copy).
-- 
  (espen)
From: Harold Lee
Subject: Re: copying arrays
Date: 
Message-ID: <1177866195.982475.24500@u30g2000hsc.googlegroups.com>
On Apr 29, 2:43 am, Espen Vestre <····@vestre.net> wrote:
> Q <······@gmail.com> writes:
> > How do I pass copies of the array around, instead of the array
> > itself?  I don't want them to be eq.  But, it'd be nice if they were
> > equal :)
>
> I use copy-seq, but note that copy-seq always makes a simple-array
> (which is something I discovered just last week... I needed a fill-
> pointer in both the original and the copy).
> --
>   (espen)

Search for COPY-ARRAY in this newsgroup and you'll see a lot of
similar discussions. They discuss how to duplicate the dimensions,
element type, fill pointer, etc.

-Harold
From: Kent M Pitman
Subject: Re: copying arrays
Date: 
Message-ID: <uveffumpn.fsf@nhplace.com>
Espen Vestre <·····@vestre.net> writes:

> Q <······@gmail.com> writes:
> 
> > How do I pass copies of the array around, instead of the array
> > itself?  I don't want them to be eq.  But, it'd be nice if they were
> > equal :)
> 
> I use copy-seq, but note that copy-seq always makes a simple-array
> (which is something I discovered just last week... I needed a fill-
> pointer in both the original and the copy).

I find it oddly amusing to see the phrase "it'd be nice if they were equal"
given that it's not obvious to me what equal means.

There are many equality predicates.  Why is equal, whose semantics are
relatively arbitrary, the one that copying should try to be faithful
to.  It seems to me that this confirms my initial feeling that equal
should not have been in the language, because it encourages people to
see it as canonical, when it is not.  People grab it as a highly blunt
tool for use in circumstances where they don't care a lot.  And it
suffices for that.  I suppose we could have an equally blunt copy
function.  But it would just lead to more people confusing themselves.
For an awful lot of things, both of these tools fall short.

Ok, I don't really misunderstand how and why people use blunt tools.
We're probably optimized for it.  But let me say it a different way:
It's rarely the people who understand that culture of how to make good
on blunt tools who complain. The complaint about the absence of copying
often comes from people with languages that do more static type checking
and pay more lip service to notions like formal semantics than Lisp does.
And I find it curious that a discussion which begins from a belief that
side effects are bad for some theoretical-sounding reason can so quickly
lead to a conclusion that having a relatively arbitrarily defined copy
function would be good.  It's hard to see how to build a coherent anything
atop semantics of the arbitrary.

I guess it's like all abstracts--truth, justice, etc.  It always seems
so obvious to us what they are.  But, of course, it's really not.
From: Pebblestone
Subject: Re: copying arrays
Date: 
Message-ID: <1177879755.875579.40660@y80g2000hsf.googlegroups.com>
I think this might be something you want. I forgot where does it come
from, so please add the reference.


(defun copy-array (array &key (undisplace nil))
  "Shallow copies the contents of any array into another array with
equivalent properties.  If array is displaced, then this function will
normally create another displaced array with similar properties,
unless UNDISPLACE is non-NIL, in which case the contents of the array
will be copied into a completely new, not displaced, array."
  (declare (type array array))
  (let ((copy (%make-array-with-same-properties array undisplace)))
    (unless (array-displacement copy)
      (dotimes (n (array-total-size copy))
        (setf (row-major-aref copy n) (row-major-aref array n))))
    copy))

(defun %make-array-with-same-properties (array undisplace)
  "Make an array with the same properties (size, adjustability, etc.)
as another array, optionally undisplacing the array."
  (apply #'make-array
		 (list* (array-dimensions array)
				:element-type (array-element-type array)
				:adjustable (adjustable-array-p array)
				:fill-pointer (when (array-has-fill-pointer-p array)
								(fill-pointer array))
				(multiple-value-bind (displacement offset)
					(array-displacement array)
				  (when (and displacement (not undisplace))
					(list :displaced-to displacement
						  :displaced-index-offset offset))))))