Why string literals are in borrowed form?

It’s not a contradiction, but it is a complication. Insofar as that the dedicated mechanism of “baking a value into the executable”, static variables, also needs to care about the question of why owns the value and what implication this has. Or put differently, your thoughts exactly address the question why global variables are a bit more complicated to use in Rust than in some other languages.

The typical form ownership in Rust works is that a value is ultimately owned, at least indirectly, at a local variable by some function. (Or more precisely by some specific function call; the “same” local variable in different calls to the same function makes for different owners.)

The “baked into the executable” for of ownership, i.e. the ownership in static variables, is different… the implications of global variables is that any function (and call to any function) can access the variable, but no function owns it. So it’s inherently shared, which in Rust often means the same as “immutable”, and additionally its also inherently shared between threads, so it even requires Sync.

The other implication of “baked into the executable”, independent of ownership, is that the value must be known at compile-time (because there is no good time when some initialization code could be run), which for statics translates into the restriction to const-evaluable expressions as initial value.

Back to string literals: Their value is known at compile-time and strings are thread-safe; their data – being “baked into the executable” can be accessed in a shared manner anyways, so making their type be &'static str to begin with makes sense. Though as others have manages, this design is also related to how str is a type without a fixed size known at compile time. (And b"hello world" syntax for byte-strings returning &[u8; LEN] instead of [u8; LEN] might be for consistency.)

For comparison, literals of types that do have a known type at compile-time can also be “baked into the executable” via so-called “static promotion” (the precise rules of which are beyond the scope of this comment), but for them you’ll have to write the & yourself, as … ah @scottmcm demonstrated that just now :slight_smile:

The values of &str or static-promoted literals are a bit different from true statics in that

  • you cannot name them from other functions
  • there is no guarantee that they always refer to the same static piece of memory as true statics would; on the other hand
  • they may also be deduplicated if the compiler wants to do so. I’m not sure whether that’s allowed for actual statics, too (in cases where you do observe their address; and assuming no interior mutability)

Even though you cannot refer to the same baked-in value from a different function (other than using the same value and hoping for the compiler to de-duplicate them), as noted before, the relevant detail is different function calls are different owners, so as different calls to the same function would share the access to the same values, essentially all the same considerations apply as with true statics. Edit: Funnily enough, thinking about this for this reply made me just re-discover an (apparently known) Rust-issue about one – possibly problematic – aspect of how they aren’t currently treated the same as statics (specifically, w.r.t. Sync).

8 Likes