Michael (cc'ing rust-dev)-
On 22 May 2014, at 16:32, Michael Woerister <[email protected]> wrote:
> Lately I've been thinking that it might be nice if one could omit the
> lifetimes from the list of generic parameters, as in:
>
> fn foo<T>(x: &'a T, y: &'b MyStruct) -> (&'b int, &'a uint)
>
> instead of
>
> fn foo<'a, 'b, T>(x: &'a T, y: &'b MyStruct) -> (&'b int, &'a uint)
>
> Especially for otherwise non-generic functions, having to explicitly list
> lifetimes seems a bit redundant, as they are unambiguously defined in the
> function signature anyway (as opposed to type parameters, which don't have
> the special `'` marker).
Note that this is not true in the general case. Consider e.g. methods with an
type impl or a trait impl: in that scenario, one could bind lifetimes on the
method itself, or in the type/trait being implemented. This distinction
matters (in terms of what limits it imposes on the clients of those
types/traits).
(I provide a concrete example after my signature.)
There are other changes one could make to still accommodate a change like you
suggest in the general case, such as inferring some binding site (e.g. the
nearest one) if a lifetime is otherwise found to be unbound. But I personally
do not think such changes improve the character of the language (IMHO); I'd
rather have a straight-forward rule that one applies in every context.
Cheers,
-Felix
Concrete Example:
The variants below are quite different.
#[deriving(Show)]
struct S<'a> {
p: &'a int
}
impl<'a> S<'a> {
#[cfg(variant1)]
fn foo(&mut self, arg: &'a int) -> &'a int {
let old = self.p;
self.p = arg;
old
}
#[cfg(variant2)]
fn foo<'a>(&mut self, arg: &'a int) -> &'a int {
let old = self.p;
self.p = arg;
old
}
#[cfg(variant3)]
fn foo<'a>(&mut self, arg: &'a int) -> &'a int {
arg
}
#[cfg(variant4)]
fn foo<'a>(&mut self, arg: &'a int) -> &'a int {
self.p
}
#[cfg(variant5)]
fn foo<'a>(&self, arg: &'a int) -> &'a int {
self.p
}
#[cfg(variant6)]
fn foo<'a>(&'a self, arg: &'a int) -> &'a int {
let _ = arg;
self.p
}
}
#[allow(unused_mut)]
fn main() {
let x = 3;
let mut s = S{ p: &x };
let y = 4;
println!("begin: {:?}", s);
let z = s.foo(&y);
println!("later: {:?} z: {:?}", s, z);
}
Half of them do not compile (for differing reasons). Variants 1, 3, and 6 do
run (and each produces a different output), but the interesting points come
from understanding why the other cases do not compile.
(FYI: It is probably easier to talk about the example if you first alpha-rename
the method-bound lifetimes to something other than `'a`.)
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev