Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What a reference actually is

117 views
Skip to first unread message

Juha Nieminen

unread,
Nov 17, 2022, 4:01:30 AM11/17/22
to
I have noticed that a lot of C++ programmers have an... well, perhaps the
word "incorrect" is too strong, but at least slightly incorrect concept
of what a "reference" in C++ is. Not in terms of how the compiler
implements it internally, but at the language level. Thus, they tend to
explain it to beginners in a way that might not be the best. (They tend to
go too much into the internal implementation details that the compiler uses,
even if they do this inadvertently, instead of talking at the *language*
level, about the semantics.)

What I mean with this is that many (perhaps most?) C++ programmers seem to
think of C++ references, for all intents and purposes, as "an alternative
syntax for pointers". A more limited version of a pointer. Perhaps "a safer
alternative syntax for a pointer."

While a reference might in practice be internally implemented by the
compiler pretty much as if it were a pointer, it shouldn't really be
thought as such at the language level.

A reference should be thought of as an "alias" for the original variable
it's referencing. In almost all situations the reference behaves in the
exact same way as the original object it's referencing. Whatever you do
to the reference is in practice as if you were doing it directly to the
original object. In fact, the syntax for doing things to the original
object via the reference is in almost all cases identical to the syntax
if you were using the original object directly.

The reason why a reference is not a pointer is because of that. For example,
you can not use the 'variable[integer]' syntax on a reference if the original
object does not support that syntax (and, conversely, you *can* use that
syntax if the original object supports it). This shouldn't be thought of as
"it's because this is a more limited alternative syntax for pointers", but
as "it's because this is an 'alias' for the original object, and behaves the
same as that original object does". It's as if you were using the original
object directly, and thus all the same syntax support applies.

This form of thinking also explains why you can't change a reference to
later refer to a different object. It would be like you were trying to
make the original object somehow become the other object. Not a *copy*
of the other object, but literally the other object. From a semantical
perspective that makes no sense. It just doesn't compute.

(One could argue that there should be a way to make a reference change
what it's an "alias" of, but this is how it was originally designed, so
this is how it works.)

The advantage of using such an 'alias' reference is that the 'alias' is
not a *copy* of the original object. It's just an alias of the original
object (which still resides where it originally was created). Thus the
reference is usually much more lightweight than taking the original
object by copy.

While that makes it *similar* to a pointer (and it may internally be
implemented as such), it shouldn't really be thought of as one.

Michael S

unread,
Nov 17, 2022, 9:09:22 AM11/17/22
to
For language that is so similar (nearly identical) to C at the level of
"virtual machine", as is C++, the concept of reference is just unnecessary.
Don't use references in your code except when forced by interfaces that
are out of your control! Then people that are going to read and comprehend
your code will be thankful.

Bonita Montero

unread,
Nov 17, 2022, 1:27:48 PM11/17/22
to
References are so simple that I don't understand why to write
such a long text about them.

Paavo Helde

unread,
Nov 17, 2022, 5:37:12 PM11/17/22
to
17.11.2022 16:09 Michael S kirjutas:
>
> For language that is so similar (nearly identical) to C at the level of
> "virtual machine", as is C++, the concept of reference is just unnecessary.
> Don't use references in your code except when forced by interfaces that
> are out of your control! Then people that are going to read and comprehend
> your code will be thankful.

Aren't most languages similar to C at the level of virtual machine? And
isn't it so that a major point of having higher level languages is to
provide better abstractions than the virtual machine?

With C++, my advise is to not use raw pointers in your code except when
forced by interfaces that are out of your control. Prefer references
instead, especially const lvalue and non-const rvalue references.

JiiPee

unread,
Nov 18, 2022, 12:49:54 AM11/18/22
to
On 18/11/2022 00:36, Paavo Helde wrote:
> With C++, my advise is to not use raw pointers in your code except when
> forced by interfaces that are out of your control. Prefer references
> instead,

I have done C++ since 1997 and I agree.

Juha Nieminen

unread,
Nov 18, 2022, 4:40:43 AM11/18/22
to
Michael S <already...@yahoo.com> wrote:
> For language that is so similar (nearly identical) to C at the level of
> "virtual machine", as is C++, the concept of reference is just unnecessary.

If we start dismissing everything that one could deem "unnecessary" then we
could start dropping off quite many features even from C itself.

