Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Passing arrays, structures and other arguments which can’t simply be put into a single register requires a different method, in which a pointer to the data is passed: ‘call by reference‘.

Note that small structures will be passed in registers. Here's an example: https://godbolt.org/z/rsGEbefcv. a and b are 32 bits and passed packed in x0, and c is a long passed in x1.



It's also wrong to call this "call (or pass) by reference." Pass by reference and pass pointer by value are different things (here's an example — https://godbolt.org/z/Kv7jPPvnz)


A reference is just a pointer but with restrictions enforced by the compiler. ASM-wise, they're totally the same thing.

'Reference' doesn't mean C++'s reference, it means that you pass where the data is, not the data itself. Even Visual Basic had this concept.


Argument-passing semantics (evaluation strategies) are something defined by the source language, not by the calling convention of the target architecture/platform. pdpi is right to point out that what the article is describing is not pass-by-reference semantics.

Unlike C++, C does not support pass-by-reference (ignoring preprocessor silliness). Passing a pointer by value is not the same thing. edit To be clear, C++ supports both pass-by-value and pass-by-reference.

This topic cropped up a year ago: https://news.ycombinator.com/item?id=23553574


this is also a case of the later nomenclature redefining the previous nomenclature in a backwards incompatible way -

Wasn't there, but pretty sure in 70s, the notion of pointer and reference (and 'handle', etc) were pretty much interchangeable, since AFAIK there wasn't any compiler capable of creating a compiler-checked 'reference' construct.

so, if this is true, in the relm of asm, since really we are just dealing with bits in a register that could be interpreted as data or addresses, it makes sense to treat pointer and reference interchangably, since there is no such thing as a higher-order 'reference' anyway.


No, they used to use both "pointer" and "reference" interchangeably to mean an opaque handle that you could only pass around or dereference; for things that supported address arithmetic they used, well, "address". See for example [0] — the paper itself is from 1992, but it extensively quotes the papers from the seventies.

[0] Amir M. Ben-Amram and Zvi Galil. 1992. On pointers versus addresses. J. ACM 39, 3 (July 1992), 617–648. DOI:https://doi.org/10.1145/146637.146666


> are something defined by the source language, not by the calling convention of the target architecture/platform

In that case perhaps the response should have been "pass-by-reference doesn't exist on machine level", not "pass-by-reference is something different", as the latter would seem to be a category error.


> the response should have been "pass-by-reference doesn't exist on machine level"

Which would barely make any sense.


Assuming the machine code has no concept of a function call, isn't it true to say that pass-by-reference doesn't exist at the machine level? Function calls are a high level concept that compile down to machine code.

A typical CPU deals with abstractions like jumps and copies, and has no real concept of a function call. It seems fair to say that, at the level of a typical assembly language/machine language, there is no argument passing, and therefore no evaluation strategy. Same goes for a Turing machine.


This is similar to saying, for instance, that there are no pointers, at the machine level, just integers. (In fact, there are just bits and, maybe, bytes, for that matter.) But it is the usage semantics that matters. (Typically, CPU architectures are designed with it in mind.) An instruction that saves the the next instruction's address somewhere before performing the jump cannot be thought of as simply combining two arbitrary operations into one...


How come? It would illustrate the notion that to a machine, everything is a value, and that (abstract) references get translated into manipulations of values (and not even always in the same way).


Because "on a machine level" and "to a machine" are two different things (the former referring to human understanding).


They're absolutely the same thing to me.


I'm reluctant to bikeshed, but if I read your argument correctly, then technically everything is pass-by-value since even for references the actual reference (a.k.a. pointer) is passed by value.


Pass-by-reference is distinct from passing a pointer by value. In my old comment [0] I gave example code fragments in C# to illustrate the difference. (C# supports both pass-by-value and pass-by-reference. It's like C++ in that regard, although the syntax is different.)

> I'm reluctant to bikeshed

This is the kind of topic where precise phrasing is important, so I wouldn't chalk it up as pedantry. It doesn't help that Java muddied the waters with its use of the word reference.

[0] Here's the link again: https://news.ycombinator.com/item?id=23553574


