RFC 1623: static

lang (typesystem | inference | const)

Summary

Let's default lifetimes in static and const declarations to 'static.

Motivation

Currently, having references in static and const declarations is cumbersome due to having to explicitly write &'static ... Also the long lifetime name causes substantial rightwards drift, which makes it hard to format the code to be visually appealing.

For example, having a 'static default for lifetimes would turn this:

static my_awesome_tables: &'static [&'static HashMap<Cow<'static, str>, u32>] = ..

into this:

static my_awesome_table: &[&HashMap<Cow<str>, u32>] = ..

The type declaration still causes some rightwards drift, but at least all the contained information is useful. There is one exception to the rule: lifetime elision for function signatures will work as it does now (see example below).

Detailed design

The same default that RFC #599 sets up for trait object is to be used for statics and const declarations. In those declarations, the compiler will assume 'static when a lifetime is not explicitly given in all reference lifetimes, including reference lifetimes obtained via generic substitution.

Note that this RFC does not forbid writing the lifetimes, it only sets a default when no is given. Thus the change will not cause any breakage and is therefore backwards-compatible. It's also very unlikely that implementing this RFC will restrict our design space for static and const definitions down the road.

The 'static default does not override lifetime elision in function signatures, but work alongside it:

static foo: fn(&u32) -> &u32 = ...;  // for<'a> fn(&'a u32) -> &'a u32
static bar: &Fn(&u32) -> &u32 = ...; // &'static for<'a> Fn(&'a u32) -> &'a u32

With generics, it will work as anywhere else, also differentiating between function lifetimes and reference lifetimes. Notably, writing out the lifetime is still possible.

trait SomeObject<'a> { .. }
static foo: &SomeObject = ...; // &'static SomeObject<'static>
static bar: &for<'a> SomeObject<'a> = ...; // &'static for<'a> SomeObject<'a>
static baz: &'static [u8] = ...;

struct SomeStruct<'a, 'b> {
    foo: &'a Foo,
    bar: &'a Bar,
    f: for<'b> Fn(&'b Foo) -> &'b Bar
}

static blub: &SomeStruct = ...; // &'static SomeStruct<'static, 'b> for any 'b

It will still be an error to omit lifetimes in function types not eligible for elision, e.g.

static blobb: FnMut(&Foo, &Bar) -> &Baz = ...; //~ ERROR: missing lifetimes for
                                               //^ &Foo, &Bar, &Baz

This ensures that the really hairy cases that need the full type documented aren't unduly abbreviated.

It should also be noted that since statics and constants have no self type, elision will only work with distinct input lifetimes or one input+output lifetime.

Drawbacks

There are no known drawbacks to this change.

Alternatives

Unresolved questions