Skip to content

Commit bdf52a8

Browse files
committed
Merge pull request #865 from quantheory/associated_const
Update RFC 195 to account for RFC 246.
2 parents 72aac43 + 992550b commit bdf52a8

File tree

1 file changed

+70
-21
lines changed

1 file changed

+70
-21
lines changed

text/0195-associated-items.md

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ more convenient, scalable, and powerful. In particular, traits will consist of a
99
set of methods, together with:
1010

1111
* Associated functions (already present as "static" functions)
12-
* Associated statics
12+
* Associated consts
1313
* Associated types
1414
* Associated lifetimes
1515

@@ -20,6 +20,13 @@ This RFC also provides a mechanism for *multidispatch* traits, where the `impl`
2020
is selected based on multiple types. The connection to associated items will
2121
become clear in the detailed text below.
2222

23+
*Note: This RFC was originally accepted before RFC 246 introduced the
24+
distinction between const and static items. The text has been updated to clarify
25+
that associated consts will be added rather than statics, and to provide a
26+
summary of restrictions on the initial implementation of associated
27+
consts. Other than that modification, the proposal has not been changed to
28+
reflect newer Rust features or syntax.*
29+
2330
# Motivation
2431

2532
A typical example where associated items are helpful is data structures like
@@ -173,7 +180,7 @@ provide a distinct `impl` for every member of this family.
173180
Associated types, lifetimes, and functions can already be expressed in today's
174181
Rust, though it is unwieldy to do so (as argued above).
175182

176-
But associated _statics_ cannot be expressed using today's traits.
183+
But associated _consts_ cannot be expressed using today's traits.
177184

178185
For example, today's Rust includes a variety of numeric traits, including
179186
`Float`, which must currently expose constants as static functions:
@@ -190,20 +197,20 @@ trait Float {
190197
}
191198
```
192199

193-
Because these functions cannot be used in static initializers, the modules for
194-
float types _also_ export a separate set of constants as statics, not using
200+
Because these functions cannot be used in constant expressions, the modules for
201+
float types _also_ export a separate set of constants as consts, not using
195202
traits.
196203

197-
Associated constants would allow the statics to live directly on the traits:
204+
Associated constants would allow the consts to live directly on the traits:
198205

199206
```rust
200207
trait Float {
201-
static NAN: Self;
202-
static INFINITY: Self;
203-
static NEG_INFINITY: Self;
204-
static NEG_ZERO: Self;
205-
static PI: Self;
206-
static TWO_PI: Self;
208+
const NAN: Self;
209+
const INFINITY: Self;
210+
const NEG_INFINITY: Self;
211+
const NEG_ZERO: Self;
212+
const PI: Self;
213+
const TWO_PI: Self;
207214
...
208215
}
209216
```
@@ -282,14 +289,14 @@ distinction" below.
282289

283290
## Trait bodies: defining associated items
284291

285-
Trait bodies are expanded to include three new kinds of items: statics, types,
292+
Trait bodies are expanded to include three new kinds of items: consts, types,
286293
and lifetimes:
287294

288295
```
289296
TRAIT = TRAIT_HEADER '{' TRAIT_ITEM* '}'
290297
TRAIT_ITEM =
291298
... <existing productions>
292-
| 'static' IDENT ':' TYPE [ '=' CONST_EXP ] ';'
299+
| 'const' IDENT ':' TYPE [ '=' CONST_EXP ] ';'
293300
| 'type' IDENT [ ':' BOUNDS ] [ WHERE_CLAUSE ] [ '=' TYPE ] ';'
294301
| 'lifetime' LIFETIME_IDENT ';'
295302
```
@@ -352,7 +359,7 @@ external to the trait.
352359

353360
### Defaults
354361

355-
Notice that associated statics and types both permit defaults, just as trait
362+
Notice that associated consts and types both permit defaults, just as trait
356363
methods and functions can provide defaults.
357364

358365
Defaults are useful both as a code reuse mechanism, and as a way to expand the
@@ -424,13 +431,13 @@ We deal with this in a very simple way:
424431

425432
## Trait implementations
426433

427-
Trait `impl` syntax is much the same as before, except that static, type, and
434+
Trait `impl` syntax is much the same as before, except that const, type, and
428435
lifetime items are allowed:
429436

430437
```
431438
IMPL_ITEM =
432439
... <existing productions>
433-
| 'static' IDENT ':' TYPE '=' CONST_EXP ';'
440+
| 'const' IDENT ':' TYPE '=' CONST_EXP ';'
434441
| 'type' IDENT' '=' 'TYPE' ';'
435442
| 'lifetime' LIFETIME_IDENT '=' LIFETIME_REFERENCE ';'
436443
```
@@ -767,7 +774,7 @@ as UFCS-style functions:
767774
trait Foo {
768775
type AssocType;
769776
lifetime 'assoc_lifetime;
770-
static ASSOC_STATIC: uint;
777+
const ASSOC_CONST: uint;
771778
fn assoc_fn() -> Self;
772779

773780
// Note: 'assoc_lifetime and AssocType in scope:
@@ -776,7 +783,7 @@ trait Foo {
776783
fn default_method(&self) -> uint {
777784
// method in scope UFCS-style, assoc_fn in scope
778785
let _ = method(self, assoc_fn());
779-
ASSOC_STATIC // in scope
786+
ASSOC_CONST // in scope
780787
}
781788
}
782789

@@ -875,6 +882,7 @@ trait Foo<Input1, Input2> {
875882
type Output1;
876883
type Output2;
877884
lifetime 'a;
885+
const C: bool;
878886
...
879887
}
880888
```
@@ -887,6 +895,7 @@ T: Foo<I1, I2, Output1 = O1>
887895
T: Foo<I1, I2, Output2 = O2>
888896
T: Foo<I1, I2, Output1 = O1, Output2 = O2>
889897
T: Foo<I1, I2, Output1 = O1, 'a = 'b, Output2 = O2>
898+
T: Foo<I1, I2, Output1 = O1, 'a = 'b, C = true, Output2 = O2>
890899
```
891900

892901
The output constraints must come after all input arguments, but can appear in
@@ -947,20 +956,21 @@ trait Foo<Input1, Input2> {
947956
type Output1;
948957
type Output2;
949958
lifetime 'a;
959+
const C: bool;
950960
...
951961
}
952962
```
953963

