[rust-dev] lifetime syntax

Isaac Aggrey isaac.aggrey at gmail.com
Wed Feb 6 10:33:37 PST 2013


I realize the Rust community is beginning to settle on the `'lt` as the syntax
to rule them all, but is using any sort of suffix for lifetime syntax a
non-starter?

If it is, ignore everything below, and instead I'll suggest another sigil:

What about using `#` instead of `'`? It's a bit more visually significant and
doesn't overload any operators I can think of.  The inherent numerical meaning
often associated with the symbol (since we're talking about life*times*) is also
helpful.

If lifetime as a suffix is a possibility, keep reading:

I find it harder to read this code:

    &'lt int
    &'lt mut int

over something like:

    &int#lt      // or if unambiguous, preferably: &int #lt
    &mut int#lt //         ``                    : &mut int #lt

The latter example reads as "a borrowed pointer to an integer with a lifetime
lt" versus the former as "a borrowed pointer with a lifetime lt to an integer".

It is more accurate to say the pointer has the lifetime, but it seems more
immediately useful to emphasize it is a "pointer to an integer" with the
lifetime as a modifier on "pointer to an integer". This subjective
clarity also carries over to generic functions to reduce noise in the type
parameter such as:

     fn has_next<T>#a#b(iter: &Iterator<T#b>#a) -> bool {
         iter.index + 1 < iter.source.len()
     }

    // reads as a function called has_next over type T with lifetimes a and b

vs the current style of:

     fn has_next<'a, 'b, T>(iter: &'a Iterator<'b, T>) -> bool {
         iter.index + 1 < iter.source.len()
     }

      // reads as a function called has_next with lifetimes a and b over type T

I'm not sure if the `#` symbol was ever discussed or if it's even viable, but to
my newbie eyes it seems like it's at least clearer with my eye compiler.

Despite having a very poor understanding of lifetimes and likely butchering the
original intent in the lifetime syntax below, I've attempted to suffixify
some of the examples taken from Niko's opening post:

    struct Iterator<T#lt> {
        source: &[T]#lt,
        index: uint
    }

    fn has_next<T>#a#b(iter: &Iterator<T#b>#a) -> bool {
         iter.index + 1 < iter.source.len()
    }

    fn next<T>#a#b(iter: &mut Iterator<T#b>#a) -> Option<&T#b> {
        iter.index += 1;
        if iter.index < iter.source.len() {
            Some(&iter.source[iter.index])
        } else {
            None
        }
    }

    impl<T#b> Iterator<T#b> {
        fn has_next<T#a>(&self#a) { /* same as before */ }
        fn next<T#a>(&mut self#a) -> Option<&T#b> { /* same as before */ }
     }

    struct Foo<#a#b> // or struct Foo<#a #b> if unambiguous


More information about the Rust-dev mailing list