0

Code in C++

#include <iostream>
#include <string>
using namespace std;

int main() {

string food = "Burger";

cout << &food << endl;

return 0;

}

The same code written in Rust:

fn main() {
    let food = "Burger";

    prinln!("{}", &food);
}

The output for the C++ program:

0x7fff604b2890

The output for the Rust program:

Burger

Why is this so? What am I missing?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Basil Ajith
  • 125
  • 10
  • 8
    are different languages different? Yes! Why? Because they are different languages. – 463035818_is_not_an_ai Oct 02 '20 at 07:31
  • 9
    btw I dont know Rust, but in your C++ code there is no reference – 463035818_is_not_an_ai Oct 02 '20 at 07:31
  • 6
    Concerning C++: Please, don't confuse the reference type with the address operator. `int &x;` <- This is a declaration. The meaning of `&` is reference. `std::cout << &x;` <- This is an expression. Now, the meaning of `&` is address-of-operator. (Nobody said that C++ is an easy to read language for non-experts...) – Scheff's Cat Oct 02 '20 at 07:32
  • 4
    In Rust it helps to think of `&` as meaning "borrow" more than "reference". – tadman Oct 02 '20 at 07:36
  • 1
    I haven't encountered the C++ flavour of "reference" in any other language in use today. Like a lot of C++, it came from Simula 67. (C++ is more or less what you get if you add Simula 67 and CLU, remove garbage collection, and change the syntax from Algol to C.) – molbdnilo Oct 02 '20 at 09:07
  • Oh! I mixed up the whole thing! My bad. Now, I get it. – Basil Ajith Oct 02 '20 at 10:55

1 Answers1

13

First thing first, in C++ the & (address-of) operator returns a pointer, that is, given T t;, &t will return a T*.

C++ does have references (T&), they are not created via the & operator, I'll point you to this great answer for numerous differences between C pointers and C++ references.

Now to answer your question, the concept of references is completely different between C++ and Rust.

Rust's references are fundamentally smart pointers. If we go down the list from the link above, Rust references:

  • can be initialised unset
  • can be re-bound
  • have their own identity (size, position in memory, …)
  • can be nested
  • can be dereferenced
  • can be put into other things

They're also created using the & operator, which are all pointer properties.

Now while they're pointers they're not C pointers, they're "smart" because they're (type) safe, and thus like C++ references can't be null, or dangling. But that makes them safe/sane pointers. Across the board they still really behave as pointers more often than not.

As to what you are missing, the answer is that Display (the trait used to format things) is blanket-implemented on references by delegating to the parent object, so when you print "a reference" it's going to print whatever is being referred, because... that's way more useful, especially given how common references are in Rust (they're very, very common)[0].

If you want the reference's "pointer value", you can use the pointer value formatting specifier (thanks trentcl):

println!("{:p}", &food);

(you could also cast to a raw pointer which is what I'd originally written but if you just want to print the value that's a lot more work for little payoff).

[0] to be fair other Rust smart pointers behave the same: Box, Rc, and friends all delegate Display to the underlying type

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • @tadman true, I've rewritten point 1 to try and be less misleading, and make the difference between `&t` and `T&` clearer, does that look better? – Masklinn Oct 02 '20 at 07:37
  • 2
    There's a formatting specifier and trait explicitly for pointers: `println!("{:p}", &food);` will do the trick without having to cast to a raw pointer. The same works for other kinds of pointers, such as `Arc` and `Box`. – trent Oct 02 '20 at 07:41
  • @trentcl true I'd completely forgotten that one, replaced the bits about casting with & and a doc link, thanks. – Masklinn Oct 02 '20 at 07:45