3

I am well aware of the fact that in C and C++ everything is passed by value (even if that value is of reference type). I think (but I'm no expert there) the same is true for Java.

So, and that's why I include language-agnostic as a tag, in what language can I pass anything to a function without passing some value?

And if that exists, what does the mechanism look like? I thought hard about that, and I fail to come up with any mechanism that does not involve the passing of a value.

Even if the compiler optimizes in a way that I don't have a pointer/reference as a true variable in memory, it still has to calculate an address as an offset from the stack (frame) pointer - and pass that.

Anybody who could enlighten me?

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
GermanNerd
  • 643
  • 5
  • 12
  • 1
    In C++ compiler can optimize away whole functions or inline them at will. Inlined function will not have any parameters passed, but rather it will be expanded at call place. But in runtime? I don't see any possibility to pass parameter without actually passing anything at all. – Yksisarvinen Dec 07 '18 at 12:38
  • 2
    I don't think there's any language where you can pass something somewhere without passing (a possibly different) something to that somewhere, but it's very hard to prove the absence of things. Of course, with a liberal enough interpretation of "pass", you can just use global variables for everything and then everything is passed everywhere all the time. (I have seen such code. It's not pleasant.) – molbdnilo Dec 07 '18 at 12:43
  • C does not support pass-by-reference, so that tag is wrong. And it's either language-agnostic or you add a language tag at all. As you refere C++ in the text, I left the language tag. Despite your assumption, C++ **does** support pass-by-reference as explained in every textbook. – too honest for this site Dec 07 '18 at 13:39
  • @too honest for Your comment, at least to me, just shows that you that you have not understood my question. And no, C++ does not have a specific, conceptual 'pass by reference' mechanism that is different from what C does. C++ references are just pointers, which get restricted by the compiler in what you can do with them. That does not change the fact that, when calling a function that you pass a C++ reference, receives an address + type information. And that, on the processor level, is nothing but a pointer. – GermanNerd Dec 07 '18 at 13:50
  • I very well understood your question. C++ references are no way the same as pointers (which also exist. The main difference is pointers are first class types. Also the language does not require a specific implementation. If you do some research, you might notice most (if any at all) CPUs don't hav a concept of pointers, but addresses and addressing modes. Finally: do not add irrelevant tags! As I stated before, [tag:language-agnostic] contgradicts a language tag, so please refrain from adding them.. A good C++ book, compliler construction and CPU reference manuals are a good start. – too honest for this site Dec 07 '18 at 14:37
  • @too honest for I don't want to joust with you. I can live with the removal of the C and C+ tags; the previous removal of 'language-agnostic' was plain wrong. Now, you claim the CPU does not have a concept of pointers. Hm. I can see what you mean, but I'm not sure if it is true. We certainly have things like the program counter, stack pointer, stack frame pointer. Are these not pointers? But maybe that is irrelevant; I agree that from a CPU's perspective, the language construct of a pointer (or reference!) is nothing but an address plus size and type information. Can we agree? Cont... – GermanNerd Dec 07 '18 at 15:55
  • ....cont. And going from there, the whole distinction between references and pointers is moot. So I come back to my original question: Is there any way to pass anything to a function that does not involve passing some value? – GermanNerd Dec 07 '18 at 15:56
  • 1
    None of those "pointers" are pointers in the sense of high languages, namely most CPUs (and no modern I'm aware of) don't have a type. This means we don't agree about your assumptions. As I implied, once you learned enough of the basics, you will see what I mean and that your question does not really make sense (which boils down to "how to pass information without passing information?"). I have no idea where you got that information from, but - sorry to tell - it is full of missconceptions. Plus (maybe worst: you mix abstraction levels which is always a bad idea). – too honest for this site Dec 07 '18 at 16:12
  • @too honest for I agree that things like stack pointers don't have a type on the CPU level, but they certainly have a size. 'Type' in the source-code level is nothing but a directive to the compiler, which enables it to issue the correct CPU instructions on that 'type', e.g. integer addition vs. fp-addition. So, the CPU never 'knows' about types, but it distinguishes among them, as evident in the varying ALU instructions. Misconception...learn the basics...well, sit back a moment and think. I've been doing this stuff for more than 30 years, and you come across a bit patronizing. – GermanNerd Dec 07 '18 at 16:20
  • The size of the stack pointer is not related to the size of the object. And no, the CPU does not distinguish between types, it expecially is not aware of operator overloading like most (all?) high-level languages, **including** C. The type is determined by the instruction, i.e. told to the CPU. That#s my last post, You should think about what I said and do the research. – too honest for this site Dec 07 '18 at 16:39
  • @too honest for You are not reading what I wrote. No, the stack pointer does not "know" about the size of objects. But it does "know" (is hard-wired) to "know" about it's own size. Yes, indeed, the type is determined by the instruction, which in turn is issued by the compiler according to source-code level type information. I honestly don't know why we disagree. All high-level abstractions only ever exist in the realm of the source language. But somehow, they get shifted down to the CPU level, incorrectly, with statements that there is no 'passing by reference in C'. – GermanNerd Dec 07 '18 at 16:48
  • @molbdnilo - I read your comment twice this morning. Once before coffee, next time after coffee. Enjoyed it thoroughly both times, although for different reasons the second time through. If I could, I would have up-clicked in in an answer. (Even though the rule-followers among us would likely cancel my up-clicks with many more down-clicks.) – ryyker Dec 07 '18 at 17:19

5 Answers5

5

From C perspective:

There are no references as a language level concept. Objects are referred to by pointing at them with pointers.

The value of a pointer is the address of the pointed object. Pointers are passed by value just like any other arguments. A pointed object is conceptually passed by reference.


At least from C++ perspective:

How is 'pass by reference' implemented [...] ?

Typically, by copying the address of the object.

... without actually passing an address to a function?

If a function invocation is expanded inline, there is no need to copy the address anywhere. Same applies to pointers too, because copies may be elided due to the as-if rule.


in what language can I pass anything to a function without passing some value?

Such language would have to have significantly difference concept of a function than C. There would have to be no stack frame push.

Function-like C pre-processor macros, as their name implies, are similar to functions, but their arguments are not passed around at runtime, because pre-processing happens before compilation.

On the other hand, you can have global variables. If you change the global state of the program, and call a function with no arguments, you have conceptually "passed the new global state to the function" without having passed any value.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Inlining and elision are not answers to my questions. They are more Zen-like, "unasking" a question. Sure, there are mechanisms to not even invoke a function call, even if the source specifies one, but that is hardly a representation of 'passing'. And the abstraction about global variables - do I really need to say anything about that? Again, if- in whichever way - I can avoid the actual calling of a function, all discussion about 'passing' anything to them is non-sensical. – GermanNerd Dec 07 '18 at 16:04
2

At a machine-code level, "pass X by reference" is essentially "pass the address of X by value".

2

Pointers are values. Valuea ars values. Values have a unique identity, require storage.

References are not values. References have no identity. If we have:

int x=0;
int& y=x;
int& z=x;

both y and z are references to x, and they have no independent identity.

In comparison:

int x=0;
int* py=&x;
int* pz=&x;

both py and pz are pointers at x, and they have independent identity. You could modify py and not pz, you can get a size of them, you can memset them.

In some circumstances, at the machine code level, references are implemented the same way as pointers, except certain operations are never performed on them (like reaiming them).

But C++ is not defined in terms of machine code. It is defined innterms of the behaviour of an abstract machine. Compilers compile your code to operations on this abstract machine, which has no fixed calling convention (by the standard), no layout for references, no stack, no heap, etc. It then does arbitrary transformations on this that do not change the as-if behaviour (a common one is single assignment), rearranges things, and then at some point emits assembly/machine code that generates similar behaviour on the actual hardware you are running on.

Now the near universal way to compile C++ is the compilation unit/linker model, where functions are exported as symbols and a fixed ABI calling convention is provided for other compilation units to use them. Then at link stage the compilation units are connected together.

In those ABIs, references are passed as pointers.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

How is 'pass by reference' implemented without actually passing an address to a function?

Within the context of the C languages, the short answers are:

  • In C, it is not.
  • In C++, a type followed by an ampersand (&) is a reference type. For instance, int& is a reference to an int. When passing an argument to a function that takes reference type, the object is truly passed by reference. (More on this in the scholarly link below.)

But in truth, most of the confusion is semantics. Some of the confusion could be helped by:

  • 1) Stop using the word emulated to describe passing an address.
  • 2) Stop using the word reference to describe address

