Skip to content

borrow/ref: Not clear what's the difference between ref and & #390

@kornelski

Description

@kornelski
Contributor

In other languages & is called a reference and borrowing looks very much like references, so to me & and ref seem like the same thing.

I'd appreciate an example that contrasts the two — why let Point { x: ref ref_to_x, y: _ } is OK, but let Point { x: & ref_to_x, y: _ } isn't?

Activity

strega-nil

strega-nil commented on Jan 11, 2015

@strega-nil

ref is used in pattern matching, so its used when you want to borrow
something in, for example, a match statement.

let a = Some("Hello!".to_string());
match a {
    Some(ref s) => { //s is an &String here
    }
    ...
}

match a {
    Some(s) => {
        // s is a String here, and therefore
        // is owned by the match
    }
    ...
}
kornelski

kornelski commented on Jan 11, 2015

@kornelski
ContributorAuthor

Why can't you use & to borrow in the match?

match a {
    Some(&s) => {}
}

?

e.g. in methods I can use &self instead of ref self.

strega-nil

strega-nil commented on Jan 11, 2015

@strega-nil

That, I don't know. It's not really a decision I agree with. I like that
style better, personally.

On Sun, Jan 11, 2015 at 11:27 AM, Kornel notifications@github.com wrote:

Why can't you use & to borrow in the match?

match a {Some(&s) => {}
}

?


Reply to this email directly or view it on GitHub
#390 (comment)
.

"Calling all. This is our last cry before our eternal silence."
"The lone and level sands stretch far and away"

kornelski

kornelski commented on Jan 11, 2015

@kornelski
ContributorAuthor

I'm not trying to question Rust design decision here, just understand difference between ref and & — and I'm reporting that the example about references doesn't elaborate on that.

Whether that's just arbitrary, or quirky syntax to avoid ambiguity, or it has slightly different meaning, I'd like to know that, because I'm not sure when to use which and why rustc complains about &_-ptr or such when I use & instead of ref.

strega-nil

strega-nil commented on Jan 11, 2015

@strega-nil

I think the idea is that you destruct as you construct, like in a

let op = Some(a);

match op {
    Some(x) => x,
    None => ...
}

So if you type

match op {
    Some(&x) => // here you are dereferencing a pointer
        ...
    None => ...
}

On Jan 11, 2015 11:44 AM, "Kornel" notifications@github.com wrote:

I'm not trying to question Rust design decision here, just understand
difference between ref and & — and I'm reporting that the example about
references doesn't elaborate on that.

Whether that's just arbitrary, or quirky syntax to avoid ambiguity, or it
has slightly different meaning, I'd like to know that, because I'm not sure
when to use which and why rustc complains about &_-ptr or such when I use
& instead of ref.


Reply to this email directly or view it on GitHub
#390 (comment)
.

kornelski

kornelski commented on Jan 12, 2015

@kornelski
ContributorAuthor

Sorry, I don't understand your last answer. &x is dereferencing a pointer? I thought *x is dereferencing.

Perhaps I'm asking stupid questions, but the mental model I have is from C:

object  ----  reference operator &  ---> pointer
object  <--- dereference operator * ---- pointer

and there's no room in it for ref. If it's like this:

object  ---- ref operator ---> pointer

then in my mind it's identical with &, but clearly in Rust there must be a difference.

When I use & where Rust expects ref I get error message that I don't understand:

mismatched types: expected isize, found &_ (expected isize, found &-ptr)

I'm not sure what &_ and &-ptr are, but I'm guessing it means reference to an unknown type. And it's weird, because the type should be known from the context.

strega-nil

strega-nil commented on Jan 12, 2015

@strega-nil

So where are you seeing this error? In Rust, you basically have this:

let a = &i;
let r = *a;
// These are exactly like in C (i.e. `&i` gets the address of i,
// `*a` dereferences a)

And in pattern matching, you do this:

