Why use the word 'generic' in lifetime parameters?
Asked Answered
L

2

1

When we write:

fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
    x
}

Why don't we just refer to the 'as and the 'bs as lifetime parameters as opposed to generic lifetime parameters? It's just a syntactical way to communicate to the compiler a constraint on the returned reference's lifetime in terms of the lifetimes of the arguments. I'm struggling to see the rationale for the inclusion of the word "generic" here.

Licking answered 17/12, 2020 at 23:32 Comment(0)
M
2

"Generic" makes me think of generic types, but as far as I can tell it has no relevance here.

You can think of "generic type" as a shorthand for "type with generic parameters", but those generic parameters can be any or all of:

  1. generic type parameters (as in Vec<T>);

  2. generic lifetime parameters (as in type Ref<'a> = &'a i32);

  3. generic const parameters (real soon now).

Same for "generic function" = "function with generic parameters".

You could shorten it to "lifetime parameters" exactly because all lifetime parameters (not all lifetimes!) are generic. The same applies to type parameters.

but I still don't see how that makes 'a generic as opposed to simply a parameter which takes various values

Lifetime parameters and type parameters have a few things in common which don't have to go together, but do in Rust:

  1. the most obvious: they are written between < > and not ( );

  2. they can be inferred;

  3. code can't branch depending on their value.

So they are grouped together as "generic parameters" as opposed to "value parameters".

Marcin answered 18/12, 2020 at 11:18 Comment(0)
A
6

We use the word "generic" in front of "lifetime parameters" because they are generic lifetime parameters.

The obvious counter-example is 'static which is the only non-anonymous lifetime so we can refer to it outside of generic contexts. On the other hand, since all other possible lifetimes are anonymous the only way we can refer to them is through generic lifetime parameters.

The foo function below can be called with theoretically infinitely many different possible lifetimes, and it works in all those situations because it's generic over lifetimes. Here's an example of calling it with 2 different lifetimes:

fn foo<'a>(x: &'a i32) -> &'a i32 { x }

fn main() {
    foo(&1); // called with 'static lifetime
    let x = 1;
    foo(&x); // called with x's anonymous lifetime
    // and so on
}

The lifetime-constraint relationship between the input argument and the output return type in both calls is the same but the lifetimes are different.

Acquaintance answered 17/12, 2020 at 23:59 Comment(4)
Thanks for the answer, but I still don't see how that makes 'a generic as opposed to simply a parameter which takes various values (among them 'static). Are you saying 'static is a different type to the-lifetime-of-x ? In particular, foo can be called with infinitely many arguments, not because it's generic over x but because the parameter x can be passed with infinitely many argument values.Licking
@JSStuball 'a is a generic lifetime parameter while 'static is not a generic lifetime parameter. 'static represents a very specific lifetime. Just like i32 is not a generic type. And yes lifetimes can affect types. Consider the type Foo<'a>, instances of Foo with different lifetimes are not interchangeable (though the compiler can coerce them depending on the case). In this context they act more like generic types.Thermit
Is the point that &'a i32 and &'b i32 are considered different types? Until now I had thought of the lifetime annotations as information associated with the arguments passed to functions, as opposed to actual type information. This semantic adjustment would seem to justify the use of the term generic everywhere we discuss lifetimes.Licking
@JSStuball Yes, &'a i32 and &'b i32 are different types when 'a and 'b are different lifetimes. It can be hard to observe this, though, since the compiler tries to unify lifetimes in order to make code compile.Libido
M
2

"Generic" makes me think of generic types, but as far as I can tell it has no relevance here.

You can think of "generic type" as a shorthand for "type with generic parameters", but those generic parameters can be any or all of:

  1. generic type parameters (as in Vec<T>);

  2. generic lifetime parameters (as in type Ref<'a> = &'a i32);

  3. generic const parameters (real soon now).

Same for "generic function" = "function with generic parameters".

You could shorten it to "lifetime parameters" exactly because all lifetime parameters (not all lifetimes!) are generic. The same applies to type parameters.

but I still don't see how that makes 'a generic as opposed to simply a parameter which takes various values

Lifetime parameters and type parameters have a few things in common which don't have to go together, but do in Rust:

  1. the most obvious: they are written between < > and not ( );

  2. they can be inferred;

  3. code can't branch depending on their value.

So they are grouped together as "generic parameters" as opposed to "value parameters".

Marcin answered 18/12, 2020 at 11:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.