Skip to content

Make the implicit type parameter Self have no default Sized bound #546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 4, 2015

Conversation

nikomatsakis
Copy link
Contributor

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.

Rendered view.

@japaric
Copy link
Member

japaric commented Dec 30, 2014

👍

Traits applicable to DST by default, and opt-out via the Trait: Sized bound makes sense to me and feel more natural that "anti-bounds": Trait: ?Sized.

@Kimundi
Copy link
Member

Kimundi commented Dec 30, 2014

Hm... How does that interact with possible future default-implied traits? Eg, the hypothetical Movable to express that a type can (not) be moved?

Specifically, would such an addition still require something similar to the trait Foo for ?Movable syntax for default methods to be correct?

@pythonesque
Copy link
Contributor

@Kimundi I can't speak for other default types, but I think ?Movable can be added backwards compatibly without reintroducing such syntax.

For starters, I believe that if it is defined correctly, Movable is a subtype of Sized (that is, T: Movable => T: Sized). Observe that all primitive types are sized, except for slices and trait objects. Including one of those two forms directly in a struct (not behind a pointer) is the only way of making a new unsized types. And coercing from Foo<Sized? T>, &T, or &mut T where the particular instance of T is sized to Foo<U>, &U or &mut U where U is unsized is the only way of actually instantiating a type whose signature includes an unsized type in it. It is not possible to move out of &mut U, &U, or Foo<U> where U is unsized (this is because the intrinsics required to do this, such as those used in mem::swap, all have an implicit Sized bound). And all local variables must have a statically known size, so T can never be moved by direct assignment. Thus, we conclude that if T is not Sized, T is not Movable; hence, T: Movable => T: Sized.

(For a more direct demonstration that this is supposed to be the case, by abusing Box sufficiently you can get this error: "cannot move a value of type std::io::Reader: the size of std::io::Reader cannot be statically determined [E0161]").

In current Rust, the reverse is also true (Sized => Movable). This opens up the interesting backwards-compatible possibility of defining current Sized to embody Movable, by having it inherit from ?Frozen, which is essentially "Sized and potentially immovable." Then the defaults wouldn't actually have to change: after this RFC, T: Sized (the default for non-Self type parameters) means "movable [and sized, by implication]", T: ?Sized (in where clauses and the default for Self type parameters) means "potentially immovable [and therefore, potentially unsized]", and if you explicitly required "sized but potentially immovable" (which would only be a bound in new functions, hence not a backwards compatibility concern), you would use an explicit bound of ?Frozen.

The biggest problem with this is that I see is that the name ?Frozen is bad. Hypothetically, it would be nicer if we renamed current Sized to Movable. Then we could have the traits look like: Movable is the default for non-Self type parameters, Movable? is the default for Self type parameters, and if in the future we wanted to add types that were movable and not sized, we could define a Sized trait (such that Movable: Sized) which would serve the same role as ?Frozen ("Sized and potentially immovable") but with a much clearer name.

Is this thought worth pursuing? Should we consider renaming Sized to Movable? Or am I missing edge cases that make this a bad idea?

@nikomatsakis
Copy link
Contributor Author

@pythonesque I intend to allow unsized types to be moved (via parameter passing only) in the future. It simplifies and cleans up a lot of things.

@pythonesque
Copy link
Contributor

Ah, okay, interesting. That line of reasoning doesn't work, then :P Anyway, I like the RFC. It seems much saner.

@comex
Copy link

comex commented Jan 1, 2015

You say it only affects default implementations; does that mean it doesn't prevent traits not inheriting Sized from having methods taking or returning values of type Self?

@nikomatsakis
Copy link
Contributor Author

@comex at the moment, it does not, no. There was some discussion about this point at the weekly meeting, though of course the minutes don't cover it in detail (sigh, taking minutes is hard). The compiler as implemented today, at least, only enforces sizedness of parameters (and some other criteria) on the impl side, or at least only on fns with bodies. Going forward, I'd like generally to move to implied bounds which would formalize this idea even further (but of course that's not been formally proposed).

@Ericson2314
Copy link
Contributor

What if input trait parameters also had no Size bound? Trait params would be different from other type params, but at least they would be consistent with Self.

@brson
Copy link
Contributor

brson commented Jan 4, 2015

Though this RFC has been up a short time, and hasn't had a great deal of discussion, it needs to be done fast and most people I've heard from seem to be in favor. Merged. Tracking.

@Centril Centril added A-traits Trait system related proposals & ideas A-typesystem Type system related proposals & ideas labels Nov 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-traits Trait system related proposals & ideas A-typesystem Type system related proposals & ideas
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants