2015-01-04 09:29:47 +08:00
|
|
|
- Start Date: 2015-01-03
|
|
|
|
- RFC PR: [rust-lang/rfcs#546](https://github.com/rust-lang/rfcs/pull/546)
|
|
|
|
- Rust Issue: [rust-lang/rust#20497](https://github.com/rust-lang/rust/issues/20497)
|
2014-12-24 04:17:25 +08:00
|
|
|
|
|
|
|
# Summary
|
|
|
|
|
|
|
|
1. Remove the `Sized` default for the implicitly declared `Self`
|
|
|
|
parameter on traits.
|
|
|
|
2. Make it "object unsafe" for a trait to inherit from `Sized`.
|
|
|
|
|
|
|
|
# Motivation
|
|
|
|
|
|
|
|
The primary motivation is to enable a trait object `SomeTrait` to
|
|
|
|
implement the trait `SomeTrait`. This was the design goal of enforcing
|
|
|
|
object safety, but there was a detail that was overlooked, which this
|
|
|
|
RFC aims to correct.
|
|
|
|
|
|
|
|
Secondary motivations include:
|
|
|
|
|
|
|
|
- More generality for traits, as they are applicable to DST.
|
|
|
|
- Eliminate the confusing and irregular `impl Trait for ?Sized`
|
|
|
|
syntax.
|
|
|
|
- Sidestep questions about whether the `?Sized` default is inherited
|
|
|
|
like other supertrait bounds that appear in a similar position.
|
|
|
|
|
|
|
|
This change has been implemented. Fallout within the standard library
|
|
|
|
was quite minimal, since the default only affects default method
|
|
|
|
implementations.
|
|
|
|
|
|
|
|
# Detailed design
|
|
|
|
|
|
|
|
Currently, all type parameters are `Sized` by default, including the
|
|
|
|
implicit `Self` parameter that is part of a trait definition. To avoid
|
|
|
|
the default `Sized` bound on `Self`, one declares a trait as follows
|
|
|
|
(this example uses the syntax accepted in [RFC 490] but not yet
|
|
|
|
implemented):
|
|
|
|
|
|
|
|
```rust
|
|
|
|
trait Foo for ?Sized { ... }
|
|
|
|
```
|
|
|
|
|
|
|
|
This syntax doesn't have any other precendent in the language. One
|
|
|
|
might expect to write:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
trait Foo : ?Sized { ... }
|
|
|
|
```
|
|
|
|
|
|
|
|
However, placing `?Sized` in the supertrait listing raises awkward
|
|
|
|
questions regarding inheritance. Certainly, when experimenting with
|
2015-01-03 01:10:53 +08:00
|
|
|
this syntax early on, we found it very surprising that the `?Sized`
|
|
|
|
bound was "inherited" by subtraits. At the same time, it makes no
|
|
|
|
sense to inherit, since all that the `?Sized` notation is saying is
|
|
|
|
"do not add `Sized`", and you can't inherit the absence of a
|
2014-12-24 04:17:25 +08:00
|
|
|
thing. Having traits simply not inherit from `Sized` by default
|
|
|
|
sidesteps this problem altogether and avoids the need for a special
|
2020-05-16 13:08:09 +08:00
|
|
|
syntax to suppress the (now absent) default.
|
2014-12-24 04:17:25 +08:00
|
|
|
|
|
|
|
Removing the default also has the benefit of making traits applicable
|
|
|
|
to more types by default. One particularly useful case is trait
|
|
|
|
objects. We are working towards a goal where the trait object for a
|
|
|
|
trait `Foo` always implements the trait `Foo`. Because the type `Foo`
|
|
|
|
is an unsized type, this is naturally not possible if `Foo` inherits
|
|
|
|
from `Sized` (since in that case every type that implements `Foo` must
|
|
|
|
also be `Sized`).
|
|
|
|
|
|
|
|
The impact of this change is minimal under the current rules. This is
|
|
|
|
because it only affects default method implementations. In any actual
|
|
|
|
impl, the `Self` type is bound to a specific type, and hence it known
|
|
|
|
whether or not that type is `Sized`. This change has been implemented
|
|
|
|
and hence the fallout can be seen on [this branch] (specifically,
|
|
|
|
[this commit] contains the fallout from the standard library). That
|
|
|
|
same branch also implements the changes needed so that every trait
|
|
|
|
object `Foo` implements the trait `Foo`.
|
|
|
|
|
|
|
|
[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
|
|
|
|
[RFC 490]: https://github.com/rust-lang/rfcs/blob/master/text/0490-dst-syntax.md
|
2014-12-24 04:23:12 +08:00
|
|
|
[this branch]: https://github.com/nikomatsakis/rust/tree/impl-trait-for-trait-2
|
2014-12-24 04:17:25 +08:00
|
|
|
[this commit]: https://github.com/nikomatsakis/rust/commit/d08a08ab82031b6f935bdaf160a28d9520ded1ab
|
|
|
|
|
|
|
|
# Drawbacks
|
|
|
|
|
|
|
|
The `Self` parameter is inconsistent with other type parameters if we
|
2015-01-03 01:10:53 +08:00
|
|
|
adopt this RFC. We believe this is acceptable since it is
|
2014-12-24 04:17:25 +08:00
|
|
|
syntactically distinguished in other ways (for example, it is not
|
|
|
|
declared), and the benefits are substantial.
|
|
|
|
|
|
|
|
# Alternatives
|
|
|
|
|
|
|
|
- Leave `Self` as it is. The change to object safety must be made in
|
|
|
|
any case, which would mean that for a trait object `Foo` to
|
|
|
|
implement the trait `Foo`, it would have to be declared `trait Foo
|
|
|
|
for Sized?`. Indeed, that would be necessary even to create a trait
|
|
|
|
object `Foo`. This seems like an untenable burden, so adopting this
|
|
|
|
design choice seems to imply reversing the decision that all trait
|
|
|
|
objects implement their respective traits ([RFC 255]).
|
|
|
|
|
|
|
|
- Remove the `Sized` defaults altogether. This approach is purer, but
|
2015-01-03 01:10:53 +08:00
|
|
|
the annotation burden is substantial. We continue to experiment in
|
|
|
|
the hopes of finding an alternative to current blanket default, but
|
|
|
|
without success thus far (beyond the idea of doing global
|
|
|
|
inference).
|
2014-12-24 04:17:25 +08:00
|
|
|
|
|
|
|
# Unresolved questions
|
|
|
|
|
|
|
|
- None.
|