After all, for example the syntax 'a[b]' is just syntactic sugar for
'*(a+b)', and thus the former is "unnecessary" and could just be dropped
off. A 'for()' statement is unnecessary because you can write the same
thing using a 'while()' statement. And obviously the 'do' keyword is
completely unnecessary. As well as the 'switch' keyword. And why do we
even need a 'const' keyword at all? That could be easily dropped off.

We could easily drop half of C syntax as "unnecessary" and still be able
to write the same programs as before. Not to talk about C++!

> Don't use references in your code except when forced by interfaces that
> are out of your control! Then people that are going to read and comprehend
> your code will be thankful.

Actually references add useful abstraction to interfaces. For example,
when you write 'foobar(abc)', is that 'foobar' function taking the
parameter by value or by reference? It can decide! Whatever is best in
that particular function, it can choose. The calling code doesn't need to
tie its hands and force one or the other.

Moreover, if later it turns out that the function would need to change
how it takes the parameter (for example it originally took it by value,
but the type got a lot larger after a refactor, so now it would be more
efficient to take it by reference), it can do so without breaking any
code that's calling the function. (And no, "just fix all the places
where the function is called, by following the compiler errors" is not
a good solution because this may be a library used somewhere, and you
will be breaking the API, causing it to become incompatible with the
previous version, forcing every project that uses the library to fix
all the calls.)

Also, how do you suggest implementing copy constructors and operator
overloading without references?

Michael S

unread,
Nov 18, 2022, 6:23:10 AM11/18/22
to
On Friday, November 18, 2022 at 11:40:43 AM UTC+2, Juha Nieminen wrote:
> Michael S <already...@yahoo.com> wrote:
> > For language that is so similar (nearly identical) to C at the level of
> > "virtual machine", as is C++, the concept of reference is just unnecessary.
> If we start dismissing everything that one could deem "unnecessary" then we
> could start dropping off quite many features even from C itself.
>
> After all, for example the syntax 'a[b]' is just syntactic sugar for
> '*(a+b)', and thus the former is "unnecessary" and could just be dropped
> off.

The [] variant is shorter by 2 characters. In DRM view, shortness of most
frequently used language features was of high priority.
Also, in slightly more complex expressions, in case of *(a+b) variant reader
has to look for more information in order to figure out which of two homonyms
of * is actually used. I would speculate that DRM was not really pleased with
using asterisk for dereference, but had no better choice in available
character set.

A 'for()' statement is unnecessary because you can write the same
> thing using a 'while()' statement.

Except that 'continue' behave differently.
The better argument is that 'while' loops are unnecessary and that is
absolutely correct. A mistake on part of DRM.

> And obviously the 'do' keyword is completely unnecessary.

I don't see it. Please elaborate.

> As well as the 'switch' keyword.

What alternative do have in mind? if-else-if chains?
Both more typing and intentions of using the same selection variable
for all choices is not pronounced clearly.

> And why do we
> even need a 'const' keyword at all? That could be easily dropped off.

People argue for that. IIRC, 'const' is relatively late addition to C, so
likely DRM was not very sure about it.
Personally, I find it useful, primarily for documenting of intent.
The claim that it often helps to catch bugs is hard to prove.
As to C++ [mis]use for peeking one of polymorphic methods... well,
it's pretty bad, but not the worst thing caused by polymorphic methods.

>
> We could easily drop half of C syntax as "unnecessary" and still be able
> to write the same programs as before. Not to talk about C++!

So, you don't think that C++ will become a better language if 2/3rd of it
is dropped? I was under impression that just about everybody agree about
that. Of course, they rarely agree about what third to retain.

> > Don't use references in your code except when forced by interfaces that
> > are out of your control! Then people that are going to read and comprehend
> > your code will be thankful.
> Actually references add useful abstraction to interfaces. For example,
> when you write 'foobar(abc)', is that 'foobar' function taking the
> parameter by value or by reference? It can decide! Whatever is best in
> that particular function, it can choose. The calling code doesn't need to
> tie its hands and force one or the other.
>
> Moreover, if later it turns out that the function would need to change
> how it takes the parameter (for example it originally took it by value,
> but the type got a lot larger after a refactor, so now it would be more
> efficient to take it by reference), it can do so without breaking any
> code that's calling the function. (And no, "just fix all the places
> where the function is called, by following the compiler errors" is not
> a good solution because this may be a library used somewhere, and you
> will be breaking the API, causing it to become incompatible with the
> previous version, forcing every project that uses the library to fix
> all the calls.)
>

