> > > > This is a subtle but really crucial point. In C++ call-by-value really > > > > means something more like "call-by-copy-of-value" whereas in Lisp > > > > call-by-value means call-by-actual-value.
> > > No, this interpretation is wrong.
> > That may be. Nonetheless the behavior of two apparently equivalent
> "Apparently" according to whom?
Me.
> They do not look equivalent to me.
But you are not the target audience for my explanation. The target audience for my explanation was a C++ programmer who is just beginning to learn Lisp who has just been told (only) that both C++ and Lisp use call-by-value semantics.
> They do not even look similar to me. C and Lisp are different > languages. Simply assuming that there is some sort of 1-1 > correspondence is not going to work.
Obviously. People do nonetheless assume this, and if you're going to explain things to them effectively you have to take that into account.
> The problem that we are having is that different people seem to have > different ideas of where the 1-1 correspondence breaks down.
That's right. But if you're going to explain something to someone you have to do it on *their* terms (assuming, of course, that your goal is actually to educate someone, and not simply to put your superior knowledge on display).
> > This is not to say that you're wrong; I know you're not. But the point > > here is not to be right. The point here is to explain how Lisp works to a > > C programmer.
> I think the point is to be right, not to try to distort one's > explanation with falsehoods just to avoid having to correct someone's > earlier misconceptions. It is the same as with lying: Once you start, > it is impossible to stop. One lie leeds to another, and it becomes > increasingly difficult to stay consistent.
An approximation to the truth is not the same thing as a lie.
> > And most C programmers don't know that this is how C works > > because most C books don't explain it this way.
> That is unfortunate, but not my fault. :-)
It most certainly is your fault. Where are your publications written for a non-academic audience? Where is your book on C that explains how lvalues get coerced in rvalue contexts? Oh, you haven't written any? Then it is your fault that people don't know this stuff. Your fault, and mine, and the fault of everyone who understands what's really going on but hasn't bothered to put in the effort to explain it to people in ways that they can understand it.
> > Yes, but that's not nearly as easy to do as the brevity of your > > description implies. I didn't say it was impossible, I just said it was a > > substantial amount of work. All you've done is give a brief description > > of the work.
> Well, I have done this work several times over. Trust me, it is > really not hard at all compared to many other things that come up when > implementing HLLs.
I believe that. But just because it isn't hard relative to something else doesn't mean it's not "a substantial amount of work."
g...@jpl.nasa.gov (Erann Gat) writes: > and the fault of everyone who understands what's really going > on but hasn't bothered to put in the effort to explain it to > people in ways that they can understand it.
to recast fault-finding constructively and paraphrase some old dudes: what is a good person but a bad person's teacher? what is a bad person but a good person's job?
* Frode Vatvedt Fjeld <fro...@acm.org> | So maybe this description could be correct, and informative for | outsiders: | | Common Lisp is call-by-value. Every value is (or can be considered to | be) a pointer, however some values (like numbers, characters, and nil) | are immutable.
I think we need a fresh start.
Argument passing in Common Lisp is conceptually equivalent to building a list of the result of evaluating each of the argument forms to the function and passing that list to the function, which conceptually unpacks it into the formal parameters. All knowledge of the source of the values is lost by that time.
The conceptual equivalence to a list is used to lay the ground for apply, &rest, &key, etc, and also neatly captures the order of evaluation so an explanation of this rule will fall out naturally from the description. -- In a fight against something, the fight has value, victory has none. In a fight for something, the fight is a loss, victory merely relief.
70 percent of American adults do not understand the scientific process.
> I hate to blaspheme here in the presence of so much useless formalism, > but all that really matters to me is to be able to explain the > behavior to users in terms they are familiar with.
Well, the question is: _Are_ you (able to explain)? I think the answer is "no". Otherwise there wouldn't be so much confusion about these issues around here.
> Formalisms exist > to serve me, not me to serve a formalism. When you start talking > about what happens inside and how it's hidden by the surface language, > you're basically giving me all the confirmation I need that I've made > a good decision to avoid this terminology.
Where did I say anything about something being "hidden" by the surface language?
> You're welcome to try to > sway others with the kind of argument you're making above as a kind of > abstract esoteric discussion among language designers; but when it > comes to teaching people and helping them avoid errors, I don't think > any of this tommyrot is how I want to do my teaching.
You are, of course, welcome to do you teaching any way you like. Whether it actually does your students a favor is debateable, though.
> There's way too > much purposeless baggage in your exposition; I don't want my students
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Huh? You haven't even made an _attempt_ at trying to understand, have you? If you had, you would know that there is a purpose to all that.
> thinking about problems in the way you suggest. That doesn't mean > it's not possible to think about it that way--it just isn't my cup of > tea. Thanks for the suggestions anyway, though.
You are welcome to use non-standard and ill-defined terms such as "pass-by-identity". You probably have a good mental model of what you mean by those, but if you actually try to make them precise, you inevitably have to do something along the lines of how PL semanticists usually do things (i.e, the way I tried -- clearly unsuccessfully -- to described it to you).
Most of the trouble with guys like the original poster is that they tend to have a good graps of neither the semantics of their "home language" (C++ in this case) nor the new language in question (Lisp). If people wouldn't dismiss precise semantics out of hand, refusing to learn them, and if they would not be encouraged in this attitude by renowned seniority such as yourself, we wouldn't have quite as many of these discussions. As Erik said, all this is CS101 stuff.
g...@jpl.nasa.gov (Erann Gat) writes: > > They do not even look similar to me. C and Lisp are different > > languages. Simply assuming that there is some sort of 1-1 > > correspondence is not going to work.
> Obviously. People do nonetheless assume this, and if you're going to > explain things to them effectively you have to take that into account.
As much as it is important to build on existing knowledge when trying to communicate new knowledge, it is important not to further existing misconceptions (guised as "existing knowledge") by trying to build on them.
> > The problem that we are having is that different people seem to have > > different ideas of where the 1-1 correspondence breaks down.
> That's right. But if you're going to explain something to someone you > have to do it on *their* terms (assuming, of course, that your goal is > actually to educate someone, and not simply to put your superior knowledge > on display).
Not if "*their* terms" are wrong to begin with. In that case, the first thing to do is establish new, correct terms.
> > > And most C programmers don't know that this is how C works > > > because most C books don't explain it this way.
> > That is unfortunate, but not my fault. :-)
> It most certainly is your fault. Where are your publications written for > a non-academic audience? Where is your book on C that explains how > lvalues get coerced in rvalue contexts? Oh, you haven't written any? > Then it is your fault that people don't know this stuff. Your fault, and > mine, and the fault of everyone who understands what's really going on but > hasn't bothered to put in the effort to explain it to people in ways that > they can understand it.
I would be ready to take (some of) the blame if the situation were such that there are *no* C books that explain things correctly. But that is not so.
C books that explain things correctly exist. Me writing one more would not have made a difference. Or are you trying to say that I should write a couple of hundred "correct" C books to give "correct" C books the majority? :-)
> > > Yes, but that's not nearly as easy to do as the brevity of your > > > description implies. I didn't say it was impossible, I just said it was a > > > substantial amount of work. All you've done is give a brief description > > > of the work.
> > Well, I have done this work several times over. Trust me, it is > > really not hard at all compared to many other things that come up when > > implementing HLLs.
> I believe that. But just because it isn't hard relative to something else > doesn't mean it's not "a substantial amount of work."
When I wrote the three lines above, I somewhat expected you to come back with this reply. Unfortunately, I resisted my urge to say "It is dead easy." -- which is what I originally intended to write. And yes, it *is* dead easy. In fact, I don't see at all why you think that there would be any problem whatsoever.
Erik Naggum wrote: > * "Pierre R. Mai" <p...@acm.org> > | Isn't CL fun?
> I think I regret posting that first seed of this idea. :) > -- > In a fight against something, the fight has value, victory has none. > In a fight for something, the fight is a loss, victory merely relief.
> 70 percent of American adults do not understand the scientific process.
----- Original Message ----- From: "Joe Marshall" <prunesqual...@attbi.com> Newsgroups: comp.lang.lisp Sent: Thursday, May 02, 2002 6:55 PM Subject: Re: quest for pass-by-reference semantics in CL
> I think that rather than discussing `call-by-value' vs. `call-by-reference', > that the clearest description of Lisp for a C++ programmer is this:
> Nearly everything in Lisp is a pointer to a struct.
I have always thought in terms of, *everything* in Lisp is a pointer to a struct, but some of those structs are immutable and an attempt to modify simply creates a new object.
That is, you can think of an integer as being implemented as a struct, and something like (setf (ldb (byte 8 8) i) 25) simply creates a new struct rather than returning a modified one. In most (if not all) Lisp implementations, small integers are not implemented as structs, but you can only know this by observing allocation meters; there isn't an "in language" way to figure out that integers are not implemented as structs. And of course, bignums work exactly the way I described; (setf (ldb (byte 8 8) a-bignum) 25) does not modify the struct that represents the bignum.
This little trick I play on myself works because Lisp has no way to explicitly create pointers, or to dereference those pointers that you can't create anyway.
Somebody long ago -- maybe Dan Weinreb -- referred to this as "call by value-reference", and that's what I still think of it as.
> > I've also disliked the usage of the term "tagged pointer" to describe > > the words which describe Lisp objects, for the same reason (pointer > > implies address, which doesn't exist for an immediate object). So I > > have always described these tagged words as LispVals, and thus by using > > a completely made-up word I avoid the preconception of whether a > > LispVal is a pointer or a value (it is both and it is none). And if > > one accepts the made-up and unencumbered term LispVal, it becomes > > obvious that Lisp is "pass by LispVal".
> Not the sort of term you'd expect any other language to adopt. ;) > I'd accept "by object"...? LispVal is a foreign term to anyone who uses > the language. It also suggests that it can't be used for any other language, > when in fact I think it should be usable by other languages.
Right. As I said in another post, I would be willing to have a better term suggested than LispVal, one which is more general than pertaining only to Lisp. However, if you accept "by object", are you ready for all of the overloading which _that_ term has on it? :-)
-- Duane Rettig Franz Inc. http://www.franz.com/ (www) 1995 University Ave Suite 275 Berkeley, CA 94704 Phone: (510) 548-3600; FAX: (510) 548-8253 du...@Franz.COM (internet)
Matthias Blume <matth...@shimizu-blume.com> writes: > No. I am using the usual meaning of call-by-value. And, yes, there > are systems that do not "pass-by-value". Examples are Haskell and > Miranda (call-by-need aka lazy evaluation), Algol (call-by-name), > Pascal and friends (including C++) where you can declare parameters as > call-by-reference, Ada (can declare parameters as call-by-copy-in-out). > Maybe there are more.
Hey, how about the grand-daddy of them all! FORTRAN is traditionally call-by-value-result. However, in FORTRAN 77 (I don't know about the more recent standards), implementations were allowed to use call-by-reference instead, and compatible programs are not allowed to do anything that might tell the difference.
(I assume that what I was taught to call call-by-value-result is what you say Ada does with call-by-copy-in-out.)
> > Would it be wrong to say that CL is pass-by-reference, with the > > exception of numbers and characters, which are pass-by-value?
> Yes, that would be wrong.
It's easiest if you think of *everything* as being pass-by-reference.
Numbers and characters are immutable objects which means there are no operations that allow you to change their value. So there isn't any way that you can find out whether they are passed by reference or by value.
In article <m33cxadkir....@hanabi.research.bell-labs.com>, Matthias Blume
<matth...@shimizu-blume.com> wrote: > C books that explain things correctly exist.
Really? Would you be so kind as to cite a few?
> Me writing one more would not have made a difference.
How do you know?
> Or are you trying to say that I > should write a couple of hundred "correct" C books to give "correct" C > books the majority? :-)
No need to write a couple of hundred, but it should be a number greater than zero if you want to claim that it's not your fault that people don't know this stuff. People don't know this stuff because they read Stroustrup's book instead of yours, because his exists and yours doesn't. That's your fault. Or maybe they read Stroustrup instead of someone else's book because you never got around to telling anyone which books are the ones that "explain things correctly." That's your fault too.
> > > > Yes, but that's not nearly as easy to do as the brevity of your > > > > description implies. I didn't say it was impossible, I just said it was a > > > > substantial amount of work. All you've done is give a brief description > > > > of the work.
> > > Well, I have done this work several times over. Trust me, it is > > > really not hard at all compared to many other things that come up when > > > implementing HLLs.
> > I believe that. But just because it isn't hard relative to something else > > doesn't mean it's not "a substantial amount of work."
> When I wrote the three lines above, I somewhat expected you to come > back with this reply. Unfortunately, I resisted my urge to say "It is > dead easy." -- which is what I originally intended to write. And yes, > it *is* dead easy. In fact, I don't see at all why you think that > there would be any problem whatsoever.
I didn't say it was a problem. I didn't say it wasn't easy. I just said it was a substantial amount of work. Many things in C are neither problematic nor hard but are nonetheless a substantial amount of work, at least by comparison with Lisp. (Creating complex linked data structures, for example.)
You could prove me wrong by posting some code that shows how it's done. If it's as dead-easy as you say it shouldn't take you very long.
Matthias Blume <matth...@shimizu-blume.com> writes: > Jacek Generowicz <jacek.generow...@cern.ch> writes:
> > In what sense do you mean that "as in Lisp" no copy is made ? In > > Common Lisp, when passing objects (with the possible excepiton of > > numbers and characters), no new instance (copy) is made; in (C and) > > C++ there is (as can be seen above).
> Read my reply to the OP
You appear not to have repiled to the OP. I'm not prepared to trawl through all your other replies trying to guess which one you mean.
> who posted the same irrelevant (since besides-the-point) stuff.
Beside which point ? The name of this thread is `quest for pass-by-reference semantics in CL'. Such a quest is motivated by the misunderstaning of what happens when Lisp passes by value. If anything is beside the point, then it is your insintence that it does, strictly speaking, pass by value.
> There simply is no Lisp equivalent of a C variable of struct type.
Fine, use the (exteremely relevant) example of a C++ object. The OP wanted pass-by-reference which doesn't even exist in C.
> A variable holding a struct in Lisp is equivalent to a C pointer to > a C struct.
Equivalent in what sense? In the latter one has to faff around with explicitly dereferencing the pointer to get at the interesting data, in the latter one does not. Your equivalence relation strikes me as irrelevant.
> In C and in Lisp, when using a variable as the actual argument to a > function call, the bits in all the locations denoted by that > variable get copied into a fresh location denoted by the formal > parameter of the function.
Define `denoted'. I can't find an entry for `denote' in the Hyperspec. The Oxford English Dictonary gives (among less relevant things) the following:
To signify; to stand for as a symbol, or as a name or expression
Consider (setq x (list "hello" (make-instance 'blark)) ... ).
You appear to be suggesting that "hello" and the instance of blark will get copied to fresh locations when x is passed as an argument to a function.
> It just so happens that in Lisp, the number of locations so copied > is always 1 while in C it can be greater than 1. > A "value", btw., is just those "bits" without the location that stores > them.
How do you reconcile this with the preceding two lines ? Specifically, how does any arbitrarily complex, compound lisp object get passed by value satisfying both your conditions:
a) no more that 1 location is copied, b) the locaton that stores the object is not part of the value
?
> In contrast, call-by-reference does not transmit the bits. > Instead, it transmits the location(s)
Sounds very much like what happens in Lisp: the bits making up the "hello" and the blark instance are not transmitted.
If you really wanted to carry your argument ad absurdum, then I'm sure you could argue that pass-by-reference doesn't exist anywhere, because ultimately, somewhere in the implementation a value representing the reference is passed.
> > > > In C, pass-by-value implies that a copy is made of the value passed,
> > > Nonsense!!
> > Of course. How can I argue with such authority?
> Right, I was wondering, too.
> > > In C, as in Lisp, no copy is made.
> > You should check your facts. I agree that in Lisp no copy is made > > (except in the actual transfer of the always-one-word LispVal from > > caller to callee). But C is allowed to copy small structs, as part > > of the pass-by-value strategy. And most other C values are one-word > > values, and as such they are copied or transferred, however you > > wish to call it.
> I know my facts. See my answer to Erann's post.
OK, here are a few items I pulled off the web to lend credence to my "Nonsense":
===
Brian W. Kernigan (1974) "Programming In C: A Tutorial"
"Simple variables (not arrays) are passed in C by ``call by value'', which means that the called function is given a copy of its arguments, and doesn't know their addresses."
(Here, Kernigan is defining call-by-value, where copying is explicitly prescribed.)
Question 2.7: "I heard that structures could be assigned to variables and passed to and from functions, but K&R1 says not."
Answer: "What K&R1 said was that the restrictions on structure operations would be lifted in a forthcoming version of the compiler, and in fact structure assignment and passing were fully functional in Ritchie's compiler even as K&R1 was being published. Although a few early C compilers lacked these operations, all modern compilers support them, and they are part of the ANSI C standard, so there should be no reluctance to use them.
"However, passing large structures to and from functions can be expensive (see question 2.9), so you may want to consider using pointers, instead (as long as you don't need pass-by-value semantics, of course)."
(Here, the structure passing style is clearly labelled pass-by-value.)
Question 2.9: "How are structure passing and returning implemented?"
Answer (for the passing half): "When structures are passed as arguments to functions, the entire structure is typically pushed on the stack, using as many words as are required. (Programmers often choose to use pointers to structures instead, precisely to avoid this overhead.) Some compilers merely pass a pointer to the structure, though they may have to make a local copy to preserve pass-by-value semantics.
(Again, pass-by-value is clearly distinguished from explicit passing by reference).
(Here's a C++ reference which strongly encourages creating copy constructors for classes you define, explicitly because passing by value _means_ calling the copy constructor!)
===
I believe that my case is not to prove to you what "pass-by-value" means - it is going to mean to you whatever you want it to mean. What I do hope you'll start to understand is that "pass-by-value" has multiple meanings, and that such multiple meanings cause problems for Lisp and languages like it. That is why Kent and I each coin and search for more descriptive (or less overloaded) terminology to describe what goes on. The semantics of Lisp's calling style shouldn't need all of the baggage that "pass-by-value" carries with it.
-- Duane Rettig Franz Inc. http://www.franz.com/ (www) 1995 University Ave Suite 275 Berkeley, CA 94704 Phone: (510) 548-3600; FAX: (510) 548-8253 du...@Franz.COM (internet)
> > > I've also disliked the usage of the term "tagged pointer" to describe > > > the words which describe Lisp objects, for the same reason (pointer > > > implies address, which doesn't exist for an immediate object). So I > > > have always described these tagged words as LispVals, and thus by using > > > a completely made-up word I avoid the preconception of whether a > > > LispVal is a pointer or a value (it is both and it is none). And if > > > one accepts the made-up and unencumbered term LispVal, it becomes > > > obvious that Lisp is "pass by LispVal".
> > Not the sort of term you'd expect any other language to adopt. ;) > > I'd accept "by object"...? LispVal is a foreign term to anyone who uses > > the language. It also suggests that it can't be used for any other language, > > when in fact I think it should be usable by other languages.
> Right. As I said in another post, I would be willing to have a better > term suggested than LispVal, one which is more general than pertaining > only to Lisp. However, if you accept "by object", are you ready for all > of the overloading which _that_ term has on it? :-)
Oh sure. At least here I've got the moral high ground. And besides, it matters a lot more to make the term meaningful within Lisp than for people who want to compare languages. The essence of what I hear Matthias Blume saying is basically just that I should begin from the terms others use outside, and I reject that premise. They have made no effort to begin with terms that are familiar to us, and we're a very old language community that pre-dates those things which are asserting a right to dictate terminology... I say we make the best of it and leave the comparative linguists (which include myself btw, on other days) to fend for themselves.
Btw, I went to a meeting (perhaps the first meeting) of X3H7 which was going to address this issue. It seemed to be an attempt to transplant some CORBA group to ANSI rules, and I found it a little troubling because it kind of had a pre-dictated agenda that was hard for outsiders to affect, so I declined to attend subsequent meetings, not wanting to waste my time. But one thing we did for that meeting was go around the room and ask people what an object was. The answers were revealing. One person said, "I think an object is like--like--a database." Another said, "I think an object is like a satellite. A satellite is an object isn't it?" Weird stuff like that. Very touchy-feely. I said "I think an object is something you can pass to a function as an argument in a function call." There was spontaneous laughter when I said this. I think they thought I was kidding. My answer was ridiculously concrete compared to the others people were offering... but that was the point. And again, this is the yin to the yang of the other point: _of course_ Lisp is call by object/identity, since what you want to do in Lisp is give objects (or object identities) as arguments to functions, and have those objects still be themselves when they arrive on the other side. The pass-through of the argument is supposed to be an identity transformation!
Then again, maybe the real problem is not over the function calling but that we have lost the war on what identity means. If so, that's very sad.
> > > Would it be wrong to say that CL is pass-by-reference, with the > > > exception of numbers and characters, which are pass-by-value?
> > Yes, that would be wrong.
> It's easiest if you think of *everything* as being pass-by-reference.
It may be "easiest", but it is also completely wrong.
Notice that "pass-by-value" (which is the only correct answer to the question) does not imply that the caller cannot change parts of a data structure. The whole question is *only* about how the formal parameter of the function (i.e., within the caller) is related to the actual argument given at the callsite.
Call-by-reference, otoh, would mean that in
(defun f (x) (setq x 2)) (defun g (y) (f y) y) (g 1)
the final answer from calling g would have to be 2. Replace 2 with (CONS 2 '()) and 1 with (CONS 1 '()), and you see a result of (1), not (2). So the problem is unrelated to what data you send to the function.
Jacek Generowicz <jacek.generow...@cern.ch> writes: > > who posted the same irrelevant (since besides-the-point) stuff.
> Beside which point ? The name of this thread is `quest for > pass-by-reference semantics in CL'. Such a quest is motivated by the > misunderstaning of what happens when Lisp passes by value. If > anything is beside the point, then it is your insintence that it does, > strictly speaking, pass by value.
It does, there is nothing I or you could do about it right now. Whether or not it is irrelevant is another question. I don't think it is, though.
> > There simply is no Lisp equivalent of a C variable of struct type.
> Fine, use the (exteremely relevant) example of a C++ object. The OP > wanted pass-by-reference which doesn't even exist in C.
There is no equivalent of a C++ variable of class type in Lisp. A variable holding an object in Lisp would have to be modeled by a pointer to a value of class type in C++.
> > > A variable holding a struct in Lisp is equivalent to a C pointer to > > a C struct.
> Equivalent in what sense?
In the sense that if you write down a variable holding such a thing as an actual argument of a function and the function writes to the formal parameter corresponding to this argument, you will not see the change in the caller. On the other hand, changes to the state of the object itself are visible. The first fact shows that argument passing is by-value, the second shows that objects in Lisp have reference semantics (generally, this is not tied to the problem of argument passing). The only way I know of to achive both in C or C++ is to use pointers to structs/objects.
> In the latter one has to faff around with > explicitly dereferencing the pointer to get at the interesting data, > in the latter one does not. Your equivalence relation strikes me as > irrelevant.
That's because the deref op is built into the respective Lisp operations. This is just like C's or C++'s -> operator which also has a built-in deref. (As a matter of fact, in C++ you do *not* have to write explicit deref ops because the field accessor ".", when applied to a pointer, ends up behaving like ->.)
> > In C and in Lisp, when using a variable as the actual argument to > > a function call, the bits in all the locations denoted by that > > variable get copied into a fresh location denoted by the formal > > parameter of the function.
> Define `denoted'.
It is a standard term in PL semantics.
> Consider (setq x (list "hello" (make-instance 'blark)) ... ).
> You appear to be suggesting that "hello" and the instance of blark > will get copied to fresh locations when x is passed as an argument to > a function.
No, I am not at all suggesting that. The variable x denotes a single location which is not one of those (several) locations that constitute the CONS cells (which in turn make up the list), or which hold the characters in the string, or which make up the blark instance. Under cbv semantics, only the bits stored in that one location denoted by x get copied.
> > It just so happens that in Lisp, the number of locations so copied > > is always 1 while in C it can be greater than 1.
> > A "value", btw., is just those "bits" without the location that stores > > them.
> How do you reconcile this with the preceding two lines ? > Specifically, how does any arbitrarily complex, compound lisp object > get passed by value satisfying both your conditions:
I have explained this already. This is because "arbitrarily complex, compound Lisp objects" are constructed from many individual values, most of them containing _locations_. Locations, in turn, are mapped by what's usually called the "store" to other values.
Example: (LIST 1 2) consists of 5 values, 2 of them numbers, two of them cons cells, one is the atom NIL. Cons cells contain two locations each. The first location in the first cell is mapped to 1, the second is mapped to the second cell, the first location of the second cell is mapped to 2, the second location is mapped to NIL. Any updates to locations in this data structure leave all 5 values alone, they merely change the glue -- the mapping from locations to values.
When you pass such a structure, you really only pass the root value around. All the others get "dragged along" by virtue of the glue.
> a) no more that 1 location is copied, > b) the locaton that stores the object is not part of the value
I see no problem whatsoever with these 2.
> > In contrast, call-by-reference does not transmit the bits. > > Instead, it transmits the location(s)
> Sounds very much like what happens in Lisp: the bits making up the > "hello" and the blark instance are not transmitted.
But these bits are not the ones denoted by X! If you do (setq x '()) you still have the same variable x, and it still denotes the same location as before, but now there is no trace of a relationship between it and your list data structure.
> If you really wanted to carry your argument ad absurdum, then I'm sure > you could argue that pass-by-reference doesn't exist anywhere, because > ultimately, somewhere in the implementation a value representing the > reference is passed.
No, I would not argue that way. But you are right insofar as it is indeed true that call-by-reference tends to get implemented internally by passing addresses around -- which could be expressed in an implementation's intermediate language by making these addresses explicit (and then passing them by value).
> Then again, maybe the real problem is not over the function calling but that > we have lost the war on what identity means. If so, that's very sad.
I don't think its a war that has been lost, but a lack of appreciation of the concept. In C/C++/VB etcetera, you're always thinking in terms of "by value" or "by reference" and dealing with consequences of fussing about with how the parameter is used. I think the complexity of this tends to blind one to the simplicity that call-by-identity offers. I asked you about this very thing some time ago and it took me a while to begin to "get it", mostly because the idea seemed too simple in some way.
> > It's easiest if you think of *everything* as being pass-by-reference.
> It may be "easiest", but it is also completely wrong.
> Notice that "pass-by-value" (which is the only correct answer to the > question) does not imply that the caller cannot change parts of a data > structure. The whole question is *only* about how the formal > parameter of the function (i.e., within the caller) is related to the > actual argument given at the callsite.
> Call-by-reference, otoh, would mean that in
> (defun f (x) (setq x 2)) > (defun g (y) (f y) y) > (g 1)
> the final answer from calling g would have to be 2.
?? No it would not.
Here's the equivilent C code (with types assumed to be integers for simplicity):
#include <iostream.h>
int* f(int *x){return x = new int(2);} int* g(int *y){f(y); return y;}
int main(){ cout << *g(new int(1)) << endl; return 0;
}
This prints "1", just as any Lisp does (CL, elisp, scheme, dylan).
As I said, an appropriate model for thinking about Lisp programs is that all values live on the heap and variables and function arguments contain references to those values.
The only real modification you need to the above for full Lisp compatability is that you need to assume an "operator new" for integers that returns the same object each time it is called with the same argument.
> Replace 2 with (CONS 2 '()) and 1 with (CONS 1 '()), and you see a > result of (1), not (2). So the problem is unrelated to what data you > send to the function.
perhaps one could return to the original terms. where mccarthy defines
primitive equality, he writes:
"eq. The program for eq[e; f] involves testing for the numerical equality of the locations of the words. This works because each atomic symbol has only one association list."[1]
according to which, lisp is a language in which all argument values are locations. that is, lisp is "call-by-location". while this may well be a special case of "call-by-value", that term is not, of itself, adequate to express either that all values are locations, or that a "variable" in lisp does not name a storage location which can contain values, but names a location which contains a binding. it is not significant that some locations may be distinguished, may be immutable, or, as an aspect of a given implementation, may even not be associated with any register in the store. the initial implementation already made such distinctions.[thus the second sentence in the above citation, and 2]
the original description also already explains why, although it is possible to emulate call-by-reference, it is not a first-class feature, but is available only implicitly through operations on closures:
"2. eval[e; a] has two arguments, an expression e to be evaluated, and a list of pairs a. The first item of each pair is an atomic symbol, and the second is the expression for which the symbol stands. 3. If the expression to be evaluated is atomic, eval evaluates whatever is paired with it first on the list a."[3]
in terms of which call-by-reference would entail admissibility of the word which represents a variable binding as an argument value. in other words, there is no intrinsic call-by-reference since there is no language construct which effects a binding to a binding.
as an aside, this terminology even offers the advantage unifying common-lisp with other lisp dialects.
> > > I've also disliked the usage of the term "tagged pointer" to describe > > > the words which describe Lisp objects, for the same reason (pointer > > > implies address, which doesn't exist for an immediate object). ...
> > Not the sort of term you'd expect any other language to adopt. ;) > > I'd accept "by object"...? LispVal is a foreign term to anyone who uses > > the language. It also suggests that it can't be used for any other language, > > when in fact I think it should be usable by other languages.
> Right. As I said in another post, I would be willing to have a better > term suggested than LispVal, one which is more general than pertaining > only to Lisp. However, if you accept "by object", are you ready for all > of the overloading which _that_ term has on it? :-)
Erik Naggum wrote:
> I think we need a fresh start.
> Argument passing in Common Lisp is conceptually equivalent to building > a list of the result of evaluating each of the argument forms to the > function and passing that list to the function, which conceptually > unpacks it into the formal parameters. All knowledge of the source of > the values is lost by that time.
> The conceptual equivalence to a list is used to lay the ground for apply, > &rest, &key, etc, and also neatly captures the order of evaluation so an > explanation of this rule will fall out naturally from the description.
-------------------------- [1] "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I" #1=(http://www-formal.stanford.edu/jmc/recursive.pdf) p.28 [2] #1# p23, p25 [3] #1# p18
"Coby Beck" <cb...@mercury.bc.ca> writes: > > The lisp program is not equivalent to the > > C program. There are these particular differences:
> > 1. The C code allocates a struct on the stack, the Lisp code > > allocates it in main memory. So you'd need to call malloc > > in the C code.
> > 2. C allows you to pass structs in argument lists. The way > > this works is that the struct is `destructured' at the call > > site, and `restructured' at the callee.
> While I am always happy to know about things like this for my own > well-roundedness I can tell you that as a user of a language the above is > not relevant *at all* to understanding what will happen when I write > "foo(bar);" in C and when I write "(foo bar)" in lisp. That kind of stuff > is not for users it is for compiler writers (I have great respect for people > who write compilers, but no desire be one).
Au contraire. As a user of a programming language one should have a very deep understanding of the semantics of that language.
> The fact that such contortions as you went through below in lisp and similar > contortions one would have to do with pointer dereferencing to satisfy > Mathias' objections in C, the fact that these contortions are necessary to > produce equivalent programs is very strong evidence that the languages do > behave differently.
But not as far as call-by-value parameter passing is concerned. The differences are in what kind of values and what kind of variables exist.
> If the text books all agree that C and Lisp are both call-by-value then that > is what they say and it is pointless to dispute. But names are supposed to > disambiguate between concepts,
They do. The concept is the same here, as far as parameter passing is concerned.
> and there are clearly two distinct concepts > here. Too claim that they are the same merely because the have the same > label is foolish.
No, they have the same label because they are conceptually the same.
> No need to write a couple of hundred, but it should be a number greater > than zero if you want to claim that it's not your fault that people don't > know this stuff. People don't know this stuff because they read > Stroustrup's book instead of yours, because his exists and yours doesn't.
I am not in the business of writing C or C++ books. I cannot take the blame for every ommision and mistake of others just because I have not filled in the gap or provided the correction. Or are you going to blame me for world hunger next?
> I didn't say it was a problem. I didn't say it wasn't easy. I just said > it was a substantial amount of work.
But it isn't.
> You could prove me wrong by posting some code that shows how it's done. > If it's as dead-easy as you say it shouldn't take you very long.
Write struct foo * f (struct bar * x) ... where you would have written struct foo f (struct bar x) Then replace occurences of "x." with "x->".
(In C++ you don't even have to do the latter, IIRC.)
This move from struct variables to "pointer to struct" variables must be applied, mutatis mutandis, to other parts of the program as well. But doing so is trivial.
In article <fooffxnx7z....@blume-pcmh.research.bell-labs.com>, Matthias Blume <matth...@shimizu-blume.com> wrote:
> > > C books that explain things correctly exist.
> > Really? Would you be so kind as to cite a few?
> Harbison & Steele.
Harbison & Steele states "C provides only call-by-value parameter passing. This means that the value of the actual parameters are conceptually copied into a storage area local to the called function." <Sec 9.5>. This behavior is different from that of Common Lisp.
-- "What we hear constantly is that after September 11th, everything changed. There is a good rule of thumb: if something is repeated over and over as obvious, the chances are that it is obviously false." -- Chomsky <http://www.zmag.org/content/ForeignPolicy/chomsky_march26.cfm>
Bruce Hoult <br...@hoult.org> writes: > In article <m34rhpiiya....@hanabi.research.bell-labs.com>, > Matthias Blume <matth...@shimizu-blume.com> wrote:
> > > It's easiest if you think of *everything* as being pass-by-reference.
> > It may be "easiest", but it is also completely wrong.
> > Notice that "pass-by-value" (which is the only correct answer to the > > question) does not imply that the caller cannot change parts of a data > > structure. The whole question is *only* about how the formal > > parameter of the function (i.e., within the caller) is related to the > > actual argument given at the callsite.
> > Call-by-reference, otoh, would mean that in
> > (defun f (x) (setq x 2)) > > (defun g (y) (f y) y) > > (g 1)
> > the final answer from calling g would have to be 2.
> ?? No it would not.
> Here's the equivilent C code (with types assumed to be integers for > simplicity):
> #include <iostream.h>
> int* f(int *x){return x = new int(2);} > int* g(int *y){f(y); return y;}
> This prints "1", just as any Lisp does (CL, elisp, scheme, dylan).
FYI, this is C++, not C. Anyway, you see the same effect as in Lisp because your code uses CALL-BY-VALUE, just like Lisp (and C) does!! Try declaring x as &x.
> As I said, an appropriate model for thinking about Lisp programs is that > all values live on the heap and variables and function arguments contain > references to those values.
No, variables are values that hold *pointer*. There is a fine distinction between these two things.