Change:
This is a tracking issue for the feature and trait, which allows a closure to be invoked via the sugar. I'm not sure what the primary concerns are. All I know is it'd be really, really nice if we could invoke a somehow in safe Rust. This may or may not be the best approach. feel free to CC anyone who might want to comment or edit this issue to add any pertinent information.
The reason we don't want to stabilize is because we would prefer to make just work. Making work isn't exactly controversial (there's only one obvious way to handle the construct), but it's sort of tied up with , and more generally the issue that we want to remove the special cases for from the compiler.
So in the stable version of rust it's impossible to call and it's impossible to return a closure that's not in a box, judging from , because it doesn't have a known size. So how does one return a closure and call it?
and can both be called without a problem, because they don't require destructuring the box they're in; they only need or , respectively, which totally works with the current deref coercions. Which of the closure traits, or , is implemented for a specific closure is determined by inference. is a challenge because it takes by-value, which means it needs to be moved out of the and onto the stack to be executed, but this doesn't work in current Rust because there's no stable way to move out of (destructure) a . The trait proposed in the RFC linked would make this work, but the design of it is still being worked on. The key here is that does have a known size, but it's hidden behind the pointer so that anything implementing , regardless of its size, can fit in the same spot. The v-table in the trait object directs the processor to the concrete implementation of the trait (in this case, the closure body) for that specific object. All the details about the object, its size, fields, etc., are coded into that implementation.
Oh that makes more sense, thanks!
I don't want to be pushy, but I think this is really a major missing piece in Rusts "Closures" story - and not really mentioned on in the rust book. I understand that you want to remove special-cases for Box in the compiler and I agree that that's a worthy goal. But when will that land? If we can have Box&lt;FnOnce&gt; right now for the price of "a bit more Box magic" until the no-special-case-for-Box story is complete, then is that maybe the right price to pay? (I couldn't say, I would just profit from it as a Rust user)
Nominating for discussion in 1.6
cc me
:bell: This issue is now entering its cycle-long final comment period :bell: The libs team discussed this and we have two possible routes for this right now: in-tree copy could be stabilized with the intention of immediately deprecating once by-value DST works. The in-tree copy has the benefit of "being variadic" and having the paren sugar in bounds. in-tree copy could be deprecated and a crate could provide a suite of traits like , , etc. This has the benefit of not polluting the standard library but is less ergonomic to use. We're a little undecided on which route to take, so some comments would be welcome!
I'd vote for the former. We have enough micro-crates in the ecosystem and this is a common enough pattern that it's worth supporting in the stdlib. Edit: I want to add that I do have a use for this. I need it for one-off callbacks in . Right now I'm having to so I can call it from a box. It's not very ergonomic. I don't want to have to add another crate to my build because that seems like a very heavyweight solution just to get a trait or two.
you can do a bit better than that with some boilerplate: but it's a bit of a pain.
It's clunky any way you spin it.
Given that we all understand that FnBox is a will-inevitably-be-deprecated-hopefully-sooner-rather-than-later hack (albeit a useful one), I would like commitment from the Rust devs on some kind of timeframe for fixing the underlying issues before letting this be stabilized. Being able to say "this will be deprecated within the next year" is much more reassuring than "this will be deprecated, uhm, iunno, sometime".
What's wrong with "this will be deprecated, uhm, iunno, sometime"? If we don't have a timeline for by-value trait objects, why would we not want to have this bridge?
Well, the "it lives on until it's stabilized" pattern has been applied to other cases, it's a stopgap solution that's cleaner than introducing something with the intent of deprecating it.
Hi, With the current implementation of FnBox, I note that drop() is not implicitly called for captured members at the end of a boxed closure, which may (or may not) be a unintended source of leaking memory if relying solely on Rust's move semantics. I have produced a gist to demonstrate what i believe to be going on. I am not sure of the future of FnBox, (certainly would love to see a full blown implementation if under review for a 1.6 release), but in the interim, I wonder if its possible to address this specifically to bring things inline. Thanks all
Filed .
Brilliant, thank you.
I think I would stabilize this, personally. My reasoning is: we can do to make things more ergonomic here is good, until such time as works properly. original idea of was that it would serve as a place-holder for where you would use such that, in the glorious future, you can basically and Everything Just Works. I think this is mostly true now. This will be rather untrue if we move things to a crate. Obviously I don't really expect anyone to run , but I think having work as much like as we can makes it easier to explain to newcomers: "ah, doesn't quite work yet, but you can do for now, and it mostly works the same except that it requires a box". Basically, our story here is not great, but I don't see any reason to make it worse, just to avoid a deprecated item in the standard library.
The libs team discussed this during triage yesterday and the decision was to stabilize. brought up a good point, however, that doesn't implement for coherence reasons related to which may be good to sort out, however. Concretely, an impl like does not work. An impl of requires an impl of which in turn requires an impl of : Unfortunately this impl can't be written for two reasons: types by value don't work, so we can't use or to move out of the box if . impl is a coherence violation with .
What's blocking from "just working"? seems like a lot of work for a band-aid.
Ok, so I'm wary to stabilize if it prevents us from later having the impls for to also implement , and to drill down a bit I've come up with : This represents basically the traits that are in play here, but doesn't worry about the unsized types by value problem. Currently this code yields a coherence violation: Yet I would think that because of the attribute the compiler should be able to know that the type does not implement so the two impls can never overlap. mentioned that may come into play here. For now I'm not going to stabilize while we sort this out, but it's certainly a candidate for backporting quickly!
DST by value
"DST by value" or its explicit / first-class formulation, .
they are different: doesn't copy bits into its stack frame does copy bits. better be refining a move reference as it's stack frame doesn't live long enough. copies bits into receiver. Now for making a realistic API and may be used under the hood, just as they are for certain return values today, but that is an implementation detail. Out pointers are not very ergonomic.
If it's ok with others, let's keep this issue focused on , not on topics like DST-by-value, why doesn't work today, , etc. The specific issue at hand that we are worried about is that stabilizing as-is may provide a coherence violation to later have in the standard library (which is something we'd like to do). It doesn't work today, but we can somewhat safely assume that it will eventually work.
Is it that though? We are not trying to do , but rather . I thought the problem was that traits taking self by-value were not "object safe". As long the concrete type implementing is a SST, I don't see a problem. I forget if does or doesn't have a sized bound, but if it doesn't, should work fine with a little effort.
sorry, to be clear I meant that let's have discussions like that on other threads/issues as it's not relevant to here.
Hmm? My previous comment on vs by-value DST was off topic I'll readily admit, but isn't trying to clarify what the underlying problem with quite relevant to deciding whether is worth stabilizing?
I think the subtext here is that any way of making work is going to require some non-trivial new language work, and thus will take quite some time to design, implement, and stabilize. Meanwhile, as points out, makes things a bit more ergonomic in the meantime, and is easily deprecated later. In short, the team has already decided to move forward with stabilization in principle, with eventual deprecation planned. All that's left to discuss here is whether that stabilization/deprecation would somehow cause us problems later on.
Sorry, I misread my notification and thought eddyb's comment was the first I hadn't read and thus stabilization had not been decided upon just yet. Technically, I see also that per our ABI, the caller needs to be aware of static size of the argument, so isn't easier than .
:bell: This issue is now remaining in final comment period for stabilization :bell: We'd like to specifically sort out this question of whether we can add these impls in a stable fashion today and still be able to have the full suite of other trait implementations in the future. The coherence error is something that we're specifically concerned about. do you have any thoughts here about that setup? Is that expected to give a coherence violation?
We have two major problems with and HRTB, dunno how it impacts stabilization but I personally would like to see them fixed first: If manually invoking via continues to remain unstable as with and , then this makes unusable with HRTB on the stable channel even after being stabilized.
so I investigated the coherence error you were . As I suspected initially, the problem is due to . In particular, coherence is required to check that, for all types : (Here I am using the notation from RFC rust-lang/rfcs.) Normally, it would be able to conclude this, because: there is no impl of for ; and, is a crate-local type OR is fundamental (hence negative reasoning is allowed) However, it decides that even despite that, it can't say for certain, because it fears that some other crate will come along with an impl like this: Now, in fact, attempting to define such an impl fails the orphan check (Interestingly, I think it fails the orphan check precisely because is not currently declared fundamental, which means that the author of reserves the right to add more impls, basically, including an impl for all .) I've been thinking for some time that we could if we made better advantage of the orphan rules. In particular, the current overlap checking code predates fundamental and does not understand the limitations that the orphan check is imposing (as we can see above). However, I think what I would like to do is to make those improvements in tandem with an improved version of negative reasoning like rust-lang/rfcs. (Note to self: write some more comments on that RFC with latest thinking.) I'm not yet sure what my conclusion is from this investigation. On the one hand, I'm 95% sure that there doesn't have to be a coherence issue here. On the other hand, I'm 5% uncertain, and I'd feel better if we resolved that 5% uncertainty before we stabilized .
Ok, cool, thanks for the investigation and
The libs team discussed this in triage recently and the decision was to punt this for now due to the concerns brought up.
cc , a possible bug for this
In case somebody else runs into this, it might be worth mentioning the "boxfnonce" crate that provides a safe+stable wrapper for this use-case. I don't claim to understand the details of this issue and don't know how good of solution that crate provides.
Just as a note, this issue is now going to end up being in the example of the final chapter of the book's second edition. We can just explain it and use the workarounds; it is the final chapter after all. But it is a small bit of tarnish right at the end, which is slightly unfortunate.
Use it as an example of how Rust is still a work-in-progress, and provide an on-ramp for people who have finished the book to come work on Rust itself. :)
With the recent impl Trait stabilization, is there anything new to discuss? I figure that impl Trait alone, especially in its current conservative form, is far from obviating the need for FnBox (though at least now we can return FnOnce from functions and call them), but given how many years it's been since this issue was opened I figure it's worth getting a survey of what the current thinking is. For example, would extending impl Trait to type position solve all of this (i.e. , (hm, I suppose there's some problems with that last one :P )), or are we still looking towards additional mechanisms like or "by-value DST" (which I don't remember ever even seeing an RFC for...)?
One thing to consider: given that we already overload the call operator to different methods depending on type (, , ), would it be feasible to take the method from , stick it into the trait, and have the compiler itself distinguish between and like it already does for the other closure calling methods? It would make it so that every would be immediately callable today without anyone using a different/unstable type, and since would remain hidden behind the call operator we wouldn't need to stabilize anything (and it's not like the Fn methods are going to be stable anytime in the foreseeable future anyway). It may not make it possible to move out of a , but it's not like it's possible to move out of a either, and it would let us deprecate FnBox. Thoughts?
Given that we now support arbitrary self type, I wonder if we will need things like or .
"By-value DST" was not only RFCed, but accepted, under the name . :) (No implementation yet though, as far as I'm aware.)
I don't think there's any use case for , because you wouldn't be able to do anything with it unless the refcount is 1, which is sort of against the point of Rc. AFAICT it would be equivalent in behavior to having some code in a destructor on Foo and then doing . And I don't think that makes sense either, because you'd never be able to call it since AFAIK it's basically &mut FnOnce, which also can't be called. Generalizing this to other potential smart pointers, the underlying problem here is that there's no way at all to store a FnOnce that allows it to be called. If ever works, it means that, in the worst-case scenario, they would just do rather than just . That seems like it would be an acceptable temporary situation until a proper solution was found, rather than coming up with a menagerie of new Fn traits.
exactly, the (or mpsc with it) will not work ‒ for example, if you want to send unknown tasks from one thread to another, they're going to be different. allows not to name the type, but they would still have to be the same type.
Precisely, but (and this is probably getting off-topic) I was curious whether or not we would want to make all anonymous types be considered interchangeable iff, for each specific trait Foo, they have the same size; this would (among other things) let work both technically and conceptually, and would let us do as long as each closure inserted into closed over elements whose sizes come to the same sum (e.g. a vector could contain multiple closures if they all close over nothing). Of course this still wouldn't let anyone use those closures until we had unsized rvalues... but at the same time it would make unsized rvalues strictly more useful as well. Anyway, I'm still curious whether my above proposal to make special (temporarily) would suffice for most of this.
Wouldn't that make it a breaking change for any type to change its size? That's already somewhat true when is in use, but what you propose seems more fundamental.
Hm, probably. :) I can imagine mitigation strategies, but this is an involved topic that deserves its own internals thread or RFC, rather than clogging up this one. We only got on this tack because I brought up impl Trait as part of asking the question "what's next?", to which the answer appears to be the unsized rvalues RFC.
I think I would be against this. It sounds like a weird form of subtyping where . I think when people want this sort of relationship, they should explicitly use a Trait object.
That's actually an interesting idea. Something like a , but without the heap allocation, one with configurable maximal size. One could put a trait object into it (so long as it would fit) and use it. I wonder if it could be implemented as a crate, with some amount of unsafe code. But that's completely ortogonal to the problem here I guess. This one still wouldn't allow to call the thing and it would still benefit from some kind of DerefMove or something, just like what would help to be called.
No. Something owning, holding the data inline, something like ‒ you specify the max capacity and it acts like a vector, but stores everything inline on the stack. So this one, you'd say there's capacity of so many bytes and you could move an object implementing the given trait inside it and use it as a trait object. Anyway, that's probably off-topic here.
My considerations: There is no harm to stablize and make it works the same way the other traits works. It is consistant with the different "fundamental" types: , , and . should imply , and should imply . The implementation is trivial. (would this be a breaking change?) and also We can get just work by allowing a trait object, and a valid method receiver. See By-value DST can be implemented later and should not be affected by this Conclusion: We can have the best of both worlds: have stable and also allow , and nothing should be affected by by-value DST RFC.
sigh Unsized arguments are such a small part of by-value DSTs - they aren't even by-value DSTs, since you can always pass those arguments by reference! We had working ages ago but then removed support for it. EDIT: there are some complications with borrowck, but they would presumably be solved by borrowing the unsized argument "uniquely" for the duration of the call, instead of moving it.
You can use but it appears not to work for arguments taken by reference. This issue is a bit frustrating, as it has a fair negative impact on the ease of structuring APIs so they accurately reflect intended ownership constraints.
As far as I can tell, . Edit: Never mind; I didn't realize it was an open issue and that you can use the desugaring instead.
Just hit this problem (again!) from another angle: The solution is to turn into , but the error message is pretty incomprehensible to anyone not familiar with this issue (see also ).
was caused by recent relax on calling . causes Compiler Unexpected Panic.
is no long a panic on stable/nightly 2015/2018
Calling seems to work on Nightly: () I think this removes the need for . Am I missing something, or should we deprecate and eventually remove? fcp close
Team member has proposed to close this. The next step is review by the rest of the tagged teams: [x] [x] [x] [x] [x] [ ] No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
Is it too early to close? although your example seems to work, but when you actually try to call it, you get ICE Maybe it is just because the playground used an outdated nighly (10-25 in message, 10-29 already now)?
Yes, the newest nightly compiles your example. The ICE message (that is resolved and removed in ) was emitted in codegen phase, so one would not have seen this unless the main function actually used it. That's the difference between your example and examples that have already compiled before .
Fine. Hopefully the "Nightly" at playground wouldn't become "Weekly" or worse as it is still 10-25 right now.
:bell: This is now entering its final comment period, as per the . :bell:
The same code I posted above compiles (and runs), but when you run the miri check it gives ICE in the playground. Where should I report issue for the miri check?
Report it as a separate issue (referencing this one) on this repo.
Perhaps somebody should add a test for that case before we FCP?
I view FCP as an opportunity for anyone to object to a proposal, or to some details of it. At this point I believe there is strong consensus that we can and will make work eventually, it’s "only" a matter of implementation effort. So, while it’d probably be premature to deprecate right now, I think FCP to decide we want to do it once the replacement works is fine.
This seems confusing to me. It's already fully implemented, isn't it? (ignoring the bug that found - which is not relevant to Rust itself)
I meant "implementation" as opposed to design decisions, so fixing bugs is part of it.
Ah, sure, I'm only trying to point out that the only bug we're aware of relates to supporting this, which shouldn't block anything, it's not relevant to the language itself.
The final comment period, with a disposition to close, as per the , is now complete.
This issue (fixing ) is the only hard blocker preventing the libtest crate from working on stable Rust. : errors with:
That is not a hard blocker. You can easily build a one-off trait to cover the boxed once closure use case.
Do you have an example or is that documented somewhere? This is the closest thing I know (): But it doesn't work (, and I don't know how to call that in a trait impl since one can't move that out of the box).
Does this API specifically require taking exactly the type ?
I haven't spent too much time trying to use but that was the first thing I attempted and it does requires significant refactorings - it requires changing many APIs that rely on being able to move the environment into the closure to take references to the environment, which must be kept alive somehow else. I didn't see them through because I thought these refactorings were too invasive, but I'll take a PR that does them if it gets the library running on stable.
so I performed a lot of refactorings since I tried that, and I just tried it again, and it all worked with minimal changes - sorry for the noise =/
I think means you can change the API to use before can be used in stable.
Really wish can be revived and pushed forward.
Where is this requirement for tracked, or where in the source is it needed? I'm not sure but I would suspect you might want your own trait anyway, that is implemented for closures but also allows manual implementations. Alternatively, you could potentially have a wrapper that exposes only a constructor with an bound, and internally uses a private trait that works like .
will be stable in 1.35.
PR to add a deprecation warning: We can remove entirely and close this issue a couple release cycles after this lands.