let a = Some(1i); // This is how we construct an Option
match a {
    Some(x) => println!("{}', x), // This prints '1'
    // Notice we "deconstruct" in a match statement the same way we
    // normally construct
    ...
}

What about when we have to get a reference in a match statement where there was
none before? In normal code, getting a reference to a variable is easy.

struct BigFoo {
    // Lots of fields
}

fn bar(bf: &BigFoo) {
    // Do stuff with bf
}

fn main() {
    let bf = BigFoo {
        // lots of fields
    }

    bar(&bf);
}

However, what if you have, say, a match statement?

fn possibly_print(x: &Option<BigFoo>) {
    match *x {
        // BAD: It's impossible to move out of an &-reference (the Option)
        //Some(bf) => println!("{:?}", &s),

        // GOOD: Instead, we take a reference into the `Option`s memory
        Some(ref bf) => println!("{:?}", *bf),
        None => println("No BigFoo!"),
    }
}

(Note: this is taken directly from the rust docs book)

Does that make sense?

kornelski

kornelski commented on Jan 12, 2015

@kornelski
ContributorAuthor

The error I was getting was from

match a {
  Some(&x) => 
}

So I think I'm starting to get why it's illegal syntax:

fn main() {
    let x = 123;
    let &x_ref_1 = &x;
    let ref x_ref_2 = &x;
    //let & x_ref_3 = x; // same error as when matching &x
    let ref x_ref_4 = x;
}

It would be great if the tutorial explained exactly what happens in the cases above (they all print the same value, but I suppose Rust's automagic dereferencing hides the differences).

but "matching uses same syntax as constructing" doesn't seem right to me:

    let s1 = Some(&x); // legal
    let s2 = Some(ref x); // illegal
strega-nil

strega-nil commented on Jan 12, 2015

@strega-nil

There are two things going on here:

let x = 3i;
let s1 = Some(&x);
match s1 {
    Some(&y) => {}, // y = x here (it's destructured the same way it's constructed)
    ...
}

ref is only useful for match statements and the like; it's literally only for

let s2 = Some(x);
match s2 {
    Some(ref y) => {}, // y = &x here
    ...
}
kornelski

kornelski commented on Jan 12, 2015

@kornelski
ContributorAuthor

Oh, that's interesting! Are these two statements equivalent?

let x = &y;
let ref x = y;
strega-nil

strega-nil commented on Jan 12, 2015

@strega-nil

Yes, exactly!

On Mon, Jan 12, 2015 at 2:23 PM, Kornel notifications@github.com wrote:

Oh, that's interesting! Are these two statements equivalent?

let x = &y;let ref x = y;


Reply to this email directly or view it on GitHub
#390 (comment)
.

"Calling all. This is our last cry before our eternal silence."
"The lone and level sands stretch far and away"

kornelski

kornelski commented on Jan 12, 2015

@kornelski
ContributorAuthor

Ok, so now it makes sense to me! Thanks!

I suggest adding such simple example to the site:

let y = 'y';

// `ref` on the left side of an assignment is like adding `&` on the right side
let ref x1 = y;
let x2 = &y;

println!("{}", x1 == x2);

The full example is useful as well, but with destructuring at the same time there's much more going on.

strega-nil

strega-nil commented on Jan 12, 2015

@strega-nil

Thank you very much for bringing this incredibly confusing thing to our
attention; I hadn't even thought about it before you said it :)
On Jan 12, 2015 2:37 PM, "Kornel" notifications@github.com wrote:

Ok, so now it makes sense to me! Thanks!

I suggest adding such simple example to the site:

let y = 'y';
// ref on the left side of an assignment is like adding & on the right sidelet ref x1 = y;let x2 = &y;

println!("{}", x1 == x2);

The full example is useful as well, but with destructuring at the same
time there's much more going on.


Reply to this email directly or view it on GitHub
#390 (comment)
.

mdinger

mdinger commented on Jan 20, 2015

@mdinger
Contributor

@pornel I just saw this thread and modified PR #421 to try to elaborate on this.

The specific file was pointers.rs

By the way, your critiques are very helpful. It's really hard to anticipate learning questions. Generally I focus on trying to fix things I find confusing but having others do the same is really useful.

19 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @kornelski@vbauerster@abbshr@strega-nil@mdinger

        Issue actions

          borrow/ref: Not clear what's the difference between ref and & · Issue #390 · rust-lang/rust-by-example