Summary

Introduce

導入する
a new dyn Trait syntax
文法
for trait objects using a contextual dyn keyword, and deprecate "bare trait" syntax
文法
for trait objects. In a future edition, dyn will become a proper keyword and a lint against bare trait syntax
文法
will become deny-by-default.

Motivation

In a nutshell

The current syntax

文法
is often ambiguous and confusing, even to veterans, and favors a feature that is not more frequently used than its alternatives,
代わりのもの、選択肢
is sometimes slower, and often cannot be used at all when its alternatives
代わりのもの、選択肢
can. By itself, that's not enough to make a breaking change to syntax
文法
that's already been stabilized. Now that we have editions, it won't have to be a breaking change, but it will still cause
起こす
significant churn. However, impl Trait is going to require a significant shift in idioms and teaching materials all on its own, and "dyn Trait vs impl Trait" is much nicer for teaching and ergonomics than "bare trait vs impl Trait", so this author believes it is worthwhile to change trait object syntax
文法
too.

Motivation is the key issue for this RFC, so let's expand on some of those claims:

The current syntax
文法
is often ambiguous and confusing

Because it makes traits and trait objects appear

現れる
indistinguishable. Some specific
特定の
examples of this:

  • This author has seen multiple
    複数の
    people write impl SomeTrait for AnotherTrait when they wanted impl<T> SomeTrait for T where T: AnotherTrait.
  • impl MyTrait {} is valid
    有効な、正しい
    syntax,
    文法
    which can easily be mistaken for adding
    たす
    default impls of methods or adding
    たす
    extension methods or some other useful operation
    演算、操作
    on the trait itself. In reality, it adds inherent methods to the trait object.
  • Function types and function traits only differ in the capitalization of one letter.
    文字
    This leads to function pointers &fn ... and function trait objects &Fn ... differing only in one letter,
    文字
    making it very easy to mistake one for the other.

Making one of these mistakes typically

一般的に、典型的に
leads to an error about the trait not implementing
実装する
Sized, which is at best misleading and unhelpful. It may be possible to produce
産出する
better error messages today, but the compiler can only do so much when most of this "obviously wrong" syntax
文法
is technically legal.
(文法的に)適格

favors a feature that is not more frequently used than its alternatives
代わりのもの、選択肢

When you want to store multiple

複数の
types within a single
単一の
value or a single
単一の
container of values, an enum is often a better choice than a trait object.

When you want to return a type implementing

実装する
a trait without writing out the type's name--either because it can't be written, or it's too unergonomic to write--you should typically
一般的に、典型的に
use impl Trait (once it stabilizes).

When you want a function to accept

受け付ける、受理する
any type of value that implements
実装する
a certain trait, you should typically
一般的に、典型的に
use generics.

There are many cases where trait objects are the best solution, but they're not more common than all of the above. Usually trait objects become the best solution when you want to do two or more of the things listed

リスト、列挙する
above, e.g. you have an API that accepts
受け付ける、受理する
values of types defined
定義する
by external code, and it has to deal with more than one of those types at a time.

favors a feature that ... is sometimes slower

Trait objects typically

一般的に、典型的に
require allocating
確保する
memory and doing virtual dispatch at runtime. They also prevent
防ぐ
the compiler from knowing the concrete
具体的な/具象的な
type of a value, which may inhibit other optimizations. Sometimes these costs are unnoticeable in practice, or even optimized away entirely, but sometimes they have a significant impact on performance.

enums and impl Trait simply don't have these costs. It's strange that the more concise syntax

文法
gives you a feature that is often slower and rarely faster than its alternatives.
代わりのもの、選択肢

favors a feature that ... often cannot be used at all when its alternatives
代わりのもの、選択肢
can

Many traits simply can't have trait objects at all, because they don't meet the object safety rules.

In contrast,

対比する、対比
impl Trait and generics work with any trait. It's strange that the more concise syntax
文法
gives you the feature that's least likely to compile.

impl Trait is going to require a significant shift in idioms and teaching materials all on its own

Today, when you want to return a type implementing

実装する
a trait without writing out the type's name, you typically
一般的に、典型的に
Box a trait object and accept
受け付ける、受理する
the potential runtime cost. This includes most functions that return closures, iterators, futures, or combinations thereof. Most of those functions should switch to impl Trait once that syntax
文法
stabilizes and becomes the preferred idiomatic way of doing this, including many public API methods.

The way we teach the trait system will also have to change to describe impl Trait alongside all the existing ways of using traits via generics and trait objects, and explain when impl Trait is preferable to those and other options like enums. Moreover,