If only const references were allowed as function arguments I'd
wholeheartedly agree with majority of above paragraph.
Unfortunately, mutable references are as legal as const ones
and the reader of the code has no hint about which variant was
used by looking at function call.

> Also, how do you suggest implementing copy constructors and operator
> overloading without references?

How said that I suggest implementing copy constructors and operator
overloading?
In my view, non-trivial constructor is original sin of C++ language.
It begot exceptions and the rest of the mess followed.

Paavo Helde

unread,
Nov 18, 2022, 7:51:17 AM11/18/22
to
18.11.2022 11:40 Juha Nieminen kirjutas:

> After all, for example the syntax 'a[b]' is just syntactic sugar for
> '*(a+b)', and thus the former is "unnecessary" and could just be dropped
> off.

It seems other people have agreed with this idea, resulting in things like:

while (*(bord+*(*contur-1)-upp)==ncus &&
(*(*contur-1)-tper2<0 || *(*contur-1)-tper2>(ntpertper-1) ||
*(bord+*(*contur-1)-tper2)!=ncus) &&
*temporal!=*(*contur-1))
{
*(*contur)=*(*contur-1)-upp;
(*contur)++;
}

Unfortunately, these is a copy-paste from real code :-((


Michael S

unread,
Nov 18, 2022, 8:12:08 AM11/18/22
to
In post above, please mentally replace DRM with DMR.

JiiPee

unread,
Nov 18, 2022, 11:32:31 AM11/18/22
to
A lot of stars :)

James Kuyper

unread,
Nov 19, 2022, 2:34:32 AM11/19/22
to
On 11/18/22 06:23, Michael S wrote:
> On Friday, November 18, 2022 at 11:40:43 AM UTC+2, Juha Nieminen wrote:
...
I get the impression that you've missed his point. He's not arguing that
C would be made better by dropping all of those things. He's pointing
out that just because something is not necessary, is not a reason for
dropping it from the language. It is precisely his point that the
language would be less easy to use if these features were removed for no
better reason than the fact that they are unnecessary.


Michael S

unread,
Nov 19, 2022, 11:21:05 AM11/19/22
to
I don't know about your or Juha, but I personally draw a line at DRY.
Features that help to DRY can be controversial, can be even harmful,
(as many preprocessor macros) but they are not nutrient-free syntactic
sugar.
Of all features of 'C' listed by Juha, only 'while' and 'const' do not help
DRY at all and only [] help it minimally, but [] obviously help other aspects
of readability.
C++ references do not help DRY at all, except if you consider & here
or * there as repeating yourself. And, IMHO, presence of references
in the language makes understanding somebody else's code
significantly harder.

Jorgen Grahn

unread,
Nov 19, 2022, 12:10:20 PM11/19/22
to
On Thu, 2022-11-17, Juha Nieminen wrote:
> I have noticed that a lot of C++ programmers have an... well, perhaps the
> word "incorrect" is too strong, but at least slightly incorrect concept
> of what a "reference" in C++ is. Not in terms of how the compiler
> implements it internally, but at the language level. Thus, they tend to
> explain it to beginners in a way that might not be the best. (They tend to
> go too much into the internal implementation details that the compiler uses,
> even if they do this inadvertently, instead of talking at the *language*
> level, about the semantics.)

> What I mean with this is that many (perhaps most?) C++ programmers seem to
> think of C++ references, for all intents and purposes, as "an alternative
> syntax for pointers". A more limited version of a pointer. Perhaps "a safer
> alternative syntax for a pointer."
>
> While a reference might in practice be internally implemented by the
> compiler pretty much as if it were a pointer, it shouldn't really be
> thought as such at the language level.

Especially since the beginners you're explaining things to should
learn about references long before they learn about pointers. And
they don't always have a C background nowadays.

> A reference should be thought of as an "alias" for the original variable
> it's referencing.

s/variable/object/. (Happily you use "object" in the rest of the text.)

[snip]

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Paavo Helde

unread,
Nov 19, 2022, 5:38:14 PM11/19/22
to
19.11.2022 18:20 Michael S kirjutas:
> I don't know about your or Juha, but I personally draw a line at DRY.
> Features that help to DRY can be controversial, can be even harmful,
> (as many preprocessor macros) but they are not nutrient-free syntactic
> sugar.
[...]
> C++ references do not help DRY at all, except if you consider & here
> or * there as repeating yourself. And, IMHO, presence of references
> in the language makes understanding somebody else's code
> significantly harder.

That's strange, are you sure you mean the same DRY ("Don't repeat
yourself")? Because with pointers you need to consider and repeat the
fact that you are calling via a pointer at each call site, with
references this is not so.

I agree the code might be hard to understand if references or pointers
are abused for implementing "output parameters". But thankfully, C++ has
perfectly fine ways to return multiple values from the function, so
there is no need to abuse pointers or references for that purpose. And
for normal input parameters references (const or rvalue) are just fine
and often a much better choice than pointers.

Also, if you say presence of references is what makes C++ hard to
understand, I start to suspect you haven't seen half of C++ yet. Look up
any template code posts from Bonita, for starters ;-)