You've show a syntactic difference, not a functional difference. What does the 'ref' keyword change about how C# passes the argument to the function? I'd imagine (having zero C# experience) that it passes either a pointer, or an index, or an offset, to the function by value. It may also just copy the argument, pass it to the function, and then copy the copy back to the original argument (which would be daft).


> You've show a syntactic difference, not a functional difference.

Kinda, but that difference is important. We can say that C allows us to simulate pass-by-reference by using pointers. It's still true that the C language does not support pass-by-reference semantics.

Taking the address of a variable is an operation that the C language permits us to do, yielding a new value (a pointer value). This isn't part of C's argument-passing functionality, though.

> What does the 'ref' keyword change about how C# passes the argument to the function?

The internals of C# compilers aren't really the point, but I believe .Net does it the copy-intensive way, copying to pass in and copying again to pass the new value back out. I don't think this a real performance problem though, unless you overuse the feature.


Yes exactly. I believe Fortran and Perl only do pass by reference, for example.

It's not a C++ concept, I only used C++ in that example simply because godbolt.org makes it really easy to show how the language treats the two concepts differently even though they compile to the same thing.


The Fortran standard is deliberately silent about the passing method. However, virtually all Fortran compilers pass by reference.


Your example seems too C++-specific. Not all languages are defined in the same way.


I am familiar with a small set of programming languages, but they define reference and value passing similarly.

* Java: Java spec says "pass by value"

* C: pass by value

* C++: pass by value and reference(with ref qualifier)

* C#: pass by value and reference(with ref keyword)

Do you know a language that defines "pass by reference" in a very different way?


In c and assembly the terms reference and pointer are sometimes used interchangeably. An lval is a reference to a value, * is the dereference operator, and so forth. I don't know the spec admittedly but I've seen the terms used interchangeably in compiler code and documentation. I think c++ began distinguishing between and defining references as distinct from pointers, and java removed explicit pointers entirely and generates them and dereferences them automatically for objects.


Not sure if all language specs explicitly use the "pass-by-X" terminology but for example ANSI Smalltalk standard says things like "Each argument [of a message send] is a reference to an object."

> but they define reference and value passing similarly

Well, If all of them have been derived from C++ or designed by people trying to improve on C++, they would be very likely to have the notion defined similarly regardless of how anyone else would use the term, so there's not much surprise there.


They're accepted terms in computer science. They're not specific to any programming language.

https://en.wikipedia.org/wiki/Evaluation_strategy


I was simply saying that C++ using a certain terminology was a sufficient condition for C++-derived languages to use the same terminology, you wouldn't need a CS-wide definition for this and your small set of language wouldn't allow you to make the inference that such a common definition existed.

BTW the page you've linked seems to contradict some of your statements:

> so they are typically described as call by value even though implementations frequently use call by reference internally for the efficiency benefits

As you seem to be arguing that this is not call by reference you should probably correct the page.

EDIT: It also seems that there IS some amount of language specificity anyway, since in another place of the page it says:

> "In particular it is not call by value because mutations of arguments performed by the called routine will be visible to the caller. And it is not call by reference because access is not given to the variables of the caller, but merely to certain objects"

I'm reasonably sure that the first part would be called "call by value" in C++ even if in context of CLU it wasn't if the usual way of doing the same in C++, namely passing a pointer to an object, were to be used.


> As you seem to be arguing that this is not call by reference you should probably correct the page.

I don't really disagree with what the article says there, although I don't like the way it's phrased. The full quote:

> In purely functional languages there is typically no semantic difference between the two strategies (since their data structures are immutable, so there is no possibility for a function to modify any of its arguments), so they are typically described as call by value even though implementations frequently use call by reference internally for the efficiency benefits.

A purely functional language with the property of referential transparency [0] can indeed be treated as using pass-by-value, or pass-by-reference, or even some blend of the two. With referential transparency, nothing hinges on which of the two strategies is used. I'm not sure it's accurate to say that they're typically described as call by value.

> there IS some amount of language specificity anyway

As Wikipedia says, the term call by sharing is not as widespread. I hadn't seen it before. I can't say I really see where they're going with that term:

> In particular it is not call by value because mutations of arguments performed by the called routine will be visible to the caller.

No, they aren't. In Java, you can pass an object reference to the callee function, and the reference will be passed by value. The callee function can modify the members of the referred-to object, in a way that may later be visible to the caller function. So what? That's still pass-by-value. It's the same in C, where the callee can modify a pointed-to variable.

The Wikipedia article also appears to suggest that in Java, all arguments are boxed/unboxed when passed. That isn't true.

I can see some sense in having a term to emphasise that Java sometimes performs boxing, rather than simple pass-by-value. This is to say, I agree that it's a slight oversimplification to say that Java always simply passes by value. If we go too far down this road though we'll need to recategorise C, as it allows implicit conversions between many of its primitive types.

> you should probably correct the page

I don't have the will to get into a Wikipedia edit war, which is how this kind of thing often goes.

[0] https://en.wikipedia.org/wiki/Referential_transparency


In assemblers and C passing by reference and passing by pointer value means the same thing.


You can also pass structs of floating point or SIMD types by register. They have to be 2-4 elements and all of the same type. These are called HFA (Homogeneous Floating-point Aggregate) and HVA (Homogeneous Short-Vector Aggregate).

Source: the Procedure Call Standard for the Arm 64-bit Architecture https://github.com/ARM-software/abi-aa/blob/2021Q1/aapcs64/a...


More importantly, it's just wrong. Large objects are not converted to references, they're passed on the stack.

¹ §5.4 https://developer.arm.com/documentation/ihi0055/b/




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: