Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upMore implicit bounds (?Sized, ?DynSized, ?Move) #2255
Comments
This comment has been minimized.
This comment has been minimized.
I think it will make it better, because sized is right now one single exception. If there are more of it, it becomes more of a rule. |
Centril
added
the
T-lang
label
Dec 22, 2017
This comment has been minimized.
This comment has been minimized.
mikeyhew
commented
Dec 23, 2017
This comment has been minimized.
This comment has been minimized.
|
Relevant: https://gankro.github.io/blah/linear-rust/ (I really would like more implicit bounds, however I am concerned about making things too complicated) |
This comment has been minimized.
This comment has been minimized.
|
Worth noting that while Sized currently is not implied in many cases (e.g. on a trait) we probanly should make things like Move get implied everywhere, and require explicit |
This comment has been minimized.
This comment has been minimized.
|
@Manishearth I'd expect it to be written more often as |
This comment has been minimized.
This comment has been minimized.
|
@mikeyhew thanks, I’ll update it after the holiday. Edit: Fixed links. |
This comment has been minimized.
This comment has been minimized.
crlf0710
commented
Dec 31, 2017
|
Is there a "induction based" solution? I mean, what if
automatically implies
The (naive) idea is that wherever 'move operation' is implied in the method signature, an implicit 'where clause' requiring the type is Move is automatically added on a method basis. The existence of Move bound should automatically assume Sized and DynSized, i think... On the concrete type side, make these auto trait. So they're automatically inferred just like Send and Sync... I wonder if this can work? |
pnkfelix
referenced this issue
Jan 4, 2018
Closed
Immovable types prototype where the Move trait is builtin #44917
This comment has been minimized.
This comment has been minimized.
|
In addition to the concerns @kennytm identified in the original post, it appears that adding additional In terms of usability, the deep problem with these traits is not that they're weird or confusing, but that by their nature they make some question into everyone's problem. Making more of them does not reduce the problem, it multiplies it. Today, it is everyone's problem to know if they really need to know the size of this type at compile time. Tomorrow, we would have everyone also worry about whether they need to know the size at runtime, whether they need to be able to move it after they reference it, and whatever else anyone might propose to use these kinds of traits for. I'm pretty certain we can't add any additional traits like this, and both Fortunately, I think this has been a situation where we have a sledge hammer, and people have picked it up and swung it. That is, both |
kennytm
referenced this issue
Jan 25, 2018
Closed
RFC: DynSized without ?DynSized — Lint against use of `extern type` in `size_of_val`, and more #2310
This comment has been minimized.
This comment has been minimized.
Not all traits are born equal
You need a In fact, the main place that non-data-structure code cares about
On the other hand, the payoff of non-movable types is fairly large - easy safe self-borrowing generators! Because generators sit at the corner of complicated, high-performance, hostile-data-handling code, making them usable safely is a big safety and quality-of-life improvement, possibly even worth an ugly "data structure ecosystem split". NEEDSRESEARCHBTW, I didn't research this, but how bad is the issue with |
This comment has been minimized.
This comment has been minimized.
Moving is a big decisionActually, taking a second look, it might seem that we make That's it, you might think you could have the following mental model:
The reason this is not as perfect as it looks like is that there are actually not that much non-delegating uses of On the other hand, exposing a reference to a type and then moving it is a much rarer thing - there are many places where The "moving is a big decision" problem is a far bigger thing than worries about backwards-compatibility. It makes the mental model for anyone who is writing generic code more complex - do I want to commit to allowing On the other hand, that makes |
This comment has been minimized.
This comment has been minimized.
mikeyhew
commented
Jan 28, 2018
•
|
So, I just posted something over in internals https://internals.rust-lang.org/t/pre-erfc-lets-fix-dsts/6663. There's a lot of stuff in that post, but I had an idea as I was writing that that could help with the issue of Part of that proposal involves adding a
I've taken out So the idea is, Here is an example from the post I linked above: // `T: Referent` makes it clear that `T` is any type that can be pointed to
fn assemble<T: Referent>(data: *const (), meta: T::Meta) -> *const T;I think this makes things easier to reason about. I know @withoutboats was saying that that's not the issue here, but I have a hunch that the It's altogether a reduction in cognitive load, because you stop having to worry about which trait bounds are there that you can't see. (And then if you didn't write any of those traits, I'm not quite sure how this works with |
This comment has been minimized.
This comment has been minimized.
|
@mikeyhew I think (for the specific case of I'm a little confused about how However, I'm doubtful that this generalizes to any ?Trait, as opposed to working for |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
mikeyhew
commented
Jan 28, 2018
No. I mean, theoretically The point of writing
Does that clear things up a bit, or am I just making things worse? |
This comment has been minimized.
This comment has been minimized.
|
I definitely understand the appeal of writing a bound like I think it's confusing only because |
This comment has been minimized.
This comment has been minimized.
|
The only way I see to have all types implement such a trait is use |
This comment has been minimized.
This comment has been minimized.
comex
commented
Jan 31, 2018
•
|
So we have a hierarchy:
Can we avoid the For example, This implies that the following should be illegal for unsafe code:
I'm not worried about 2, but 1 seems like a somewhat arbitrary restriction. However, the benefit would be simplifying the hierarchy: we go from four possibilities to three, at least as far as the vast majority of generic code needs to care. Perhaps we should bring that down to two, and say: even if it becomes possible to move DSTs, most generic code shouldn't bother supporting that because it's not very useful. So the recommendation would be:
edit: |
This comment has been minimized.
This comment has been minimized.
mikeyhew
commented
Feb 2, 2018
Having But
The only difference between this and what you wrote is that |
This comment has been minimized.
This comment has been minimized.
mikeyhew
commented
Feb 2, 2018
|
@lxrec
I hear you. If you're coming at it with the goal of removing all possible trait bounds, or to specify that But in what context would you actually want to do that? Like, when would you have a generic type argument, associated type, or trait Perhaps there are cases where you're writing generic code and you literally have no requirements about the type, you don't even need it to be behind a pointer, but I'd like to see concrete examples. Two that I know of are |
This comment has been minimized.
This comment has been minimized.
|
@withoutboats you say in #2255 (comment) that the general concern less weirdness than making things "everyone's problem". But isn't it the other way around? Once can always ignore |
This comment has been minimized.
This comment has been minimized.
mikeyhew
commented
Apr 16, 2018
|
I had an idea that might be able to help with the ergonomics of Making default bounds a first-class language feature that libraries can use, instead of a special case for only a handful of builtin traits, would hopefully make them less confusing. It would also pave the way for changing which traits are default bounds in a new |
kennytm commentedDec 22, 2017
•
edited
The concept of implicit bound was introduced together with dynamic sized type. While having a
: Sizedbound is more specialized than no bound at all, we expect that: Sizedis much more common, and thus should be present by default. We introduced the: ?Sizedsyntax in #490 to opt-out of this default bound. The syntax: ?Sizedis called "relaxed bound".Later, new RFCs and PRs tried to introduce more traits like
Sizedwhich the common case is "this should be implemented", e.g.?Movebound, since most types do not contain internal references and thus can be freely moved around.?DynSizedbound, since most types have known size and alignment at runtime.?Leavebound, since most types can bedrop'ed.These traits themselves are often necessary at language level beyond trait bounds, e.g.
Moveis needed for immovable generators (for lack of a better solution),DynSizedis needed to reject struct tails without known alignment, andLeaveis needed to support linear type.However, the expansion of implicit bounds experienced push back from lang team due to ergonomic cost, that
?Sizeditself being a "negative feature" confuses users, adding?Moveand?DynSizedwill only make the situation worse,introducing new relaxed bound means downstream packages will need to reevaluate every API to see if adding
: ?Traitmakes sense, and this needs to be done for every new relaxed bound.the necessity of
MoveandDynSizedis 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:Essentially, the bounds on an associated type cannot be added (which breaks implementers) or removed (which breaks users).
So the questions are,
?Traitand allow language to grow more similar traits, despite the stated problems above??Sized, what else should we do regardingMoveandDynSized?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-
Sizedrelaxed bound itself should require more discussion around the language design.