Öö Tiib

unread,
Nov 19, 2022, 6:13:37 PM11/19/22
to
Pointer can be null, so everywhere it is passed has to check that it is
not null and that gets quite repetitive to do after a while.

Chris M. Thomasson

unread,
Nov 19, 2022, 6:18:59 PM11/19/22
to
Or, a lib writer can say passing a null pointer into function void*
foo(void*) will result in undefined behavior.

Michael S

unread,
Nov 19, 2022, 6:27:34 PM11/19/22
to
If you specified in the docs for your function that it can't take null
then you don't have to check for null.

Paavo Helde

unread,
Nov 19, 2022, 6:28:56 PM11/19/22
to
That's what a reference is for. It's self documenting.

Öö Tiib

unread,
Nov 19, 2022, 6:33:16 PM11/19/22
to
So caller has to check, that is even worse violation of DRY as a function is
usually called from multiple places. Meanwhile lib writer can accept a
reference and then the check is needed on neither side.

Michael S

unread,
Nov 19, 2022, 6:35:31 PM11/19/22
to
On Sunday, November 20, 2022 at 12:38:14 AM UTC+2, Paavo Helde wrote:
> 19.11.2022 18:20 Michael S kirjutas:
> > I don't know about your or Juha, but I personally draw a line at DRY.
> > Features that help to DRY can be controversial, can be even harmful,
> > (as many preprocessor macros) but they are not nutrient-free syntactic
> > sugar.
> [...]
> > C++ references do not help DRY at all, except if you consider & here
> > or * there as repeating yourself. And, IMHO, presence of references
> > in the language makes understanding somebody else's code
> > significantly harder.
> That's strange, are you sure you mean the same DRY ("Don't repeat
> yourself")? Because with pointers you need to consider and repeat the
> fact that you are calling via a pointer at each call site, with
> references this is not so.
>

As I said, "except if you consider & here or * there as repeating yourself."
I don't. Also, even those who considered it repeating would agree that
it is non dangerous sort of repeating, because each time you did it wrong
compiler will catch you.

> I agree the code might be hard to understand if references or pointers
> are abused for implementing "output parameters".

You mean tuples?
May be, they should be used more, but syntax is rather ugly.
Even pairs look ugly.

> But thankfully, C++ has
> perfectly fine ways to return multiple values from the function, so
> there is no need to abuse pointers or references for that purpose.
> And
> for normal input parameters references (const or rvalue) are just fine
> and often a much better choice than pointers.
>
> Also, if you say presence of references is what makes C++ hard to
> understand, I start to suspect you haven't seen half of C++ yet. Look up
> any template code posts from Bonita, for starters ;-)

Of course, I recognize that references are a small nuisance relatively
to 100 other features in C++, including 75 features that considered
god-send by "modern C++" enthusiasts.

Michael S

unread,
Nov 19, 2022, 6:36:50 PM11/19/22
to
No, caller does not have to check, because caller knows that he passes non-null.

Öö Tiib

unread,
Nov 19, 2022, 6:43:28 PM11/19/22
to
About reference it is known that it is not null but about pointer it is known only
after checking ... like if the caller is he or she takes checking.

Michael S

unread,
Nov 19, 2022, 6:51:19 PM11/19/22
to
No. in code below caller does non need to check anything.
int bar;
foo(&bar);

Öö Tiib

unread,
Nov 19, 2022, 8:57:33 PM11/19/22
to
That function foo there is done weirdly. Why it wasn't done without using neither
pointer nor reference? Like:

int bar = foo();


Chris M. Thomasson

