Why &ref x cannot be extended?

Reference says:

An extending pattern is either: An identifier pattern that binds by reference or mutable reference. ... So ref x, V(ref x) and [ref x, y] are all extending patterns, but x, &ref x and &(ref x,) are not.

I am wondering why these three patterns cannot be extended?

I know that 'x' is not a reference pattern and so does not need to be extended, because it owns it's value and no extension is needed.
But i can't understand why '&ref x' and &(ref x,) do not extend.

& in patterns is a dereference, a opposite of ref

My unofficial answer is it makes it too hard to read/decipher and has no value over what can already be done.

So why shouldn't extending happen in this case? Once the & is used in the pattern, the dereference operation occurs and then the reference value is entered as a reference into the identifier. Then the reference itself (which is temporary) remains until the end of the scope. But why doesn't this happen?

Any attention please?

I actually can't imagine reasonable code where &(ref x) being an extended pattern would make sense. Could you give some example code?

let &ref x = *&&temp();

Consider the following code, which doesn't compile in current rust:

fn identity<'a>(s: &'a String) -> &'a String {
    s
}

fn main() {
    let x = String::from("abc");
    let r = &x;
    let &ref y = *&identity(r);
    drop(x);
    println!("{y}");
}

According to your proposal, the &ref y pattern should cause lifetime extension of the String that identity(r) points to. However, it points to x, which is a variable, not a temporary. Therefore, this lifetime extension doesn't work in the general case.

If this isn't the lifetime extension semantics that you intend, could you more precisely specify what kinds of code should get this new kind of lifetime extension?

You said :

lifetime extension of the String that identity(r) points to

But how an owned value has any lifetime extension? I think only references may extend their lifetime, because only references have lifetimes.
So in your example we only need to expand the lifetime of temp()

There's an overlap of terminology going on.

In Rust we call those 'a things, which parameterize references,[1] lifetimes. They are part of the borrow checking part of the compiler. You can think of them as borrow durations. The borrow checker is a pass-or-fail check and does not "extend [borrow duration, 'a] lifetimes".

When people talk about the lifetime of a (owned) value, they are often talking about its drop scope -- when the destructor gets called. That's what the word "lifetime" in "temporary lifetime extension" is talking about. It does not directly correspond to a borrow-duration lifetime ('x). However, they are related, as it's a borrow checker error for something to get destructed when you're still trying to borrow it.

(The term "lifetime" when used in other languages, which don't have the borrow duration concept, is akin to the latter meaning. This confuses a lot of people, and Rust would be better off if we used a different word for those 'a borrow-duration things, but here we are.)


  1. and other types ↩︎

After some days of thinking, i still can't understand!

Please explain more...

As i know, temporary extension is all about extending the drop scope, so the temporary does not drop when the containing expression is evaluated. Now the temporary is still accessible after the expression.
So when we say ref x = *&temp() because the result is a value but this value is binding by ref, we need this value to be available after x is defined. This leads us to not have a dangling reference.

If i am correct, please explain that why ref x is extended but &ref x is not.

&T is a Copy type. I think it also owns it's value which is a memory addrees; So it is also subject to drop scope. Am i correct?

I know that those terms are overlapped, but this overlap will be worse if references also own their address!

saying "&ref x is not an extending pattern" does NOT mean "binding by &ref x cannot extend the drop scope of a temporary value". it depends on whether the temporary value is an extending expression or not.

in fact, in many common use cases like let &ref x = &temp();, it indeed extends the tempoary value's drop scope.

an counter-example can be found in the same section of the reference you quoted, where the drop scope of the temporary value is NOT extended:

let &ref x = *&&temp();
// if you try to use `x`, you get an error `E0716`:
// temporary value dropped while borrowed
//println!("{}", x);

however, if you write bind it to an extending expression, the temporary value's drop scope is extended:

let &ref x = &*&temp();
// this works
println!("{}", x);

one way to think of it, ref x "simply" binds to the scrutinee, no matter what type it is, it always suceeds[1]; but &ref x can only be matched agains a value of a reference type[2], so in some sense it "destructures" the scrutinee value and the variable name x is a "sub-pattern" so it doesn't binds to the "whole" value.

IMO, the precise definition of extending pattern and extending expression in the reference manual is confusing. the reference should not be interpreted as the "specification" of the language. in fact, rust doesn't have a specification officially. rather, the reference is mainly to explain the current behavior of the compiler. but sometimes, it does a bad job (at explaining some aspects).

in practice, rustc --explain E0716 should give enough clue to solve most drop scope related compile errors.


  1. a.k.a. irrefutable pattern ↩︎

  2. it's NOT refutable in the normal sense, but you get a compile time error if the scrutinee is not a reference type ↩︎