rust-lang / rust-lang/rfcs

More implicit bounds (?Sized, ?DynSized, ?Move)

Open
#2,255 31 comments 10 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

T-lang
Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

The concept of implicit bound was introduced together with dynamic sized type. While having a : Sized bound is more specialized than no bound at all, we expect that : Sized is much more common, and thus should be present by default. We introduced the : ?Sized syntax in #490 to opt-out of this default bound. The syntax : ?Sized is called "relaxed bound".

Later, new RFCs and PRs tried to introduce more traits like Sized which the common case is "this should be implemented", e.g.

  • #1858 and rust-lang/rust#44917 introduced the ?Move bound, since most types do not contain internal references and thus can be freely moved around.
  • #1993 and rust-lang/rust#46108 introduced the ?DynSized bound, since most types have known size and alignment at runtime.
  • https://gankro.github.io/blah/linear-rust (semiseriously) introduced the ?Leave bound, since most types can be drop'ed.

These traits themselves are often necessary at language level beyond trait bounds, e.g. Move is needed for immovable generators (for lack of a better solution), DynSized is needed to reject struct tails without known alignment, and Leave is needed to support linear type.

However, the expansion of implicit bounds experienced push back from lang team due to ergonomic cost, that

  • ?Sized itself being a "negative feature" confuses users, adding ?Move and ?DynSized will only make the situation worse,

  • introducing new relaxed bound means downstream packages will need to reevaluate every API to see if adding : ?Trait makes sense, and this needs to be done for every new relaxed bound.

  • the necessity of Move and DynSized is orthogonal to whether they need to be default.

  • the backward-compatibility may be a lie 🍰 — Relaxing the bounds in associated type, in particular FnOnce::Output, means the user of the trait will get less promises, which is a breaking change:

    let should_be_movable: Closure::Output = closure();
    let but_it_errored = should_be_movable;
    

    Essentially, the bounds on an associated type cannot be added (which breaks implementers) or removed (which breaks users).

So the questions are,

  • Should we embrace ?Trait and allow language to grow more similar traits, despite the stated problems above?
  • If we decide to stop at ?Sized, what else should we do regarding Move and DynSized?
  • Would there be a balanced solution in the middle of the two extremes?

I am filing this issue here to Move the discussion from those two different PRs to a potentially more proper place, as it seems having a non-Sized relaxed bound itself should require more discussion around the language design.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with this issue and the linked discussions for #1858, #1993, rust-lang/rust#44917, rust-lang/rust#46108, and the referenced pull requests. Review the arguments around ?Sized, ?Move, and ?DynSized; done would require a settled language-design direction addressing whether additional implicit bounds should be introduced and what to do about the existing bounds.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.