unread,
Nov 19, 2022, 10:56:28 PM11/19/22
to
Because foo takes a pointer to an int that _shall_ not be a nullptr.

Öö Tiib

unread,
Nov 20, 2022, 6:47:53 AM11/20/22
to
I mean the int pointed at must be present but may be uninitialized so it is
lot more logical to have it as return value.

Michael S

unread,
Nov 20, 2022, 7:24:38 AM11/20/22
to
This was an example intended to illustrate *one* point.
It was not an attempt to justify a passing of parameters by pointer/reference
vs other methods, but illustration of absence of material difference between
pointer and reference in this case and of weakness of your argument about need
to check for null by caller.
Normally, you are well capable of critical thinking, but in this particular
case it seems like you copied argument from bad beginner's book without giving
it your own thought.

Tim Rentsch

unread,
Nov 20, 2022, 8:48:38 AM11/20/22
to
Paavo Helde <ees...@osa.pri.ee> writes:

> 17.11.2022 16:09 Michael S kirjutas:
>
>> For language that is so similar (nearly identical) to C at the level of
>> "virtual machine", as is C++, the concept of reference is just unnecessary.
>> Don't use references in your code except when forced by interfaces that
>> are out of your control! Then people that are going to read and comprehend
>> your code will be thankful.
>
> Aren't most languages similar to C at the level of virtual machine?

No. Many are. Many are not.

Öö Tiib

unread,
Nov 20, 2022, 9:32:47 AM11/20/22
to
It did not do that very well as it looked like badly designed interface.

> It was not an attempt to justify a passing of parameters by pointer/reference
> vs other methods, but illustration of absence of material difference between
> pointer and reference in this case and of weakness of your argument about need
> to check for null by caller.

Where did I claim that there do not exist such circumstances where we know
that some pointer can't be null? Reference communicates that situation better
and with less stars to type. Library whose documentation tells that lot of its
usages are undefined behavior is low quality library.

The whole reason of languages like Rust winning is that in real application
every C++ module has to be maximally paranoid with explicit and very
repetitive code about shit feed to it. Otherwise app crashes in their module,
bug will be reported to them, and they have to analyze and explain to yet
another set of confused newbies that it was documented that the argument
should not be null.

> Normally, you are well capable of critical thinking, but in this particular
> case it seems like you copied argument from bad beginner's book without giving
> it your own thought.

There are no point in your argument. I have not used any raw pointers in
C++ code for more than 15 years. There was no need to write code for
that as smart pointers, optional, variant and array were in boost already
at 2005. After C++11 there are even less theoretical corner cases where
there might be need for pointers. So my library interface just does not
have any raw pointer arguments and you have aired zero reason why it
has to change.

Juha Nieminen

unread,
Nov 21, 2022, 6:56:32 AM11/21/22
to
I also like the lack of clarifying spaces, making the code even more
condensed and harder to read than it already is.

Juha Nieminen

unread,
Nov 21, 2022, 6:59:37 AM11/21/22
to
Jorgen Grahn <grahn...@snipabacken.se> wrote:
>> A reference should be thought of as an "alias" for the original variable
>> it's referencing.
>
> s/variable/object/. (Happily you use "object" in the rest of the text.)

I was thinking of it more like "the name of the object is 'foo', and a
reference 'bar' would be an alias for that 'foo' object".

(But yes, references can also refer to unnamed temporary objects...)

Chris M. Thomasson

unread,
Nov 21, 2022, 7:32:25 PM11/21/22
to
A C API that requires a non-null pointer is not badly designed, right?


>> It was not an attempt to justify a passing of parameters by pointer/reference
>> vs other methods, but illustration of absence of material difference between
>> pointer and reference in this case and of weakness of your argument about need
>> to check for null by caller.
>
> Where did I claim that there do not exist such circumstances where we know
> that some pointer can't be null? Reference communicates that situation better
> and with less stars to type.
^^^^^^^^^^^^^^^^^^^^^^^^^
[...]

Hard to disagree with this.





Öö Tiib

unread,
Nov 22, 2022, 11:30:35 AM11/22/22
to
C API that requires non-null pointer arguments is perfectly fine. There are no
references in C. Passing things around by value is expensive but passing
nothing can be out of question. So the only solution is to have pointer
that may not be null. Also usages of void pointers or otherwise opaque
pointers and function pointers can be rather useful in C but are relatively
rare in C++.
0 new messages