Discussion:
} ``` <del> One of the objectives of this feature is to allow `Box<dyn FnOnce>`, instead of `Box<dyn FnBox>` in the future. See [#28796] for details. [#28796]: https://github.com/rust-lang/rust/issues/28796 </del> <ins> One of the objectives of this feature is to allow `Box<dyn FnOnce>`. </ins> ## Variable length arrays

<del> # `fnbox` The tracking issue for this feature is [#28796] [#28796]: https://github.com/rust-lang/rust/issues/28796 ------------------------ This had been a temporary alternative to the following impls: ```rust,ignore impl<A, F> FnOnce for Box<F> where F: FnOnce<A> + ?Sized {} impl<A, F> FnMut for Box<F> where F: FnMut<A> + ?Sized {} impl<A, F> Fn for Box<F> where F: Fn<A> + ?Sized {} ``` The impls are parallel to these (relatively old) impls: ```rust,ignore impl<A, F> FnOnce for &mut F where F: FnMut<A> + ?Sized {} impl<A, F> FnMut for &mut F where F: FnMut<A> + ?Sized {} impl<A, F> Fn for &mut F where F: Fn<A> + ?Sized {} impl<A, F> FnOnce for &F where F: Fn<A> + ?Sized {} impl<A, F> FnMut for &F where F: Fn<A> + ?Sized {} impl<A, F> Fn for &F where F: Fn<A> + ?Sized {} ``` Before the introduction of [`unsized_locals`][unsized_locals], we had been unable to provide the former impls. That means, unlike `&dyn Fn()` or `&mut dyn FnMut()` we could not use `Box<dyn FnOnce()>` at that time. [unsized_locals]: ../language-features/unsized-locals.md `FnBox()` is an alternative approach to `Box<dyn FnBox()>` is delegated to `FnBox::call_box` which doesn't need unsized locals. As we now have `Box<dyn FnOnce()>` working, the `fnbox` feature is going to be removed. </del>

} } <del> /// `FnBox` is deprecated and will be removed. /// `Box<dyn FnOnce()>` can be called directly, since Rust 1.35.0. /// /// `FnBox` is a version of the `FnOnce` intended for use with boxed /// closure objects. The idea was that where one would normally store a /// `Box<dyn FnOnce()>` in a data structure, you whould use /// `Box<dyn FnBox()>`. The two traits behave essentially the same, except /// that a `FnBox` closure can only be called if it is boxed. /// /// # Examples /// /// Here is a snippet of code which creates a hashmap full of boxed /// once closures and then removes them one by one, calling each /// closure as it is removed. Note that the type of the closures /// stored in the map is `Box<dyn FnBox() -> i32>` and not `Box<dyn FnOnce() /// -> i32>`. /// /// ``` /// #![feature(fnbox)] /// #![allow(deprecated)] /// /// use std::boxed::FnBox; /// use std::collections::HashMap; /// /// fn make_map() -> HashMap<i32, Box<dyn FnBox() -> i32>> { ///     let mut map: HashMap<i32, Box<dyn FnBox() -> i32>> = HashMap::new(); ///     map.insert(1, Box::new(|| 22)); ///     map.insert(2, Box::new(|| 44)); ///     map /// } /// /// fn main() { ///     let mut map = make_map(); ///     for i in &[1, 2] { ///         let f = map.remove(&i).unwrap(); ///         assert_eq!(f(), i * 22); ///     } /// } /// ``` /// /// In Rust 1.35.0 or later, use `FnOnce`, `FnMut`, or `Fn` instead: /// /// ``` /// use std::collections::HashMap; /// /// fn make_map() -> HashMap<i32, Box<dyn FnOnce() -> i32>> { ///     let mut map: HashMap<i32, Box<dyn FnOnce() -> i32>> = HashMap::new(); ///     map.insert(1, Box::new(|| 22)); ///     map.insert(2, Box::new(|| 44)); ///     map /// } /// /// fn main() { ///     let mut map = make_map(); ///     for i in &[1, 2] { ///         let f = map.remove(&i).unwrap(); ///         assert_eq!(f(), i * 22); ///     } /// } /// ``` #[rustc_paren_sugar] #[unstable(feature = "fnbox", issue = "28796")] #[rustc_deprecated(reason = "use `FnOnce`, `FnMut`, or `Fn` instead", since = "1.37.0")] pub trait FnBox<A>: FnOnce<A> { /// Performs the call operation. fn call_box(self: Box<Self>, args: A) -> Self::Output; } #[unstable(feature = "fnbox", issue = "28796")] #[rustc_deprecated(reason = "use `FnOnce`, `FnMut`, or `Fn` instead", since = "1.37.0")] #[allow(deprecated, deprecated_in_future)] impl<A, F> FnBox<A> for F where F: FnOnce<A> { fn call_box(self: Box<F>, args: A) -> F::Output { self.call_once(args) } } </del> #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}

#![feature(exhaustive_patterns)] #![feature(external_doc)] #![feature(fn_traits)] <del> #![feature(fnbox)] </del> #![feature(generator_trait)] #![feature(hash_raw_entry)] #![feature(hashmap_internals)]

<del> #![feature(fnbox)] #![allow(deprecated, deprecated_in_future)] use std::boxed::FnBox; fn call_it<T>(f: Box<dyn FnBox() -> T>) -> T { f() } fn main() { let s = "hello".to_owned(); assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); } </del>