-
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
Place left arrow syntax (place <- expr
)
#1228
Conversation
place <- expr
)
“Lets add Expanding: |
I didn't follow the original syntax debate closely, but I agree with @nagisa that |
(BTW I don't know if this is clear from this RFC, but the intention is that we will keep the In other words, my intention is that people would not write The place where |
(but also I don't actually see what the problem is with |
Another alternative that perhaps I should have listed in the alternatives section
(man and I just thought this was going to be a slam dunk so there would be no need. ;) |
|
@seanmonstar But as @pnkfelix is trying to clarify, you would use |
Yay! @nagisa @aturon For example, emplacement into
or emplacement into
Ideally, a couple of basic containers ( Edit: |
I’ve been convinced. I can’t think up anything better; 👍 |
Thanks @petrochenkov; usage in those examples hews much closer to my intuitions about |
@eddyb yea, and I don't necessarily find that better. let x: Rc<i32> = box 5;
// or
let x = Rc::new(5); |
@seanmonstar In my experience the box would almost always be inferred -- but that also has issues, perhaps (akin to just invoking |
(I don't think PLACE evaluating before EXPR is a big violator to any explicit rules. Or I don't mind that.) |
@liigo it was mentioned in previous discussion EXPR might often get quite big, e.g.
which is quite a lot of scanning required to even notice this is not a regular That is, it is preferable to have |
while |
I had another look at @petrochenkov's examples, and I believe the following could be made to work: let map = HashMap::new();
map.entry(k) <- v Maybe |
@eddyb if we’re speaking concrete examples,
|
@petrochenkov asked:
Yes, now that rust-lang/rust#27215 has landed, the standard library should be able to experiment with adding implementations of the placement protocol to allow use of the |
@petrochenkov For what it's worth, I've gotten placement working with my tree map library here: https://github.com/apasel422/bst/tree/place. |
|
||
```rust | ||
let ref_1 = arena <- value_expression; | ||
let ref_2 = arena <- value_expression; |
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.
Maybe in {}
/<-
should do autoref? Otherwise these nicely looking statements would consume the arena (twice!)
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.
You generally don't keep an owned arena around, i.e. arena
would most likely have the type &Arena
.
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.
You generally don't keep an owned arena around
The same can't be said about vectors. I.e. the v <- elem
syntax proposed by @nagisa would have to roll back to v.back() <- elem
(or &mut v <- elem
). It's not especially terrible, though.
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.
Alternative I’ve been having in mind here is to change Placer::make_place
to take &mut self
instead of self
.
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.
@nagisa That wouldn’t really work for all cases, because, e.g., [Typed]Arena::alloc
takes &self
, not &mut self
, meaning that you’d be forced to use mutable references when you shouldn’t have to.
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.
It might end up being moot for Arenas. Namely, We might be able to do
impl<'a> Placer for &'a Arena { ... }
Which in that particular case side steps the choice of self
vs &mut self
.
I am personally becoming more convinced that it should be &mut self
. I spent a while last night looking through my notes to see why I had picked self
but did not find a motivating example.
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.
Would &mut self
work with map.entry(5) <- "foo"
?
Just to be clear, is it accurate to say that the only reason we want these special placement APIs and operators, instead of moving in the direction of the otherwise simpler and more general |
@glaebhoerl the phrase "recover from panics" is a bit ambiguous. We do want to be able to continue to properly unwind the stack, but I don't call that "recovery." (My personal take on it is that the Placer protocol is a simpler change than trying to add |
@glaebhoerl I agree with essentially your entire comment, except that I am slightly less sure about I wonder, for example, whether we can address the current overhead of buffer zeroing in |
Hmm... could you perhaps elaborate further on this idea? (Are there analogous owned/dynamic counterparts to the other lifetime-constrained reference types? Can you have first-class places while accomodating both unwinding and One of the reasons for my uncertainty is indeed that while
I had assumed this would be a natural use case for |
The placement protocol is indeed a version of |
I noticed this RFC does not specify precedence nor associativity of the operator. As far as associativity goes, it should be right-associative (i..e Precedence is less clear. It should bind stronger than assignment ( |
@nagisa |
Just to advertise this at the (hopefully appropriate) audience; here is the current draft, which I plan to update as feedback comes in:
|
Hmm, am I totally off-base with this comment: https://internals.rust-lang.org/t/placement-nwbi-faq-new-box-in-left-arrow/2789/19? |
@vadimcn |
@eddyb: yes, but what I am saying is that in order to use |
@vadimcn |
@vadimcn Maybe a clearer example would be: let mut v = vec![];
for x in a {
v.push(box {
if x == 0 { break; }
x + 1
});
} Were The |
Folks, I totally get what you are saying about the control flow. But look at it from the other side: the raison d'etre of the placement operator is to eliminate temporaries in the process of moving the value into its place. And it does not work for this purpose in cases when the value creator returns anything but the value itself (such as As for the second @eddyb`s motivating example, I find it unconvincing: you can easily re-write it as: let mut v = vec![];
for x in a {
if x == 0 { break; }
v.emplace(|| x+1);
} There may still be useful control flows that work with |
@vadimcn I would certainly love to just rely on closures. It's also plausible that this is indeed the best path. And maybe if we played enough tricks we might even be able to make All that said, I think there are two points being lost here:
vec <- Entry {
field1: foo?,
field2: bar?,
field3: [0; 1024]
}; Something like that might still make sense, it seems to me. You could also imagine things like: vec <- if some_condition {
return;
} else if some_other_condition {
break;
} else {
generate_big_result(some_fallible_thing()?)
}; (which I guess is just sort of a variation on a theme). |
I agree, this is what we should do.
Since computation of let field1 = foo?;
let field2 = bar?;
vec.emplace(|| Entry {
field1: field1,
field2: field2,
field3: [0; 1024]
}); Same applies to the last example. |
I think the major cost of syntactic support for emplacement, really the major cost for emplacement in general, is pedagogical. Everyone has to learn what emplacement is and when they need to use it. As a rule, additional syntax tends to increase the learning burden, but I think this is an exception. it seems easier to understand the notion of emplacement by dedicating syntax to it than it would be to understand why in some cases you should use a higher order function instead of the more at-hand function. Put another way, I don't think it is easier to explain to new users why they should not use I think it also makes it easier to comprehend when scanning code, because higher order functions can have many different purposes. |
If Rust decides do add do-notation for Monads (HKTs required), will this RFC have made the do-notation syntax that haskell uses impossible for Rust? Or is it still perhaps possible to give a different context based meaning to |
@Centril Rust is not a Haskell and it doesn’t face the same constraints as Haskell does/did. We might be considering HKTs for Rust, but Monads and sugar around them has little purpose even with HKTs in play. |
@nagisa, no that's simply not true. While they have less importance in Rust (due to e.g. sideffects), they're still very useful for e.g. error handling. |
@nagisa Having a Monad HKT trait allows you to define common operations for a whole host of data structures once. There are already a bunch of Monads in Rust, they are just not grouped together under a trait... Vec, Option, Result, BinaryHeap. Monads are not just a way to get "side-effects", but to redefine the meaning of Other interesting monads: Parsers, Futures, Language-based-security (http://www.cse.chalmers.se/edu/course/TDA342_Advanced_Functional_Programming/lecture9.html). Add to this: Monad transformers, where you have a stack of monads... http://www.cse.chalmers.se/edu/course/TDA342_Advanced_Functional_Programming/lecture6.html Also: monad comprehensions are even more powerful than list-comprehensions. |
@Centril In a systems language, fancier functional tricks meet the real world and tend to fall apart. As an example, If devirtualization doesn't occur, the slowdown compared to our current iterators or future hypothetical state-machine-based generators can be more than an order of magnitude. Parsers and futures also tend to use implicit existentials and/or GADTs, which admittedly Rust needs, but still have the overhead of boxing and virtual dispatch. We get it, monads are cool. But unless you can find a formalism for "do notation" which allows pervasive static dispatch and no boxing by default instead of as an optimization (and maybe actually integrate it with imperative control-flow primitives), I'm afraid there will always be more specialized solutions, not unlike the theoretical purity of linked lists contrasted with the real-world cache-efficiency of arrays. |
@eddyb Good comment. Didn't realize that F becomes a virtual call. But just to be clear, you're not saying that Monad::bind itself becomes virtual? Rust is a systems language, but not just. It can be used for other things =) |
@Centril Indeed, you can have |
…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
Rather than trying to find a clever syntax for placement-new that leverages
the
in
keyword, instead use the syntaxPLACE_EXPR <- VALUE_EXPR
.This takes advantage of the fact that
<-
was reserved as a token viahistorical accident (that for once worked out in our favor).
rendered draft.