- Start Date: 2014-10-13
- RFC PR: rust-lang/rfcs#379
- Rust Issue: rust-lang/rust#18046
Summary
- Remove reflection from the compiler
- Remove
libdebug
- Remove the
Poly
format trait as well as the:?
format specifier
Motivation
In ancient Rust, one of the primary methods of printing a value was via the %?
format specifier. This would use reflection at runtime to determine how to print
a type. Metadata generated by the compiler (a TyDesc
) would be generated to
guide the runtime in how to print a type. One of the great parts about
reflection was that it was quite easy to print any type. No extra burden was
required from the programmer to print something.
There are, however, a number of cons to this approach:
- Generating extra metadata for many many types by the compiler can lead to noticeable increases in compile time and binary size.
- This form of formatting is inherently not speedy. Widespread usage of
%?
led to misleading benchmarks about formatting in Rust. - Depending on how metadata is handled, this scheme makes it very difficult to allow recompiling a library without recompiling downstream dependants.
Over time, usage off the ?
formatting has fallen out of fashion for the
following reasons:
- The
deriving
-based infrastructure was improved greatly and has started seeing much more widespread use, especially for traits likeClone
. - The formatting language implementation and syntax has changed. The most common
formatter is now
{}
(an implementation ofShow
), and it is quite common to see an implementation ofShow
on nearly all types (frequently viaderiving
). This form of customizable-per-typformatting largely provides the gap that the original formatting language did not provide, which was limited to only primitives and%?
. - Compiler built-ins, such as
~[T]
and~str
have been removed from the language, and runtime reflection onVec<T>
andString
are far less useful (they just print pointers, not contents).
As a result, the :?
formatting specifier is quite rarely used today, and
when it is used it’s largely for historical purposes and the output is not of
very high quality any more.
The drawbacks and today’s current state of affairs motivate this RFC to recommend removing this infrastructure entirely. It’s possible to add it back in the future with a more modern design reflecting today’s design principles of Rust and the many language changes since the infrastructure was created.
Detailed design
- Remove all reflection infrastructure from the compiler. I am not personally
super familiar with what exists, but at least these concrete actions will be
taken.
- Remove the
visit_glue
function fromTyDesc
. - Remove any form of
visit_glue
generation. - (maybe?) Remove the
name
field ofTyDesc
.
- Remove the
- Remove
core::intrinsics::TyVisitor
- Remove
core::intrinsics::visit_tydesc
- Remove
libdebug
- Remove
std::fmt::Poly
- Remove the
:?
format specifier in the formatting language syntax.
Drawbacks
The current infrastructure for reflection, although outdated, represents a significant investment of work in the past which could be a shame to lose. While present in the git history, this infrastructure has been updated over time, and it will no longer receive this attention.
Additionally, given an arbitrary type T
, it would now be impossible to print
it in literally any situation. Type parameters will now require some bound, such
as Show
, to allow printing a type.
These two drawbacks are currently not seen as large enough to outweigh the gains
from reducing the surface area of the std::fmt
API and reduction in
maintenance load on the compiler.
Alternatives
The primary alternative to outright removing this infrastructure is to preserve
it, but flag it all as #[experimental]
or feature-gated. The compiler could
require the fmt_poly
feature gate to be enabled to enable formatting via :?
in a crate. This would mean that any backwards-incompatible changes could
continue to be made, and any arbitrary type T
could still be printed.
Unresolved questions
- Can
core::intrinsics::TyDesc
be removed entirely?