> Would it be wrong to say that CL is pass-by-reference, with the > exception of numbers and characters, which are pass-by-value?
No, because that is trying to define Lisp calling conventions in terms of other languages. As such, it is full of exceptions and odd twists.
> Hm.. (I'll answer my own question) this is probably better stated as:
> CL is pass-by-reference, but notice that numbers and characters are > immutable objects, and the fact that pass-by-value and > pass-by-reference is indistinguishable for immutable objects.
> Come to think of it, isn't (or number character boolean) the exact > set of immutable values in CL?
Again, although this seems less "exceptional", it still is, because it is borrowing terminology from other languages.
> In proper lisp terms, I agree that "pass by identiy" is the right > wording, but I'm not sure that says very much to those that doesn't > already understand lisp.
I have always liked the phrase "by identity", because it does describe how lisp passes arguments precisely, and since 'identity' and EQ are related, it properly describes the transformation of a variable before it is passed to the argument after it is passed (they are EQ). However, we've seen that even "by identity" has its encumberances when used in a universal sense, so I've always used the phrase "pass by LispVal". What is a LispVal? Glad you asked ...
-- 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: > Lisp is "call by value". Period.
Strong words. But incorrect, as "by value" doesn't properly describe what is going on.
> ("Pass by identity" is not a widely accepted term.
Precisely why Kent uses it.
> I have no idea where Kent got it.) > The story is that some (in fact, many) Lisp _values_ consist of (or > contain) one or more _locations_. Mutation affects the store (which > is a mapping from locations to values implemented via your computer's > memory hardware). This means that larger Lisp data structures such as > lists and trees are really collections of values that are glued > together via the current store. When you change the store (aka > "mutate the data structure"), you change the glue but not the values.
What's in an object matters not. Passing arguments is identical to assignment. What you do with the objects you are assigning or passing over-and-above the actual assignment/passing has nothing to do with assignment/passing.
-- 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)
CALL-BY-REFERENCE An argument passing convention where the address of an argument variable is passed to a function or procedure, as opposed to where the value of the argument expression is passed. Execution of the function or procedure may have side-effects on the actual argument as seen by the caller.
FORTRAN passes arguments by reference.
Here is an example in C++.
void yuck (int& arg) { arg = 69; }
void foo () { int x = 42; int y = x; yuck (x); // X is now 69, Y is still 42. }
Common Lisp does not work this way.
A quick google shows that the definition above seems to be prevalent.
> CL is pass-by-reference, but notice that numbers and characters are > immutable objects, and the fact that pass-by-value and > pass-by-reference is indistinguishable for immutable objects.
Numbers and characters are immutable in C++ as well. call-by-reference refers to the mutability of the binding in the caller.
> Is there any system that isn't pass-by-value under your definition?
The commonly known argument passing conventions are call-by-value, call-by-name, call-by-need, call-by-reference, and call-by-value-return.
In call-by-value, an argument is evaluated *before* it is passed to the caller. Suppose function foo were defined as follows:
In a call-by-value language, I would get an error if I wrote
(foo 0 (/ 1 0))
In a call-by-name language, however, the variable Y in foo would not be bound to the value of (/ 1 0), but to the expression `(/ 1 0)'. Since this expression is not used, the division doesn't happen.
Call-by-need is similar, but there is an efficiency hack. If Y *were* to be evaluated, the value is cached for future reference.
Call-by-value-return is a kludge for simulating call-by-reference where creating a reference is problematic (like across the network). The call is made as a call-by-value call and multiple values are collected upon return. Then the variables passed in are re-assigned to the appropriate return values.
> Strong words. But incorrect, as "by value" doesn't properly describe > what is going on.
It does describe *precisely* what's going on, so it is correct.
> > ("Pass by identity" is not a widely accepted term.
> Precisely why Kent uses it.
I know that Kent has a knack for making it sound as if Lisp is something oh-so-special when comparing it to other languages. But at least as far as argument passing is concerned, it is not.
> > I have no idea where Kent got it.)
> > The story is that some (in fact, many) Lisp _values_ consist of (or > > contain) one or more _locations_. Mutation affects the store (which > > is a mapping from locations to values implemented via your computer's > > memory hardware). This means that larger Lisp data structures such as > > lists and trees are really collections of values that are glued > > together via the current store. When you change the store (aka > > "mutate the data structure"), you change the glue but not the values.
> What's in an object matters not. Passing arguments is identical to > assignment.
Only in call-by-value argument passing.
> What you do with the objects you are assigning or passing > over-and-above the actual assignment/passing has nothing to do with > assignment/passing.
Right. I was just explaining why there is such a thing as "mutating the data structure that was passed as an argument in such a way that the caller can observe the mutation" despite having call-by-value semantics. This, indeed, has nothing to do with the argument passing itself but with the nature of the data structure.
Duane Rettig <du...@franz.com> writes: > No, because that is trying to define Lisp calling conventions in > terms of other languages. As such, it is full of exceptions and > odd twists.
it is strange that a language as old as lisp is still unable to name a calling convention that is as widely used, for whatever its twists and turns may be. has it changed much over the years and during the commonization?
oz -- you take a banana, you get a lunar landscape. -- j. van wijk
> > > Lisp is "call by value". Period. ("Pass by identity" is not a > > > widely accepted term. I have no idea where Kent got it.)
> > Maybe "pass by eqness" is what it is.
> (Actually, it's passed by "eqlness", not "eqness". Function calls do > not necessarily preserve "eqness". That's how EQL originated in the > first place--numbers and characters are sometimes passed as arguments > in different registers not known to the GC, and in so doing, their > identity under EQ can be lost, but not under EQL.)
Hmm, this is news to me. I assume that this occurs on a Lisp Machine? I've never seen such a thing on GP hardware.
> In response to Matthias Blume, though:
> I made up "pass by identity". Incidentally, that's how all the other > "pass by" terms were gotten originally; someone made them up. Why did > someone make them up? Because a term was needed. What made a term > needed? Because the absence of a term creating an ongoing problem.
I agree completely. And I've always liked and accepted your use of "pass by identity", although it does seem that even "identity" is somewhat encumbered. It becomes especially problematic to me if there are actually implementations out there which munge the bits in the tagged word as they are passed, since to me 'identity' implies EQ.
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".
[I did not invent the term LispVal, either; and I don't know who did. I first saw it in the C sources for FranzLisp on the Berkeley Software Distribution; it was a C typedef which was used to describe the union of all of the possible lisp types, Maclisp style.]
-- 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: > Kent M Pitman <pit...@world.std.com> writes:
> > I made up "pass by identity". Incidentally, that's how all the other > > "pass by" terms were gotten originally; someone made them up. Why did > > someone make them up? Because a term was needed. What made a term > > needed? Because the absence of a term creating an ongoing problem.
> Sorry to put it bluntly, but this is nonsense. Lisp is one of the > canonical examples of a call-by-value language. The whole family of > "call-by-xxx" talks about the relationship between the expression that > is used to denote an actual argument and the kind of access function > being called gets:
> call-by-value: formal parameter is local to the callee, it holds > the value resulting from evaluating the actual argument; > beyond that, callee has no access to the actual argument
The problem with this definition, as it applies to Lisp, is that it does not distinguish what is happening. Passing an argument in CL is just like binding a LET variable. You get the same lexical distinction as in a function call, and so in fact passing values around is nothing new; it doesn't actually describe what is occurring. In C, pass-by-value implies that a copy is made of the value passed, and thus the value at the caller's side is protected from mutation (as opposed to Fortran, were its call-by-reference passing allows a subroutine to modify variables and sometimes even constants in the caller). In lisp, these immediates happen to be protected as well, but not by virtue of the value-copying that occurs in the passing, but by virtue of the immutability of the object, which is entirely the same in assignment and binding as in argument passing. In effect, _all_ of Lisp is "by value", not just its argument passing. So in effect, you are trying to describe Lisp's argument passing by using terminology that is meaningless in Lisp, because it is how all of Lisp operates.
-- 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)
> > The identical term is used in > > languages that employ typed variables instead of typed objects, where > > if you pass a vector of ten elements, you actually copy all ten > > elements from caller-store to callee-store in order to accomplish this > > pass (losing identity in the process).
> That, in fact, is not what's usually called "call-by-value".
When arguing about the correct name for something there are only two (often unresolvable) approaches: argument by authority and argument by consensus. You aren't appealing to consensus but you have not provided any citations to support what you say, so it can not yet be convincing.
For myself, I am only recalling what I was taught when I took C and C++ and that was that C was call-by-value (including the pointers) and C++ provided a "new and cool" pass-by-reference mechanism. If you passed a struct in C as opposed to a reference to struct, your callee received a copy and could not affect the caller's struct. (Given a pointer, you could, by mechanisms of indirection get at the memory contents.) That has been consistent with what I recall reading and hearing about it since then and is consistent with the FAQ's from the C/C++ world on the subject. (This is not supposed to be an authoritative argument, just one opinion that counters your own with some anecdotal support for a consensus argument).
> If you > make a copy of something that can be distinguished from the original, > you have a *new* value. Call-by-value means that the callee gets the > *same* value (but nothing beyond that -- in particular not the > location that this value might have been stored at and not the > expression that was used to calculate it).
> > That is _not_ what Lisp does > > and it's not helpful to use the same term for an unrelated process.
> I agree that this is not helpful. But the blame here clearly lies > with the improper use of the term "call-by-value" in the "deep copy" > scenario that you describe.
> By the way, could you name an example of a language that does the > above?
IIRC, in C++ if you have a class with an array data member (indeed anything that needs some smarts in terms of copying) the programmer must provide a copy constructor method so that when an instance of that class is passed by value the compiler will know how to allocate memory and transfer the contents. Also, IIRC, that is required before you can even use the assignment operation.
In my C++ texts it always used pass-by-value and pass-by-reference in the same way Kent and others here seem to be using them.
> > The world finally more or less understands what object identity is. I > > think appealing to that notion clarifies things enormously, and I plan > > to just keep using the clear term until it gets currency.
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.
> > > I made up "pass by identity". Incidentally, that's how all the other > > > "pass by" terms were gotten originally; someone made them up. Why did > > > someone make them up? Because a term was needed. What made a term > > > needed? Because the absence of a term creating an ongoing problem.
> > Sorry to put it bluntly, but this is nonsense. Lisp is one of the > > canonical examples of a call-by-value language. The whole family of > > "call-by-xxx" talks about the relationship between the expression that > > is used to denote an actual argument and the kind of access function > > being called gets:
> > call-by-value: formal parameter is local to the callee, it holds > > the value resulting from evaluating the actual argument; > > beyond that, callee has no access to the actual argument
> The problem with this definition, as it applies to Lisp, is that it > does not distinguish what is happening. Passing an argument in CL is > just like binding a LET variable. You get the same lexical distinction > as in a function call, and so in fact passing values around is nothing > new; it doesn't actually describe what is occurring.
Just because a description is not new does not mean that it does not describe what's happening. It could simply mean that what's happening is not new.
> In C, pass-by-value implies that a copy is made of the value passed,
Nonsense!! In C, as in Lisp, no copy is made. A fresh variable is being initialized with the *same* value that is being passed, just like in Lisp. What makes it "call-by-value" in both cases (C and Lisp) is that an assignment to the formal parameter does not result in an update of the (l)value that was used as the actual argument.
> and thus the value at > the caller's side is protected from mutation (as opposed to Fortran, were > its call-by-reference passing allows a subroutine to modify variables and > sometimes even constants in the caller). In lisp, these immediates happen > to be protected as well, but not by virtue of the value-copying that > occurs in the passing, but by virtue of the immutability of the object,
Wrong. It has nothing to do with immutability of the object. Again, call-by-value is not about whether you can do something to the data structure represented by a given value but whether you can do something to the thing denoted by the expression that was the actual argument to the function call.
In particular, call-by-reference distinguishes itself from call-by-value in that the callee can modify the location denoted by the (l)value (i.e., the _location_) denoted by the actual argument. But that's not the only location that a callee might want to modify, and if values _contain_ locations (as it is the case in Lisp as well as all languages that have the concept of a pointer), then the callee can perform a mutation that is observable by the caller.
> which is entirely the same in assignment and binding as in argument > passing. In effect, _all_ of Lisp is "by value", not just its argument > passing. So in effect, you are trying to describe Lisp's argument passing > by using terminology that is meaningless in Lisp, because it is how all > of Lisp operates.
Indeed, one might say that all of Lisp is "by value". This does not make it meaningless to discuss, and that is *precisely* because we comparing the way Lisp works with the way *other* languages work. (Remember that the original poster asked how to do something in Lisp that he could do oh-so-easily in C++. That's what started the whole discussion.)
* Frode Vatvedt Fjeld <fro...@acm.org> | 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. Passing pointers is not the same as pass-by-reference. "Pass by reference" means that a reference to the storage of the value is passed, but the value in Common Lisp is a pointer or a number/character. Common Lisp does _not_ pass a pointer to the pointer-or-number/character. -- 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.
* Frode Vatvedt Fjeld <fro...@acm.org> | Aren't you just redefining the meaning of pass-by-value here? Is there | any system that isn't pass-by-value under your definition?
Look, this is getting annoying. The reference that is intended in the term pass-by-reference is not the value of the variable (storage cell), it is the variable (storage cell) itself. This has been the established meaning of these terms basically forever. You are seriously confused if you think pointers as such constitute references.
There are three very, very common ways to pass arguments to functions:
1 Pass by value: The value of the variable (storage cell) is extracted by the caller and passed to the callee. This also means that all arguments to a function are just values and a function call can just evaluate all arguments in order and pass the values to the callee. This is precisely what Common Lisp specifies.
2 Pass by reference: The variable (storage cell) is passed to the callee, which can read or write to it. This means that you cannot call a function with the value of another function call without storing it in a variable. Fortran has _traditionally_ been pass-by-reference. Ada has out parameters. C++ has references (coincidence? not!).
3 Pass by name: The expression itself is passed to the callee, which will re-evaluate it with the values of subexpressions captured in the call. (They actually pass closures much like I and Joe and Pierre offered with the setter/reference macro.) This is what Algol and Simula can do.
This is (or should have been) CS 101 material. Please just learn it and avoid confusing others who might have no education at all and are likely to listen to bogosities. Having to clean up after such confusions is both annoying and wasteful when you could have avoided the "information pollution" in the first place. -- 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.
Matthias Blume <matth...@shimizu-blume.com> writes: >> I don't think this is going to clear things up for anyone. Isn't a >> collection of values a value in its own right?
> No. Not in Lisp [*] (at least for most types).
This seems very peculiar to me. What exactly do you consider to be mere collections of values, rather than proper values?
> > Strong words. But incorrect, as "by value" doesn't properly describe > > what is going on.
> It does describe *precisely* what's going on, so it is correct.
You also say "C is also strictly call-by-value." Which indicates you believe there is no difference between C and Lisp argument passing. This is demonstrably not true.
The following C program produces the output below it: ............................................ #include <stdio.h>
struct thing {int x; int y;};
void foo(struct thing arg) {arg.x = 1;}
int main(int argc, char* argv[]) { struct thing bar; bar.x = 0; bar.y = 0; printf("\nbar: x = %d y = %d", bar.x, bar.y); printf("\ncalling foo..."); foo(bar); printf("\nbar: x = %d y = %d", bar.x, bar.y); return 0;
}
.............................output bar: x = 0 y = 0 calling foo... bar: x = 0 y = 0
The lisp version does this:
CL-USER 10 > (defstruct thing x y) THING CL-USER 11 > (defun foo (arg) (setf (thing-x arg) 1)) FOO CL-USER 12 > (defun main () (let ((bar (make-thing :x 0 :y 0))) (format t "~&bar: x = ~A y = ~A" (thing-x bar) (thing-y bar)) (print "calling foo...") (foo bar) (format t "~&bar: x = ~A y = ~A" (thing-x bar) (thing-y bar)))) MAIN CL-USER 13 > (main) bar: x = 0 y = 0 "calling foo..." bar: x = 1 y = 0 NIL
> > > ("Pass by identity" is not a widely accepted term.
> > Precisely why Kent uses it.
> I know that Kent has a knack for making it sound as if Lisp is > something oh-so-special when comparing it to other languages. But at > least as far as argument passing is concerned, it is not.
I detect a bit of a chip on your shoulder. Not a useful thing in a technical discussion.
Anyway, there is clearly something missing in your definitions or in the way you are applying the labels.
> This is (or should have been) CS 101 material. Please just learn it and > avoid confusing others who might have no education at all and are likely > to listen to bogosities. Having to clean up after such confusions is > both annoying and wasteful when you could have avoided the "information > pollution" in the first place.
Actually I was blaming it on CS 101 for not debunking two popular misconceptions thoroughly:
- pass-by-value can have no side-effects - (eq pass-by-reference (pass-by-value pointer))
Come to think of it, they were the ones that told me those in the first place. I remember arguing with the prof. over something he had told the class that was just plain wrong, and he replied that the concepts being introduced were bad enough without burying first year students with details not germane to the day's subject.
> >> I don't think this is going to clear things up for anyone. Isn't a > >> collection of values a value in its own right?
> > No. Not in Lisp [*] (at least for most types).
> This seems very peculiar to me. What exactly do you consider to be > mere collections of values, rather than proper values?
In Lisp, a CONS cell is a value. But the contents of the CAR of the cell is not part of that value, it is merely referenced by it. If you do a RPLACA on the original cell, you do not get a different cell -- so is is still the same value. To take account of this in a semantic model, a CONS cell is represented as consisting of a pair of _locations_ (and probably a type tag of some sort), one location holding the CAR and one holding the CDR. Doing a RPLACA, you still have the same locations, they simply hold other values (or, to put it more formally, the external mapping called "store" that associates each location with a value will have been changed).
So your question above asks the wrong thing. We are not talking about "mere collections of values", we are talking about collections of locations. In some languages, where certain composite types such as CONS are always immutable, one can do away with the step of mapping locations to values via the store and consider the CAR of a CONS part of the CONS. On the implementation side you probably still allocate physical memory for such a CONS (at least in most cases), but you do not have to mention that in the formal semantic model. In a semantic model for Lisp you do have to mention locations in some way or the other because you need to be able to model mutation.
To go back to you question. Suppose you give me ("a collection of") two values x and y. Now I construct (CONS x y). You will certainly agree with me that the result of this expression is more than "just the two values". In fact, I can prove this to you by calling (CONS x y) again -- which results in something that is observably different from the first result. Thus, the two values in a CONS are not "just a collection of two values". Instead, the result of CONS is a collection of two locations, which initially happen to hold the two values you gave me. If you do a RPLACA or RPLACD on the result of CONS, you still have the same cons cell (i.e., you did NOT change this value).
Erik Naggum <e...@naggum.net> writes: > Passing pointers is not the same as pass-by-reference. "Pass by > reference" means that a reference to the storage of the value is > passed, but the value in Common Lisp is a pointer or a > number/character.
Ok, I was making a false assumption about the meaning of "pass-by-reference", or actually "call-by-reference". I agree lisp is call-by-value.
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.
Or, using Duane Rettig's word:
Common Lisp is call-by-value. Every value is a LispVal, which is a tagged word, which is ...
The "every value is a pointer" bit seems to be crucial piece of information, otherwise people apparently expect the callee to receive a copy of for example a cons cell. This is what C does, because there every value is _not_ a pointer.
In article <3229347076995...@naggum.net>, Erik Naggum <e...@naggum.net> wrote: > 1 Pass by value: The value of the variable (storage cell) is extracted by > the caller and passed to the callee. This also means that all arguments > to a function are just values and a function call can just evaluate all > arguments in order and pass the values to the callee. This is precisely > what Common Lisp specifies.
I have this strange sense of deja-vu. Luckily there is Google:
I think it's worth pointing out that even though Lisp and C++ are both call-by-value the actual behavior you get from Lisp's calling convention more resembles (but is not identical to) what you get from call-by-reference in C++. For example, consider:
class C { public: int x;
};
void f(C c) { c.x++; } // c is passed "by value" -- sort of
main() { C c; c.x=0; f(c); cout << c.x;
}
and the Common Lisp equivalent:
(defclass C () (x))
(defun f (c) (incf (slot-value c 'x)))
(defun main () (let ( (c (make-instance 'C)) ) (setf (slot-value c 'x) 0) (f c) (print (slot-value c 'x))))
The output of the C++ version is '0' while the Lisp version output is '1'. (On the other hand, if you changed f in the C++ version to be f(C &c) then it too would output '1'.) The difference arises because:
> Common Lisp offers object identity as one of its basic features as well > as the ability to store any kind of object in a Lisp "storage cell" > location, meaning a variable, structure or class slot, array cell, the > car and cdr of a cons, etc, etc. This naturally means that Lisp must > pass around some kind of references to objects, as no other mechanism can > store any kind of value in equal amounts of space.
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. There really is nothing in C++ that mimics the true semantics of Lisp's calling convention. It's a substantial amount of work to reproduce all aspects of Lisp's argument passing semantics in C++.
> > > ("Pass by identity" is not a widely accepted term.
> > Precisely why Kent uses it.
> I know that Kent has a knack for making it sound as if Lisp is > something oh-so-special when comparing it to other languages. But at > least as far as argument passing is concerned, it is not.
But Lisp _is_ something oh-so-special! :-)
> > > I have no idea where Kent got it.)
> > > The story is that some (in fact, many) Lisp _values_ consist of (or > > > contain) one or more _locations_. Mutation affects the store (which > > > is a mapping from locations to values implemented via your computer's > > > memory hardware). This means that larger Lisp data structures such as > > > lists and trees are really collections of values that are glued > > > together via the current store. When you change the store (aka > > > "mutate the data structure"), you change the glue but not the values.
> > What's in an object matters not. Passing arguments is identical to > > assignment.
> Only in call-by-value argument passing.
This is not true is C. Define a small struct. Pass it through a function call, and assign it to a variable in an assignment statement. Now, do the new variable and the formal parameter contain the same bits? Not necessarily, because the struct may have been passed by-value, i.e. actually copied to the stack, as opposed to being passed as a "value-by-reference", i.e., a pointer to it copied to the stack and received by the callee.
The problem here, I think, is in the dual meaning of the term "value". There seem to be two prevalent meanings to the term "by-value"; one means "passed after evaluation", and one means "copied". Both are attempts to meet the real goal of a procedure not affecting the variables owned by its caller (even so, C does not meet this goal). This dual meaning is why I object to the term "by-value" to describe Lisp calling style.
Lisp objects are what are passed, and the values of variables tend not to be owned specifically by functions, but are owned as a whole by the process (I suspect that's mostly true of all gc'd languages).
-- 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)
> > 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?
> 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.
See my previous answer to you on this thread.
-- 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)
> > > Strong words. But incorrect, as "by value" doesn't properly describe > > > what is going on.
> > It does describe *precisely* what's going on, so it is correct.
> You also say "C is also strictly call-by-value." Which indicates you > believe there is no difference between C and Lisp argument passing. This is > demonstrably not true.
> The following C program produces the output below it: > ............................................ > #include <stdio.h>
> struct thing {int x; int y;};
> void foo(struct thing arg) > {arg.x = 1;}
> int main(int argc, char* argv[]) > { > struct thing bar; > bar.x = 0; > bar.y = 0; > printf("\nbar: x = %d y = %d", bar.x, bar.y); > printf("\ncalling foo..."); > foo(bar); > printf("\nbar: x = %d y = %d", bar.x, bar.y); > return 0; > } > .............................output > bar: x = 0 y = 0 > calling foo... > bar: x = 0 y = 0
> The lisp version does this:
> CL-USER 10 > (defstruct thing x y) > THING > CL-USER 11 > (defun foo (arg) > (setf (thing-x arg) 1)) > FOO > CL-USER 12 > (defun main () > (let ((bar (make-thing :x 0 :y 0))) > (format t "~&bar: x = ~A y = ~A" > (thing-x bar) (thing-y bar)) > (print "calling foo...") > (foo bar) > (format t "~&bar: x = ~A y = ~A" > (thing-x bar) (thing-y bar)))) > MAIN > CL-USER 13 > (main) > bar: x = 0 y = 0 > "calling foo..." > bar: x = 1 y = 0 > NIL
You are confused. The proper C equivalent of passing a CL struct to a function is to pass a pointer to a C struct. A plain struct variable in C is is an lvalue -- something for which there is no direct equivalent in Lisp.
> Anyway, there is clearly something missing in your definitions or in the way > you are applying the labels.
If you do not like to take my word, go and look at the literature on PL semantics.
I've found this article, Data Representation in Guile, to be somewhat instructive, even though it is dealing with scheme.
It starts off
Because variables, pairs, and vectors may hold values of any type, Scheme implementations use a uniform representation for values -- a single type large enough to hold either a complete value or a pointer to a complete value, along with the necessary typing information.
The following sections will present a simple typing system, and then make some refinements to correct its major weaknesses. However, this is not a description of the system Guile actually uses. It is only an illustration of the issues Guile's system must address. ...
> The following C program produces the output below it: > ............................................ > #include <stdio.h>
> struct thing {int x; int y;};
> void foo(struct thing arg) > {arg.x = 1;}
> int main(int argc, char* argv[]) > { > struct thing bar; > bar.x = 0; > bar.y = 0; > printf("\nbar: x = %d y = %d", bar.x, bar.y); > printf("\ncalling foo..."); > foo(bar); > printf("\nbar: x = %d y = %d", bar.x, bar.y); > return 0; > } > .............................output > bar: x = 0 y = 0 > calling foo... > bar: x = 0 y = 0
> The lisp version does this:
> CL-USER 10 > (defstruct thing x y) > THING > CL-USER 11 > (defun foo (arg) > (setf (thing-x arg) 1)) > FOO > CL-USER 12 > (defun main () > (let ((bar (make-thing :x 0 :y 0))) > (format t "~&bar: x = ~A y = ~A" > (thing-x bar) (thing-y bar)) > (print "calling foo...") > (foo bar) > (format t "~&bar: x = ~A y = ~A" > (thing-x bar) (thing-y bar)))) > MAIN > CL-USER 13 > (main) > bar: x = 0 y = 0 > "calling foo..." > bar: x = 1 y = 0 > NIL
This is disingenuous. 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.
Lisp provides this for lists via APPLY and &REST args.
(defstruct (thing (:type list)) x y)
(defun foo (&rest bar) (setf (thing-x bar) 1))
(defun main () (let ((bar (make-thing :x 0 :y 0))) (format t "~&bar: x = ~a y = ~a" (thing-x bar) (thing-y bar)) (print "calling foo...") (apply #'foo bar) (format t "~&bar: x = ~a y = ~a" (thing-x bar) (thing-y bar))))
> > > 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.