-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
overloaded-box
and placement-in
#809
overloaded-box
and placement-in
#809
Conversation
👍 I am happy with this compromise (stable intentions, unstable protocol). |
the `<place-expr>` to determine what placement code to run. | ||
|
||
* The only stablized implementation for the `box <expr>` operator | ||
proposed by this RFC is `Box<T>`. The question of which other types |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, does this affect inference in an adverse way if we add later implementations to support box
expressions creating Rc<T>
and Arc<T>
? For example, would this compile successfully today with only one implementation, but fail with many implementations?
drop(box 3);
If we only have one implementation of boxing, does this mean that we'll successfully resolve this to Box<i32>
vs Rc<i32>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good question; I had assumed that the coherence rules would ensure that drop(box 3)
would be rejected, but its possible I misremember/misunderstand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it will too, I just haven't kept up with all the coherence rules and trait selection recently! FWIW this does not compile:
pub trait Foo {
fn make() -> Self;
}
impl Foo for i32 {
fn make() -> i32 { 2 }
}
fn main() {
drop(Foo::make());
}
foo.rs:10:5: 10:9 error: unable to infer enough type information about `_`; type annotations required [E0282]
foo.rs:10 drop(Foo::make());
^~~~
error: aborting due to previous error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(in the prototype from the Appendix, if you add
drop(box_!( 7 ));
it fails to compile, with the message
<anon>:36:13: 36:22 error: unable to infer enough type information about `_`; type annotations required [E0282]
<anon>:36 let mut place = ::protocol::BoxPlace::make_place();
^~~~~~~~~
So, a terrible error message, but that does jibe with my hypothesis that such code would be rejected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, sounds good to me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexcrichton I am assuming we will add implementations for Rc
and Arc
once the protocol exists, so this concern is somewhat moot.
Will this land behind a feature gate? |
use std::rc::Rc; | ||
|
||
let mut v = vec![1,2]; | ||
in (v.emplace_back()) 3; // has return type `()` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer in(v.back()) 3
, fwiw, as "emplace" is just a longer way of conveying the same thing in
does.
Also it could return &mut T
, but I may be mistaken.
This is straying a bit from the topic at hand, and I'm not sure what will come of it, but I have the start of a design that makes *v.back() = 3
possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding names and return types: The beauty of the approach of this RFC is to try to avoid spending time right now quibbling over these kinds of details, which are the topic of library design and not language design. (Having said that, I am not attached to any particular names here.)
The reason I said "has return type ()
was mostly to make it clear that the API can be made flexible enough so that the in (<place-expr>) <expr>
form is usable even in scenarios where it is solely used for imperative update and not for its return value.
Regarding making *v.back() = 3
possible: Okay, that's good, but I do not think such a feature will make the need for placement-in
obsolete. (It would, I guess, obsolete its use in this example of Vec::emplace_back
.)
@brson asked:
Hmm. So my gut reaction is "yes; shouldn't everything land behind a feature gate?" But another (more important) way to interpret your question is as follows:
(Where "this", I believe, refers to the I would like to try to ensure we have a beta cycle with the syntax unfeature-gated. Otherwise, its not clear why we would attempt to put it into the 1.0 release at all. |
Has anyone considered using |
@netvl a large host of syntaxes have been considered. I guess I should have referenced those discussions in the RFC. See e.g. https://github.com/pnkfelix/rfcs/blob/fsk-placement-box-rfc/text/0000-placement-box.md#same-semantics-but-different-surface-syntax which does list One particular constraint I am interested in maintaining is: The evaluation order should reflect the order of expressions in the syntax. Also the author of #405 points out another drawback: the (Meanwhile, the other alternative of |
@netvl another problem with syntaxes that have an optional suffix is that they tend to induce ambiguity. For example, |
👍 on the semantic, but 👎 on the placement
While in (v.emplace_back()) 3;
// feels like, what? "In... emplace to v's back, 3. ...?"
// looks like a strange version of `v.emplace_back(3);`?
// then why can't we use `v.emplace_back(3);` etc. etc.
let b6 = in (HEAP) 6;
// feels like, check if 6 is in the HEAP? Just some alternatives I feel more natural, if the order is required to be placer → expression: // use `box in` phrase. that is, `box expression in[to] place`.
box in (v.end()) 1 + 2 + 3;
let b6 = box in (HEAP) 4 + 5 + 6;
// more rearrangements. already mentioned by pnkfelix.
// the `box` keyword is *required* for human to get the correct context.
in v.end() box 1 + 2 + 3;
let b6 = in HEAP box 4 + 5 + 6;
// reuse `move` keyword. should have no conflict with `move |x| y + x`.
// but sounds like going to move the placer instead of the expression.
// misnomer since nothing is actually moved.
move (v.end()) 1 + 2 + 3;
let b6 = move (HEAP) 4 + 5 + 6;
// use `move in` phrase. a bit too verbose, but make it clear that the placer
// is the target. rearranged from `move expression in[to] place`.
move in (v.end()) 1 + 2 + 3;
let b6 = move in (HEAP) 4 + 5 + 6;
// use a new operator. free to define whatever it means, but hard to learn about it.
v.end() <| 1 + 2 + 3;
let b6 = HEAP <| 4 + 5 + 6;
v.end() <~ 1 + 2 + 3;
let b6 = HEAP <~ 4 + 5 + 6;
// just create another built-in syntax extension?
emplace!(v.end(), 1 + 2 + 3);
let b6 = emplace!(HEAP, 4 + 5 + 6);
|
+1! Better than this rfc.
|
that said, while I agree that |
One more thought regarding stabilization -- even if we want to land this feature-gated, I think it'd be better to take the RFC and get this work in tree. I feel pretty sure that we want this sort of "emplacement" feature, even if we're not ready to commit to the details in particular. I'd rather have it in tree so we can experiment and gain experience with it. (I'd feel differently if no work had been done -- but @pnkfelix has most of the pieces implemented by now.) |
I agree that inference-based overloaded And I may be misunderstanding something, but why add the |
I believe it's no different from how this works: let v: Vec<_> = (0u32 .. 10).collect();
I agree, that's why I suggested
I also agree that |
@nikomatsakis I agree that |
A note about |
It'd be very nice if chained NRVO, URVO and placement-new were guaranteed to apply in scenarios like
and elide all the unnecessary copies. |
@petrochenkov regarding return-value-optimization: the intention is that the desugaring described in the RFC hopefully presents the code in a manner where LLVM can optimize it accordingly. If we observe that LLVM fails to optimize the code as desired, then we can instead switch from a macro-based implementation to more integrated support within the whole compiler pipeline; but that will hopefully be unnecessary. (i.e., the focus of this RFC is on the changes that are visible to the programmer, not on the quality of implementation, though of course we do care about quality of implementation.) |
I just wanted to jot a few cases where the current desugaring still fails to do as well as I would like, even after augmenting
(Both of the above cases compile fine if you use It would be good to resolve that, or at least incorporate it into the drawbacks section if I cannot fix it quickly. Some of the errors I'm seeing from the desugaring on the above cases is arising because the traits as written are not as general as they could be, with respect to the It may be possible to generalize the trick I used in rust-lang/rust#22006, instead of making it a special case just for the |
nice!
|
The core team has decided to accept this RFC. However, the The reason for this feature gate is not only the usual matter of not wanting to expose partially implemented features, but also some questions as to the desirability of the overall design (as raised in this discussion thread):
Ordinarily these uncertainties might lead to the RFC being postponed. However, given that there is an existing |
Tracking issue is rust-lang/rust#22181 |
Up to date final text will be available here: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md |
My favorite would be the latter variant because it does not use this strange inversion. |
Do you think there'll be confusion if the name "box" can refer both to the "simple heap pointer" and "any type of pointer"? I e, if you write:
A newcomer would probably expect something like this:
Rather than:
In this case there is a distinction between |
I don’t think this will lead to confusion, especially when talking about the language. |
Regardless of whether |
I agree that since emplacing is semantically almost always preferable (possibly faster, never slower, changed ordering of allocation and construction usually not significant), it should be as close to syntactically preferable as possible, or at least not much worse. |
cc RFC #98 |
someone said that (of course one can say "but what about expressions like |
What about |
@m13253 that's the less-than-or-equal operator... |
What about |
…sakis Remove all unstable placement features Closes #22181, #27779. Effectively makes the assortment of placement RFCs (rust-lang/rfcs#470, rust-lang/rfcs#809, rust-lang/rfcs#1228) 'unaccepted'. It leaves `box_syntax` and keeps the `<-` token as recognised by libsyntax. ------------------------ I don't know the correct process for unaccepting an unstable feature that was accepted as an RFC so...here's a PR. Let me preface this by saying I'm not particularly happy about doing this (I know it'll be unpopular), but I think it's the most honest expression of how things stand today. I've been motivated by a [post on reddit](https://www.reddit.com/r/rust/comments/7wrqk2/when_will_box_and_placementin_syntax_be_stable/) which asks when these features will be stable - the features have received little RFC-style design work since the end of 2015 (~2 years ago) and leaving them in limbo confuses people who want to know where they're up to. Without additional design work that needs to happen (see the collection of unresolved questions later in this post) they can't really get stabilised, and I think that design work would be most suited to an RFC rather than (currently mostly unused) experimental features in Rust nightly. I have my own motivations - it's very simple to 'defeat' placement in debug mode today and I don't want a placement in Rust that a) has no guarantees to work and b) has no plan for in-place serde deserialisation. There's a quote in [1]: "Ordinarily these uncertainties might lead to the RFC being postponed. [The RFC seems like a promising direction hence we will accept since it] will thus give us immediate experience with the design and help in determining the best final solution.". I propose that there have been enough additional uncertainties raised since then that the original direction is less promising and we should be think about the problem anew. (a historical note: the first mention of placement (under that name - uninit pointers were earlier) in an RFC AFAIK is [0] in late 2014 (pre-1.0). RFCs since then have built on this base - [1] is a comment in Feb 2015 accepting a more conservative design of the Place* traits - this is back when serde still required aster and seemed to break every other nightly! A lot has changed since then, perhaps placement should too) ------------------------ Concrete unresolved questions include: - making placement work in debug mode [7] - making placement work for serde/with fallible creation [5], [irlo2], [8] - trait design: - opting into not consuming the placer in `Placer::make_place` - [2] - trait proliferation - [4] (+ others in that thread) - fallible allocation - [3], [4] (+ others in that thread) - support for DSTs/unsized structs (if at all) - [1], [6] More speculative unresolved questions include: - better trait design with in the context of future language features [irlo1] (Q11), [irlo3] - interaction between custom allocators and placement [irlo3] [0] rust-lang/rfcs#470 [1] rust-lang/rfcs#809 (comment) [2] rust-lang/rfcs#1286 [3] rust-lang/rfcs#1315 [4] #27779 (comment) [5] #27779 (comment) [6] #27779 (comment) [7] #27779 (comment) [8] rust-lang/rfcs#1228 (comment) [irlo1] https://internals.rust-lang.org/t/placement-nwbi-faq-new-box-in-left-arrow/2789 [irlo2] https://internals.rust-lang.org/t/placement-nwbi-faq-new-box-in-left-arrow/2789/19 [irlo3] https://internals.rust-lang.org/t/lang-team-minutes-feature-status-report-placement-in-and-box/4646
Summary:
box (<place-expr>) <expr>
instead to:in <place-expr> { <block> }
(Note: waspreviously)in (<place-expr>) <expr>
box <expr>
to an overloaded operator that chooses its implementation based on the expected type.core::ops
for both operators, so that libstd can provide support for the overloaded operators; the traits are unstable so that the language designers are free to revise the underlying protocol in the future post 1.0.(rendered
text/
)(rendered draft)
Tracking issue: rust-lang/rust#22181