>On the contrary, I think inventing a new class of of "call-by-X" function arguments makes it harder to explain Python to newcomers.
Then I think you may have forgotten what it's like to move to a call-by-sharing language for the first time.
>Passing a C struct to a function does _not_ copy all the fields of the struct. It passes a reference (pointer) to the function, which the function then uses to access the fields (or properties if you will) in the struct directly at their original location in memory.
Wow ok.. I'm going to try to be polite. I don't think _you_ tried it as you suggest I do:
first shot:
~ gcc -o foo -ggdb foo.c
foo.c: In function ‘main’:
foo.c:31: error: ‘flippedPoint’ undeclared (first use in this function)
foo.c:31: error: (Each undeclared identifier is reported only once
foo.c:31: error: for each function it appears in.)
Typo fixed: s/flippedPoint/secondPoint
what's the output?
"{1, 2}{-1, -2}"
EDIT: Yours is actually an interesting example, and you're right, i responded to quick from the typo fix and didn't actually grok it.
But, actually we're both wrong... and right? The real answer turns out to be a bit more complicated. In your example the copies are made (automatically) in the caller (main) which actually passes a pointer to flipPoint. Try disassembling your executable. You'll see what I mean.
[Double posting because I was out of my edit window by the time I saw your edit]
>But, actually we're both wrong... and right? The real answer turns out to be a bit more complicated. In your example the copies are made (automatically) in the caller (main) which actually passes a pointer to flipPoint. Try disassembling your executable. You'll see what I mean.
I'm really not sure that what the assembly code does is relevant. First off, once it's in assembly, the concepts of "caller" and "function" are gone completely. There are structures that correspond to what compilers typically emit when you define and call functions, but there is no "copy in the caller and pass a pointer to the function". There's just "copy this data on the stack, put the location into a register, and then jump to this location".
Furthermore, this is looking at implementation details, and what we're concerned here with are the abstract concepts of how these languages work. If you look at the assembly, you're seeing how your compiler decided to handle it. If you have optimization on, flipPoint is going to be inlined anyway. The spec doesn't really care how the compiler achieves the result as long as it does achieve the correct result. One compiler might have it copy before jumping and pass a pointer, but another compiler could just as easily pass a pointer before jumping and then have the copy made after the jump. You would not know the difference.
But the way C acts is as if the fields of the struct were being copied when they were passed to the function.
Yeah, I renamed something and then had to do an edit, but I guess you saw the original broken version. Sorry.
The output of {-1, -2} is because it returned the other point by value. The first point is unmodified, which is why it prints out {1, 2}. If the value was being passed as a reference, the output would be {-1, -2}{-1, -2}.
Edit: "If the value was being passed as a reference" is sort of a weird thing to say. What I meant, of course, was "if the struct was being passed as a reference".
Comments
>On the contrary, I think inventing a new class of of "call-by-X" function arguments makes it harder to explain Python to newcomers.
Then I think you may have forgotten what it's like to move to a call-by-sharing language for the first time.
>Passing a C struct to a function does _not_ copy all the fields of the struct. It passes a reference (pointer) to the function, which the function then uses to access the fields (or properties if you will) in the struct directly at their original location in memory.
I'm sorry, but everything you said there is wrong. Try it out for yourself: https://gist.github.com/4073329
Wow ok.. I'm going to try to be polite. I don't think _you_ tried it as you suggest I do:
first shot: ~ gcc -o foo -ggdb foo.c foo.c: In function ‘main’: foo.c:31: error: ‘flippedPoint’ undeclared (first use in this function) foo.c:31: error: (Each undeclared identifier is reported only once foo.c:31: error: for each function it appears in.)
Typo fixed: s/flippedPoint/secondPoint
what's the output?
EDIT: Yours is actually an interesting example, and you're right, i responded to quick from the typo fix and didn't actually grok it.But, actually we're both wrong... and right? The real answer turns out to be a bit more complicated. In your example the copies are made (automatically) in the caller (main) which actually passes a pointer to flipPoint. Try disassembling your executable. You'll see what I mean.
[Double posting because I was out of my edit window by the time I saw your edit]
>But, actually we're both wrong... and right? The real answer turns out to be a bit more complicated. In your example the copies are made (automatically) in the caller (main) which actually passes a pointer to flipPoint. Try disassembling your executable. You'll see what I mean.
I'm really not sure that what the assembly code does is relevant. First off, once it's in assembly, the concepts of "caller" and "function" are gone completely. There are structures that correspond to what compilers typically emit when you define and call functions, but there is no "copy in the caller and pass a pointer to the function". There's just "copy this data on the stack, put the location into a register, and then jump to this location".
Furthermore, this is looking at implementation details, and what we're concerned here with are the abstract concepts of how these languages work. If you look at the assembly, you're seeing how your compiler decided to handle it. If you have optimization on, flipPoint is going to be inlined anyway. The spec doesn't really care how the compiler achieves the result as long as it does achieve the correct result. One compiler might have it copy before jumping and pass a pointer, but another compiler could just as easily pass a pointer before jumping and then have the copy made after the jump. You would not know the difference.
But the way C acts is as if the fields of the struct were being copied when they were passed to the function.
Yeah, I renamed something and then had to do an edit, but I guess you saw the original broken version. Sorry.
The output of {-1, -2} is because it returned the other point by value. The first point is unmodified, which is why it prints out {1, 2}. If the value was being passed as a reference, the output would be {-1, -2}{-1, -2}.
Edit: "If the value was being passed as a reference" is sort of a weird thing to say. What I meant, of course, was "if the struct was being passed as a reference".