- Feature Name: associated_statics
- Start Date: 2018-05-14
- RFC PR:
- Rust Issue:
Summary
Traits and impls can have associated consts, but not associated statics. This RFC proposes to allow associated statics in traits and impls.
Motivation
const
s are useful, but they are limited:
- They can’t have some useful or necessary attributes applied to them (e.g.
export_name
,link_section
, etc.). - They can’t refer to statics.
- They can’t be imported from some external library.
- They don’t represent a precise memory location.
These limitations apply to associated const
s. Statics address these limitations, and associated statics in particular address these limitations with all the same benefits that associated const
s have (compared to non-associated const
s).
Guide-level explanation
Static items can be associated with a trait or type, much like const
items can be associated with a trait or type.
A struct may contain associated statics:
struct CustomStruct;
impl CustomStruct {
// Statics may have attributes (like #[no_mangle]) applied to them.
#[no_mangle]
pub static CUSTOM_STRUCT_ID: u32 = 13;
}
fn main() {
println!("The struct's ID is {}", CustomStruct::CUSTOM_STRUCT_ID);
}
A struct’s associated statics may be provided by an external library by wrapping them in an extern {}
block:
struct Struct;
impl Struct {
extern "C" {
static EXTERN_STATIC: usize;
}
}
fn main() {
println!("The extern static is {}", unsafe { Struct::EXTERN_STATIC });
}
Traits may also have an associated static (though the static may not be extern
):
trait Trait {
static ID: usize;
}
struct Struct;
impl Trait for Struct {
static ID: usize = 15;
}
fn main() {
println!("The struct's ID is {}", Struct::ID);
}
The trait may define a default value (and linker-related attributes) for the static, though the implementation may override these:
trait Trait {
#[link_section = ".default_key_section"]
static KEY: usize = 1;
#[link_section = ".default_value_section"]
static VALUE: usize = 2;
#[link_section = ".default_key_ref_section"]
static KEY_REF: &'static usize = &Self::KEY;
}
struct Struct;
impl Trait for Struct {
#[link_section = ".custom_key_section"]
static KEY: usize = 16;
}
fn main() {
// Struct::KEY's link section is ".custom_key_section".
assert_eq!(Struct::KEY, 16);
// Struct::VALUE's link section is ".default_value_section".
assert_eq!(Struct::VALUE, 2);
// Struct::KEY_REF's link section is ".default_key_ref_section".
assert_eq!(Struct::KEY_REF as *const _, &Struct::KEY as *const _);
}
Reference-level explanation
Due to a number of complexities and limitations, this RFC proposes that the feature be kept minimal initially. Associated statics are only permitted as follows:
- Generic structs and traits cannot contain associated statics, even if the static does not use the generic parameter.
- This is because generic statics cannot be supported on Windows in a dynamic library without explicitly declaring which monomorphizations are provided (like C++ requires).
- Even if the static does not use the generic type parameter, it is unclear whether all monomorphizations should share a single static or if they should each get their own. For example:
It is unclear whetherstruct Struct<T>(std::marker::PhantomData<T>); impl<T> Struct<T> { static STATIC: usize = 42; }
Struct<u8>::Static
should be the same static asSruct<i8>::Static
, or if they should refer to unique statics (in which case this hits the same problem on Windows as above). This can be addressed in a later RFC if desired.
- The static itself cannot be generic. That’s a separate RFC.
- Associated trait statics cannot be extern. For example, the following is not permitted:
This is not permitted because extern statics are unsafe, and using an extern static breaks the safety contract of the trait. The following is also not permitted:trait Trait { static TRAIT_STATIC: usize; } impl Trait for Struct { extern { static TRAIT_STATIC: usize = 13; } }
It could be permitted, but this RFC proposes we start by not permitting this and leave it as a later expansion point.trait Trait { extern { static TRAIT_STATIC: usize; } }
Drawbacks
Since this RFC proposes minimal support for associated statics, there are some unsupported situations that are unlikely to be obvious to users. The compiler should take this into consideration when emitting error messages, and perhaps links to additional information resources should be included in the diagnostic messages.
Rationale and alternatives
The rationale for this feature is largely the same as the rationale for associated const
s, except associated statics will be more useful for FFI.
Prior art
Associated const
s blazed the trail for associated statics, and this RFC attempts to draw as much as possible from the existing associated const
s feature.
Associated statics have been discussed before:
- Associated Statics - a way to have high performance, (mostly) statically dispatched event busses
- How about “generic global variables”?
The primary road block these discussions mentioned is the problem of monomorphizing generic statics in a dynamic library. This RFC attempts to avoid that road block by prohibiting generic statics.
Unresolved questions
None (yet).
Future possibilities
The syntax extern { ... }
within a struct
item opens the door for associated extern functions. This RFC does not propose adding these, but future RFCs may do so.
Generic statics might be feasible if they are not part of the crate’s public API (since all monomorphizations are known at compile time and the previously mentioned dynamic library is avoided). A future RFC could explore this further.
Associated statics for generic traits and types that don’t depend on a generic parameter (e.g., impl<T> Struct<T> { static DOES_NOT_USE_T: usize = 42; }
) might be feasible to add in a future RFC.