0

From what I can tell, references can be used wherever the original type can (I'm not implying the reverse is true), the only difference is their mutation semantics (when the variables are used as lvalues).

Wouldn't they then qualify as the same type as the original? If so, why is the fact that something is a reference, stored in its type?

Edit: if references are a different type, why can they be substituted for the original type in so many situations, without explicit casting? Is there implicit cast involved?

Example:

void bar(int& a);

int x;
int& y = x;

bar(y) // matching type
bar(x) // what happened here? was x cast to a reference?
corazza
  • 31,222
  • 37
  • 115
  • 186
  • References have different properties than pointers, while still having a "target type" they reference (point to) just like plain pointers. See [here](http://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in) for more details. – Jens Jul 26 '15 at 14:43
  • T and T& are different types, so you can overload your function – grisha Jul 26 '15 at 14:43
  • @dyp OK, true, I meant mutation in general. – corazza Jul 26 '15 at 14:48
  • @CamelToe What in this question makes you think I don't know C++? And your comment is not an answer. You might want to take a look at TheParamagneticCroissant's answer, he seems to be the only one to have correctly understood what I'm asking. It's about apparent inconsistency in the type system. – corazza Jul 26 '15 at 15:05
  • 2
    @jco: (a) Comments are not _intended_ to be answers, so not sure what you're saying there. (b) Insulting the people you're asking for help is not going to get you very far. If your question is unclear then that's your fault, not ours. – Lightness Races in Orbit Jul 26 '15 at 15:07
  • @LightnessRacesinOrbit (a) He called it an answer, what am I to do? (b) If I insulted someone that was not my intention. However I'm pretty sure *"I though you said you knew c++ on your profile."* is an attempted insult. If not, I'm still waiting to see how it's warranted. – corazza Jul 26 '15 at 15:20
  • 2
    @jco: (a) No, he didn't. (b) I didn't say that wasn't an insult. It's certainly warranted, if inappropriate. My point is that _you_ are the one asking for free help, not us. Accusing everyone of "not getting you" is not going to do you any favours. You are responsible for making your question clear and unambiguous. – Lightness Races in Orbit Jul 26 '15 at 15:20
  • @LightnessRacesinOrbit He literally said "here's an answer", provided a wrong example, and then deleted it. And I don't see how it's warranted, care to explain? – corazza Jul 26 '15 at 15:29
  • @jco: Oh, well, I didn't see that comment. He deleted it before I saw it. Time to delete your reply, then? – Lightness Races in Orbit Jul 26 '15 at 15:30
  • @jco You have changed your original question alot of times now and its hard to understand what you are asking for. First you make the claim that references can be used whereever the original type can (fail), then you ask if references are the same type as the original type (fail), then you ask something that doesn't make more sense (if not why are they written in the type) (fail) and than you are asking why a reference to a reference is not being cast, its the language design and ref to a ref is rly original to a ref. This is basic c++ mate –  Jul 26 '15 at 15:30
  • Also regarding the "wrong answer" i gave you the right answer before you changed your question and highlighted something new in there. Stop editing the question 20 times so the answers stays relevant: int x = 10; int* ptr = &x; int* anotherPtr = &*ptr; foo(anotherPtr); does anotherPtr needs to be cast? NO –  Jul 26 '15 at 15:31
  • @CamelToe Yeah I've edited the question because it was unclear. That's the point of StackOverflow. But there's been like only two significant edits: changing "assignment" to "mutation", and responding to LightnessRacesinOrbit's answer to clarify what I'm asking about. Your first comment is grasping for straws, this has nothing to do with "basic C++", and nothing I've written is false, it was just ambiguous, but now it hopefully isn't any more. – corazza Jul 26 '15 at 15:38

4 Answers4

6

A reference is formally a type; or at least you can read things like "if T is a reference type" in the C++ standard itself.

However, your question is perfectly legitimate in that references have very confusing semantics. They are not quite first-class types (for example, you can't have a reference-to-reference or a pointer-to-reference), and in my opinion that's because C++ managed to conflate two different kinds of types with how it defines and uses references.

What a reference really does is it gives an alternate name to an already-existing object (value). What does this mean? It means that it doesn't "qualify" the type of the value it refers to per se; it rather qualifies the name ("variable", "storage") itself that is used for referencing the value.

In C++, the semantics of a type and a value often depends on additional properties of the storage where the object/value is stored. This is not always explicit, and that's what confuses people.

I think because C++ heavily relies on exposing the concept of "storage" (rather than hiding it as an implementation detail), there really should be two type systems: one for pure values themselves, and one for storage, where the type system for storage should be a superset of the type system for values.

Another example where a very similar issue appears is CV-qualification. It's not an object/value itself that should be const or volatile. It's the storage containing that value that may or may not be mutable, and may or may not need to be protected from certain load/store optimizations. Again, this could be better expressed if there was a way to express these properties of types separately in the case of values and storage.

  • 2
    __that's because C++ managed to conflate two different kinds of types__ ... this is a very good observation. The type system in C++ isn't only used to describe the values, but also how they're accessed. – Daniel Jour Jul 26 '15 at 15:21
  • 1
    *"express these properties of types separately in the case of values and storage"* This is, to some degree, already the case. Actual *values* in C++ are prvalue-expressions, and prvalues of non-class, non-array types are not cv-qualified [expr]p6. Actual *values* of class types do not occur AFAIK, even prvalue-expressions of class type can be given an address via `this` or binding to a reference. – dyp Jul 26 '15 at 15:45
3

From what I can tell, references can be used wherever the original type can

That is simply not true.

Consider:

void foo(int  x);
void bar(int& x);

foo(3);
bar(3); // whoops!

And how about this:

struct T
{
   int& x;
};

It wouldn't make sense not to have a distinct type for references. This way, you get function overloading powers and every other benefit that the type system gives you.

You would otherwise need to invent some other mechanism to denote a thing as being a reference rather than a non-reference; surely the type system is the perfect mechanism to denote that?

int and int& are two distinct types.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • *From what I can tell, references can be used wherever the original type can* How does your example show otherwise? Sure, you can't accept an rvalue in place of a reference, but that's not what my statement means. It means for example that if a function accepts `int`, it will also accept a reference to an `int`. So I'm asking, if they're two different types, is there an implicit cast involved? – corazza Jul 26 '15 at 15:00
  • @jco: I showed a place where you can use the original type, and that you cannot use a reference in the same place. And yes, basically. References would be completely useless if you could never obtain one. – Lightness Races in Orbit Jul 26 '15 at 15:05
  • *I showed a place where you can use the original type, and that you cannot use a reference in the same place.* What do you mean? `bar(3); // whoops!` is the opposite example I never talked about. *And yes, basically.* This is exactly what the answer should be **about**, I'm asking about how this is justified in the type system, there must be some more formal explanation as C++ usually has stricter rules than "it's just implicitly cast". – corazza Jul 26 '15 at 15:08
  • @jco: Yes, of course it does. Pick up your copy of the standard and read how references are initialised. The standard cannot and does not need to be recreated here. – Lightness Races in Orbit Jul 26 '15 at 15:15
  • 2
    @jco *"if a function accepts `int`, it will also accept a reference to an `int`"* For overload resolution etc. as well as implicit conversions, the type of *expressions* is used. The (observed) type of an expression is never a reference, e.g. `int i = 42; int& r = i;`, then the expression `r` has the (observed) type `int`, not `int&`. – dyp Jul 26 '15 at 15:50
  • @dyp Thanks, that's definitely the type of information I was looking for. Could you maybe convert your two comments into an answer, and expand on this one if possible (or refer me to a section of the standard draft that explains this portion of the type system in more detail)? – corazza Jul 26 '15 at 16:03
  • @jco I have not yet found a complete, accurate, simple and consistent (mental) model of what references are in C++. I know the various ways in which references are treated, but they do not form a coherent picture. I'm not even sure if there even is one. Therefore, I'm reluctant to write an answer, but I'll try again to connect the various pieces. – dyp Jul 26 '15 at 16:23
  • @dyp OK, whatever works for you. I was just trying to understand what was happening with the relation to the rest of the type system because it seemed like an inconsistency -- I had theories of my own that for example involved subtyping (which would explain the one-way "implicit cast"). What do you think about that? (Obviously not the whole picture is accounted for, as higher-order references don't exist, and I think that containers would be covariant if we understood it this way, but at least when it comes to calling it seems to apply.) – corazza Jul 26 '15 at 16:37
2

From what I can tell, references can be used wherever the original type can

No. A reference refers. You can think of it as a pointer in disguise.

Are references separate types in C++?

Yes.

If not, why are they written in the type?

That's just the syntax for specifying a reference type, using & as a type builder symbol. As another example, * is a type builder for pointers. Except for a limitation of type inference we could now replace that (1)impractical syntax with template syntax.


1) Both the creators of C and the creator of C++ have on several occasions described the original C declaration syntax as a “failed experiment”.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
-2

Unlike a pointer, a reference cannot be reseated; the address it is referencing cannot be changed. By like a pointer, the reference is useful when avoiding copying semantics, thus needing to create an alias to something that already exists... i.e., knowing it is a reference and not an object means the compiler knows not to copy the object at assignment or when passing through functions.

EDIT: regarding the updated questions, "if references are a different type, why can they be substituted for the original type in so many situations, without explicit casting? Is there implicit casting involved?" ... not casting, it is a reference so it simply gets "dereferenced" by "pointing" to the original object; it may help to just think of it as just a substitution name, or an alias, etc.