Skip to content

Commit 7e7fab1

Browse files
committed
First draft
1 parent 56edcec commit 7e7fab1

File tree

1 file changed

+169
-0
lines changed

1 file changed

+169
-0
lines changed

active/0000-const-vs-static.md

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
- Start Date: 2014-08-08
2+
- RFC PR: (leave this empty)
3+
- Rust Issue: (leave this empty)
4+
5+
# Summary
6+
7+
Divide global declarations into two categories:
8+
9+
- **constants** declare *constant values*. These represent a value,
10+
not a memory address. This is the most common thing one would reach
11+
for and would replace `static` as we know it today in almost all
12+
cases.
13+
- **statics** declare *global variables*. These represent a memory
14+
address. They would be rarely used: the primary use cases are
15+
global locks, global atomic counters, and interfacing with legacy C
16+
libraries.
17+
18+
# Motivation
19+
20+
We have been wrestling with the best way to represent globals for some
21+
times. There are number of interrelated issues:
22+
23+
- *Significant addresses and inlining:* For optimization purposes, it
24+
is useful to be able to inline constant values directly into the
25+
program. It is even more useful if those constant values do not have
26+
a known address, because that means the compiler is free to replicate
27+
them as it wishes. Moreover, if a constant is inlined into downstream
28+
crates, than they must be recompiled whenever that constant changes.
29+
- *Read-only memory:* Whenever possible, we'd like to place large
30+
constants into read-only memory. But this means that the data must
31+
be truly immutable, or else a segfault will result.
32+
- *Global atomic counters and the like:* We'd like to make it possible
33+
for people to create global locks or atomic counters that can be
34+
used without resorting to unsafe code.
35+
- *Interfacing with C code:* some C libraries require the use of
36+
global, mutable data. Other times it's just convenient and threading
37+
is not a concern.
38+
- *Initializer constants:* there must be a way to have initializer
39+
constants for things like locks and atomic counters, so that people
40+
can write `static MY_COUNTER: AtomicUint = INIT_ZERO` or some
41+
such. It should not be possible to modify these initializer
42+
constants.
43+
44+
The current design is that we have only one keyword, `static`, which
45+
declares a global variable. By default, global variables do not have a
46+
significant address and can be inlined into the program. You can make
47+
a global variable have a *significant* address by marking it
48+
`#[inline(never)]`. Furthermore, you can declare a mutable global
49+
using `static mut`: all accesses to `static mut` variables are
50+
considered unsafe. Because we wish to allow `static` values to be
51+
placed in read-only memory, they are forbidden from having a type that
52+
includes interior mutable data (that is, an appearance of `UnsafeCell`
53+
type).
54+
55+
Some concrete problems with this design are:
56+
57+
- There is no way to have a safe global counter or lock. Those must be
58+
placed in `static mut` variables, which means that access to them is
59+
illegal. To resolve this, there is an alternative proposal which
60+
makes access to `static mut` be considered safe if the type of the
61+
static mut meets the `Sync` trait.
62+
- The signifiance (no pun intended) of the `#[inline(never)]` annotation
63+
is not intuitive.
64+
- There is no way to have a generic type constant.
65+
66+
Other less practical and more aesthetic concerns are:
67+
68+
- Although `static` and `let` look and feel analogous, the two behave
69+
quite differently. Generally speaking, `static` declarations do not
70+
declare variables but rather values, which can be inlined and which
71+
do not have a fixed address. You cannot have interior mutability in
72+
a `static` variable, but you can in a `let`. So that `static`
73+
variables can appear in patterns, it is illegal to shadow a `static`
74+
variable -- but `let` variables cannot appear in patterns. Etc.
75+
- There are other constructs in the language, such as nullary enum
76+
variants and nullary structs, which look like global data but in
77+
fact act quite differently. They are actual values which do not have
78+
a address. They are categorized as rvalues and so forth.
79+
80+
# Detailed design
81+
82+
## Constants
83+
84+
Reintroduce a `const` declaration which declares a *constant*:
85+
86+
const name: type = value;
87+
88+
Constants may be declared in any scope. They cannot be shadowed.
89+
Constants are considered rvalues. Therefore, taking the address of a
90+
constant actually creates a spot on the local stack -- they by
91+
definition have no significant address. Constants are intended to
92+
behave exactly like a nullary enum variant.
93+
94+
### Possible extension: Generic constants
95+
96+
As a possible extension, it is perfectly reasonable for constants to
97+
have generic parameters. For example, the following constant is legal:
98+
99+
struct WrappedOption<T> { value: Option<T> }
100+
const NONE<T> = WrappedOption { value: None }
101+
102+
Note that this makes no sense for a `static` variable, which represents
103+
a memory location and hence must have a concrete type.
104+
105+
### Possible extension: constant functions
106+
107+
It is possible to imagine constant functions as well. This could help
108+
to address the problem of encapsulating initialization. To avoid the
109+
need to specify what kinds of code can execute in a constant function,
110+
we can limit them syntactically to a single constant expression that
111+
can be expanded at compilation time (no recursion).
112+
113+
struct LockedData<T:Send> { lock: Lock, value: T }
114+
115+
const LOCKED<T:Send>(t: T) -> LockedData<T> {
116+
LockedData { lock: INIT_LOCK, value: t }
117+
}
118+
119+
This would allow us to make the `value` field on `UnsafeCell` private,
120+
among other things.
121+
122+
## Static variables
123+
124+
Repurpose the `static` declaration to declare static variables
125+
only. Static variables always have a single address. `static`
126+
variables can optionally be declared as `mut`. The lifetime of a
127+
`static` variable is `'static`. It is not legal to move from a static.
128+
Accesses to a static variable generate actual reads and writes: the
129+
value is not inlined (but see "Unresolved Questions" below).
130+
131+
Non-`mut` statics must have a type that meets the `Sync` bound. All
132+
access to the static is considered safe (that is, reading the variable
133+
and taking its address). If the type of the static does not contain
134+
an `UnsafeCell` in its interior, the compiler may place it in
135+
read-only memory, but otherwise it must be placed in mutable memory.
136+
137+
`mut` statics may have any type. All access is considered unsafe.
138+
They may not be placed in read-only memory and their values may
139+
140+
# Drawbacks
141+
142+
This RFC introduces two keywords for global data. Global data is kind
143+
of an edge feature so this feels like overkill. (On the other hand,
144+
the only keyword that most Rust programmers should need to know is
145+
`const` -- I imagine `static` variables will be used quite rarely.)
146+
147+
# Alternatives
148+
149+
The other design under consideration is to keep the current split but
150+
make access to `static mut` be considered safe if the type of the
151+
static mut is `Sync`. For the details of this discussion, please see
152+
[RFC 177](https://github.com/rust-lang/rfcs/pull/177).
153+
154+
One serious concern is with regard to timing. Adding more things to
155+
the Rust 1.0 schedule is inadvisable. Therefore, it would be possible
156+
to take a hybrid approach: keep the current `static` rules, or perhaps
157+
the variation where access to `static mut` is safe, for the time
158+
being, and create `const` declarations after Rust 1.0 is released.
159+
160+
# Unresolved questions
161+
162+
- Should the compiler be allowed to inline the values of `static`
163+
variables which are deeply immutable (and thus force recompilation)?
164+
165+
- Should we permit `static` variables whose type is not `Sync`, but
166+
simply make access to them unsafe?
167+
168+
- How hard are the envisioned extensions to implement? If easy, they
169+
would be nice to have. If hard, they can wait.

0 commit comments

Comments
 (0)