Skip to content

Commit 221414d

Browse files
committed
RFC: Array pattern adjustments
1 parent 138a079 commit 221414d

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

text/0000-array-pattern-changes.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
- Start Date: 2014-12-03
2+
- RFC PR: (leave this empty)
3+
- Rust Issue: (leave this empty)
4+
5+
Summary
6+
=======
7+
8+
Change array/slice patterns in the following ways:
9+
10+
- Make them only match on arrays (`[T, ..n]` and `[T]`), not slices;
11+
- Make subslice matching yield a value of type `[T, ..n]` or `[T]`, not `&[T]`
12+
or `&mut [T]`;
13+
- Allow multiple mutable references to be made to different parts of the same
14+
array or slice in array patterns (resolving rust-lang/rust [issue
15+
#8636](https://github.com/rust-lang/rust/issues/8636)).
16+
17+
Motivation
18+
==========
19+
20+
Before DST (and after the removal of `~[T]`), there were only two types based on
21+
`[T]`: `&[T]` and `&mut [T]`. With DST, we can have many more types based on
22+
`[T]`, `Box<[T]>` in particular, but theoretically any pointer type around a
23+
`[T]` could be used. However, array patterns still match on `&[T]`, `&mut [T]`,
24+
and `[T, ..n]` only, meaning that to match on a `Box<[T]>`, one must first
25+
convert it to a slice, which disallows moves. This may prove to significantly
26+
limit the amount of useful code that can be written using array patterns.
27+
28+
Another problem with today’s array patterns is in subslice matching, which
29+
specifies that the rest of a slice not matched on already in the pattern should
30+
be put into a variable:
31+
32+
```rust
33+
let foo = [1i, 2, 3];
34+
match foo {
35+
[head, tail..] => {
36+
assert_eq!(head, 1);
37+
assert_eq!(tail, &[2, 3]);
38+
},
39+
_ => {},
40+
}
41+
```
42+
43+
This makes sense, but still has a few problems. In particular, `tail` is a
44+
`&[int]`, even though the compiler can always assert that it will have a length
45+
of `2`, so there is no way to treat it like a fixed-length array. Also, all
46+
other bindings in array patterns are by-value, whereas bindings using subslice
47+
matching are by-reference (even though they don’t use `ref`). This can create
48+
confusing errors because of the fact that the `..` syntax is the only way of
49+
taking a reference to something within a pattern without using the `ref`
50+
keyword.
51+
52+
Finally, the compiler currently complains when one tries to take multiple
53+
mutable references to different values within the same array in a slice pattern:
54+
55+
```rust
56+
let foo: &mut [int] = &mut [1, 2, 3];
57+
match foo {
58+
[ref mut a, ref mut b] => ...,
59+
...
60+
}
61+
```
62+
63+
This fails to compile, because the compiler thinks that this would allow
64+
multiple mutable borrows to the same value (which is not the case).
65+
66+
Detailed design
67+
===============
68+
69+
- Make array patterns match only on arrays (`[T, ..n]` and `[T]`). For example,
70+
the following code:
71+
72+
```rust
73+
let foo: &[u8] = &[1, 2, 3];
74+
match foo {
75+
[a, b, c] => ...,
76+
...
77+
}
78+
```
79+
80+
Would have to be changed to this:
81+
82+
```rust
83+
let foo: &[u8] = &[1, 2, 3];
84+
match foo {
85+
&[a, b, c] => ...,
86+
...
87+
}
88+
```
89+
90+
This change makes slice patterns mirror slice expressions much more closely.
91+
92+
- Make subslice matching in array patterns yield a value of type `[T, ..n]` (if
93+
the array is of fixed size) or `[T]` (if not). This means changing most code
94+
that looks like this:
95+
96+
```rust
97+
let foo: &[u8] = &[1, 2, 3];
98+
match foo {
99+
[a, b, c..] => ...,
100+
...
101+
}
102+
```
103+
104+
To this:
105+
106+
```rust
107+
let foo: &[u8] = &[1, 2, 3];
108+
match foo {
109+
&[a, b, ref c..] => ...,
110+
...
111+
}
112+
```
113+
114+
It should be noted that if a fixed-size array is matched on using subslice
115+
matching, and `ref` is used, the type of the binding will be `&[T, ..n]`,
116+
*not* `&[T]`.
117+
118+
- Improve the compiler’s analysis of multiple mutable references to the same
119+
value within array patterns. This would be done by allowing multiple mutable
120+
references to different elements of the same array (including bindings from
121+
subslice matching):
122+
123+
```rust
124+
let foo: &mut [u8] = &mut [1, 2, 3, 4];
125+
match foo {
126+
&[ref mut a, ref mut b, ref c, ref mut d..] => ...,
127+
...
128+
}
129+
```
130+
131+
Drawbacks
132+
=========
133+
134+
- This will break a non-negligible amount of code, requiring people to add `&`s
135+
and `ref`s to their code.
136+
137+
- The modifications to subslice matching will require `ref` or `ref mut` to be
138+
used in almost all cases. This could be seen as unnecessary.
139+
140+
Alternatives
141+
============
142+
143+
- Do a subset of this proposal; for example, the modifications to subslice
144+
matching in patterns could be removed.
145+
146+
Unresolved questions
147+
====================
148+
149+
- What are the precise implications to the borrow checker of the change to
150+
multiple mutable borrows in the same array pattern? Since it is a
151+
backwards-compatible change, it can be implemented after 1.0 if it turns out
152+
to be difficult to implement.

0 commit comments

Comments
 (0)