その上
the way we teach closures, iterators and futures will likely need to mention why impl Trait is useful for those types and use impl Trait in many examples, as well as when impl Trait isn't enough and you do need dyn Trait after all.

Ideally, introducing dyn Trait won't create much additional

追加の
churn on top of impl Trait, since these idiom shifts and documentation
文書
rewrites can account for both of those changes together.

"dyn Trait vs impl Trait" is much nicer for teaching and ergonomics than "bare trait vs impl Trait"

There's a natural parallel between the impl/dyn keywords and static/dynamic dispatch that we'll likely mention in The Book. Having a keyword for both kinds of dispatch correctly implies

暗黙の
that both are important and choosing between the two is often non-trivial, while today's syntax
文法
may give the incorrect impression that trait objects are the default and impl Trait is a more niche feature.

After impl Trait stabilizes, it will become more common to accidentally write a trait object without realizing it by forgetting the impl keyword. This often leads to unhelpful and cryptic errors about your trait not implementing

実装する
Sized. With a switch to dyn Trait, these errors could become as simple and self-evident as "expected a type, found a trait, did you mean to write impl Trait?".

Explanation

The functionality of dyn Trait is identical

同一の(である)
to today's trait object syntax.
文法

Box<Trait> becomes Box<dyn Trait>.

&Trait and &mut Trait become &dyn Trait and &mut dyn Trait.

Migration

On the current edition:

  • The dyn keyword will be added,
    たす
    and will be a contextual keyword
  • A lint against bare trait syntax
    文法
    will be added
    たす

In the next edition:

  • dyn becomes a real keyword, uses of it as an identifier
    識別子
    become hard errors
  • The bare trait syntax
    文法
    lint is raised to deny-by-default

This follows

下記の、次に続く、追従する
the policy laid out in the editions RFC, where a hard error is "only available when the deprecation is expected to hit a relatively small percentage of code." Adding
たす
the dyn keyword is unlikely to affect much code, but removing bare trait syntax
文法
will clearly affect a lot of code, so only the latter change is implemented
実装する
as a deny-by-default lint.

Drawbacks

  • Yet another (temporarily contextual) keyword.

  • Code that uses trait objects becomes slightly more verbose.

  • &dyn Trait might give the impression that &dyn is a third type of reference

    参照
    alongside & and &mut.

  • In general,

    一般
    favoring generics over trait objects makes Rust code take
    とる
    longer to compile, and this change may encourage more of that.

Rationale and Alternatives
代わりのもの、選択肢

We could use a different keyword such as obj or virtual. There wasn't very much discussion of these options on the original RFC thread, since the motivation was a far bigger concern than the proposed syntax,

文法
so it wouldn't be fair to say there's a consensus for or against any particular keyword.

This author believes that dyn is a better choice because the notion of "dynamic"

動的
typing is familiar to a wide variety of programmers and unlikely to mislead them. obj is likely to incorrectly imply an "object" in the OOP sense, which is very different from a trait object. virtual is a term
項、用語
that may be unfamiliar to programmers whose preferred languages
言語
don't have a virtual keyword or don't even expose the notion of virtual/dynamic dispatch to the programmer, and the languages
言語
that do have a virtual keyword usually use it to mean "this method can be overridden", not "this value uses dynamic
動的
dispatch".

We could also use a more radical syntax

文法
for trait objects. Object<Trait> was suggested on the original RFC thread but didn't gain much traction, presumably because it adds more "noise" than a keyword and is arguably misleading.

Finally, we could repurpose bare trait syntax

文法
for something other than trait objects. It's been frequently suggested in the past that impl Trait would be a far better candidate for bare trait syntax
文法
than trait objects. Even this RFC's motivation section
indirectly argues for this, e.g. impl Trait does work with all traits and does not carry a runtime cost, unlike trait objects. However, this RFC does not propose repurposing bare trait syntax
文法
yet, only deprecating and removing it. This author believes dyn Trait is worth adding
たす
even if we never repurpose bare trait, and repurposing it has some significant downsides that dyn Trait does not (such as creating the possibility of code that compiles in two different editions with radically different semantics). This author believes the repurposing debate should come later, probably after impl Trait and dyn Trait have been stabilized.

Unresolved questions

  • How common are trait objects in real code? There were some requests for hard data on this in the original RFC thread, but none was ever provided.

    与える

  • Does introducing this contextual keyword create any parsing

    構文解析する
    ambiguities?

  • Should we try to write out how The Book would teach impl Trait vs dyn Trait in the future?