Or

  • 3) Recognize that within the context of the C/C++ languages, in the phrase pass-by-reference, the word reference is defined as: value of address.

Beyond this, there are many examples of illusions and concepts created to convey impossible ideas. The concept of non-emulated pass-by-reference is arguably one of them, no matter how many scholarly papers or practical discussions.

This one (scholarly paper category) is yet another that presents a distinction between emulated and actual pass-by-reference in a discussion using both C & C++, but who's conclusions stick closely to reality. The following is an excerpt:

...Somehow, it is only a matter of how the concept of “passing by reference” is actually realized by a programming language: C implements this by using pointers and passing them by value to functions whereas C++ provides two implementations. From a side, it reuses the same mechanism derived from C (i.e., pointers + pass by value). On the other hand, C++ also provides a native “pass by reference” solution which makes use of the idea of reference types. Thus, even in C++ if you are passing a pointer à la C, you are not truly passing by reference, you are passing a pointer by value (that is, of course, unless you are passing a reference to a pointer! e.g., int*&). Because of this potential ambiguity in the term “pass by reference”, perhaps it’s best to only use it in the context of C++ when you are using a reference type.

But as you, and others have already noted, in the concept of passing anything via an argument, whether value or reference, that something must by definition have a value.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • 1
    The cited part is a bit sloppy. A pointer is not a refeence, but a first-class type. The idea of pass-by-reference is that the reference is transparent to the user, i.e. it does not have a value on it own (any operator will work on the referenced object),. A pointer is a type in its own right, i.e. has its own value, distinct from the object it points to. And: whether information itself has a (physical) substance is more an esotheric question which is not well suited on SO., – too honest for this site Dec 07 '18 at 14:58
  • You and OP. The question does just not make sense; it boils down to asking how to pass information without passing information. Everything else is just red herrings. – too honest for this site Dec 07 '18 at 15:40
  • Just because it has been asked a hundred times does not make it a good question. Remember the `i++ + ++i` questions which pop up once a wekk or more often. The problem with those (and similar) questions is they confuse language and implementation and often just lack the basics to understand the subject. – too honest for this site Dec 07 '18 at 16:06
  • @toohonestforthissite - I am not arguing, in fact I have taken your comments to heart. They make sense. And although not completely removing my answer, I have made significant changes because of your comments. (thanks again). If I might also be honest, part of why I come to this site is to simply enjoy all types of questions. This one in particular is a fun one for me, as not too long ago, I too was confused by all of the creative ways people obfuscated the simple idea of _passing an address_ with phrases like _passing-by-reference_, or _emulated_ passing-by-reference, etc... – ryyker Dec 07 '18 at 16:16
  • ...and regarding your observation: _and often just lack the basics to understand the subject._. Is this not a huge part of why Stackoverflow exists? And what makes a question a _good question_ is honestly a matter of personal perspective, not always captured in a list of rules in a _how to ask_ page. – ryyker Dec 07 '18 at 16:19
  • 1
    "obfuscated the simple idea of passing an address with phrases like passing-by-reference" - Actually apssing by address is just one way to pass a reference. There are other ways like passing the name of the object. This might be done by some high-level languages. And the lookup does not imply it yields an address either, but can retrieve the object from a database. Alternatively, it can be done passing the value and copying back on function return. More ways can be thought of. It just is the most efficient way for most architectures to pass an address under the hood. – too honest for this site Dec 07 '18 at 16:38
  • 1
    @ryyker Love your answer, especially the reference (sic!) to Escher. Yes, the whole issue seems to boil down to abstraction levels. We have human language - "pass by reference", which was crystal clear for 40+ years, and abstracted "pass by reference" in languages that "hijacked" the term "reference". From there we get quickly to things like "emulate".... This whole topic, it appears to me, is more about on what abstraction level we are talking about. – GermanNerd Dec 07 '18 at 16:40
  • @ryyker GEB, by any chance? ;) – GermanNerd Dec 07 '18 at 17:06
  • @ryyker Goedel, Escher, Bach. https://en.wikipedia.org/wiki/G%C3%B6del,_Escher,_Bach – GermanNerd Dec 07 '18 at 17:14
  • 1
    @ryyker: Oh YES. You definitely will. An incredible book. Astounding. Eye-opening. And the best part: You don't have to read it from beginning-to-end. You can cherry-pick along the way. (Not all the way, but most of the way.) Still very, very relevant today. – GermanNerd Dec 07 '18 at 17:28
  • @ryyker: If you're still looking at this, you can see it has been put on hold for "being too broad". I honestly have spent quite some time to figure out how I could edit my question as to not "being too broad", but I fail. Any suggestions? I would very much like to salvage this... – GermanNerd Dec 09 '18 at 14:34
  • @GermanNerd - _"Too broad"_ on this cite often means two things. 1) There is not a specific problem being addressed. 2) The question attracts opinion in the answers. This particular corner of StackExchange tends to be picky that way. Another option is to pick a different StackExchange area in which to post the question. ( _[There is a discussion about that here](https://meta.stackexchange.com/questions/165519/where-should-i-post-questions-about-algorithms-stack-overflow-or-software-engin)_. ) Short of that, I do not know how to make a _language agnostic_ question more specific. – ryyker Dec 10 '18 at 13:07
  • @ryyker Helpful link, thank you. I still think it belongs in SO, since soooo much confusion exists about these terms. I'm by no means immune to that, but I am aware of it. I'll try to reformulate my question, but I have the nagging feeling that it will get shot down nevertheless. Whatever, maybe I'll change my name to Don Quixote. ;) – GermanNerd Dec 10 '18 at 17:49
0

What is meant by pass by value is that the object itself is passed.

In pass by pointer, we pass the value of the pointer to the object.

In pass by reference, we pass a reference (basically a pointer that we know points to an object) in the same way.

So yes, we always pass a value, but the question is what is the value? Not always the object itself. But when we say pass a variable by **, we give the information relative to the object we want to pass, not the value actually passed.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
  • Well, that is my current understanding. But I see all so often things like 'C emulates pass by reference' etc. - what would pass by reference look like without passing a value? – GermanNerd Dec 07 '18 at 12:33
  • It will emulate by passing the value of the reference instead of the object itself. – Matthieu Brucher Dec 07 '18 at 12:33
  • "It emulates..." implies that some other mechanism exits, otherwise 'emulate' is meaningless and misleading. – GermanNerd Dec 07 '18 at 12:35
  • It emulates because it's not part of the C standard, so you reproduce how C++ compilers do that with sugar syntax. And that reproduction is the emulation. – Matthieu Brucher Dec 07 '18 at 12:36
  • @GermanNerd It only means that pass-by-reference does not exist in C, so you use pointers to achieve the same effect. It does not imply that there exists a mechanism that doesn't pass anything. – molbdnilo Dec 07 '18 at 12:38