954964
Unlike the case for static trait bounds, which do not have to specify any of the
955-
associated types or lifetimes (but do have to specify the input types), trait
956-
object types must specify all of the types:
965+
associated types, lifetimes, or consts, (but do have to specify the input types),
966+
trait object types must specify all of the types:
957967

958968
```rust
959969
fn consume_foo<T: Foo<I1, I2>>(t: T) // this is valid
960970
fn consume_obj(t: Box<Foo<I1, I2>>) // this is NOT valid
961971

962972
// but this IS valid:
963-
fn consume_obj(t: Box<Foo<I1, I2, Output1 = O2, Output2 = O2, 'a = 'static>>)
973+
fn consume_obj(t: Box<Foo<I1, I2, Output1 = O2, Output2 = O2, 'a = 'static, C = true>>)
964974
```
965975

966976
With this design, it is clear that none of the non-`Self` types are erased as
@@ -1190,6 +1200,13 @@ trait Mappable
11901200
While the above demonstrates the versatility of associated types and `where`
11911201
clauses, it is probably too much of a hack to be viable for use in `libstd`.
11921202

1203+
### Associated consts in generic code
1204+
1205+
If the value of an associated const depends on a type parameter (including
1206+
`Self`), it cannot be used in a constant expression. This restriction will
1207+
almost certainly be lifted in the future, but this raises questions outside the
1208+
scope of this RFC.
1209+
11931210
# Staging
11941211

11951212
Associated lifetimes are probably not necessary for the 1.0 timeframe. While we
@@ -1393,3 +1410,35 @@ This seems like a potentially useful feature, and should be unproblematic for
13931410
bounds, but may have implications for vtables that make it problematic for trait
13941411
objects. Whether or not such trait combinations are allowed will likely depend
13951412
on implementation concerns, which are not yet clear.
1413+
1414+
## Generic associated consts in match patterns
1415+
1416+
It seems desirable to allow constants that depend on type parameters in match
1417+
patterns, but it's not clear how to do so while still checking exhaustiveness
1418+
and reachability of the match arms. Most likely this requires new forms of
1419+
where clause, to constrain associated constant values.
1420+
1421+
For now, we simply defer the question.
1422+
1423+
## Generic associated consts in array sizes
1424+
1425+
It would be useful to be able to use trait-associated constants in generic code.
1426+
1427+
```rust
1428+
// Shouldn't this be OK?
1429+
const ALIAS_N: usize = <T>::N;
1430+
let x: [u8; <T>::N] = [0u8; ALIAS_N];
1431+
// Or...
1432+
let x: [u8; T::N + 1] = [0u8; T::N + 1];
1433+
```
1434+
1435+
However, this causes some problems. What should we do with the following case in
1436+
type checking, where we need to prove that a generic is valid for any `T`?
1437+
1438+
```rust
1439+
let x: [u8; T::N + T::N] = [0u8; 2 * T::N];
1440+
```
1441+
1442+
We would like to handle at least some obvious cases (e.g. proving that
1443+
`T::N == T::N`), but without trying to prove arbitrary statements about
1444+
arithmetic. The question of how to do this is deferred.

0 commit comments

Comments
 (0)