You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tracking issue for Fn traits (unboxed_closures & fn_traits feature)Β #29625
is the reason I have a safety issue in libloading.
Reacted by SOFe (Jonathan Chan Kwan Yin), Ahmed Ghait, Kevin Cox, Rostyslav Lesovyi, 9glenda, Isak Wertwein, Felipe S. S. Schneider and Andrew Hlynskyi
Could someone summarise what is blocking stabilisation here please?
Reacted by Lukas Kalbertodt, Colin Kiegel, Phil Ruffwind, Alexander Regueiro, Peter Hall, Mark McCaskey, Hrvoje NikΕ‘iΔ, Jakub BerΓ‘nek, Caleb Stanford, kkthmyh and 7 more
Reacted by kkthmyh, Felipe S. S. Schneider and Charlie He
@nrc uncertainty about Args being the right thing given the possibility of variadic generics coming along around 2030 is the most major reason this is unstable.
Reacted by kkthmyh, Charles Samborski and fxtressia
Reacted by Lukas Kalbertodt, bb010g, Jelte Fennema-Nio, Maciej Goszczycki, Tim, Stephan Sokolow, Dzmitry Malyshau, runiq, scottmcm, vitor cortez and 90 more
One issue we've been discussing on TheDan64/inkwell#5 is the ability to mark something as unsafe to use. What about having an UnsafeFn marker trait which could be used to tell the compiler a callable is unsafe to call?
For context, inkwell is a wrapper around LLVM and we're trying to figure out how to return a function pointer to a JIT compiled function, when calling the function is fundamentally unsafe for the same reasons FFI code is unsafe to call.
Reacted by Dan Kolsoi, Alexander Regueiro, Eira Fransham, Ellen Emilia Anna Zscheile, Brandon Dyer, Tibor Djurica Potpara, Maurits van Riezen and svblsvljb
There is another reason to add UnsafeFn: currently unsafe fns don't implement Fn. There is no way to pass unsafe fn as a function argument, they are second class citizen: example.
UnsafeFn could be implemented for things implementing Fn, so Fns can be used wherever UnsafeFn is required. There probably also should be UnsafeFnMut and UnsafeFnOnce.
Reacted by Alexander Regueiro, brunoczim, L-as, Dan Kolsoi, Alexander Huszagh, Ellen Emilia Anna Zscheile, Matt Coster, Luke, Rostyslav Lesovyi, Nick Mertin and 1 more
@Michael-F-Bryan@CodeSandwich This sounds like something for which an RFC would really be appreciated. It probably wouldn't be an overly long or intricate one to write, even. I would support it, for sure, and judging by an issue I saw about this not long ago (a long-standing one), others would too.
() is not a valid function name. And in any case we have three different traits. They need different method names to avoid ambiguity.
It is indeed illegal. But if modify the compiler to allow it, this would look better than the current syntax to me. Moreover, though we have multiple Fn* traits, it seems that there might not be ambiguity, as it's unlikely that we would need to implement all of them for a struct.
Implementing Fn requires implementing FnMut and FnOnce too given that they are supertraits of Fn. If a subtrait and a supertrait have the same method name, I believe rustc doesn't allow calling the method currently for ambiguity reasons.
Implementing Fn requires implementing FnMut and FnOnce too given that they are supertraits of Fn.
FnOnce and FnMut are supertraits of Fn, but I don't think they should be. I agree that every Fn trait needs to implements FnMut and FnOnce, but Fn does not rely on anything special about how the other traits are implemented; therefore, they should not be prerequisites to implementing Fn. In fact, it would be really annoying if they were implemented and any different than the Fn implementation. Instead, only Fn should be implemented and a trivial blanket implementation should be used to implement FnMut and FnOnce, see the example below. The example is the Fn* traits using blanket implementations instead of supertraits.
One could easy have both: There should be nothing that prevents one from requiring smth. as a supertrait, and still offering a blanket impl for the supertrait based upon the subtrait.
Perhaps beware of afaik resolution gotchas like #141807
Reacted by Lech Mazur, Ray Redondo, Bilakshan Purohit, Aβ±― and Mike Maley
Is Fn(A, B) vs Fn<(A, B)> still a topic being discussed? I had quite some hard time getting in my head that Fn(A, B) is not Fn<A, B> rather Fn<(A, B)>.
Timeline for variadic generics: Based on how long const generics, and generic associated types, took, is it not likely that this would take many years? Plus complications/interactions that we don't know about yet (with the new trait solver, or anything else new in the compiler).
EDIT: Sorry, the below doesn't work (that is, it does compile with two impl that we want to conflict). I'll investigate more.
EDIT again: See the following comment for an example.
but that wouldn't scale to function-like objects with generic arguments, for which an associated type wouldn't work.
@fogti Do you mean when Args depends on any generic argument(s) of the object for which Fn* is implemented? Solution is below.
I don't know how to support higher-order signatures while at the same time preventing multiple call signatures for a type other than keeping Fn* perma-unstable.
@bjorn3 (If I understand right, and as mentioned by others earlier), we can prevent multiple call signatures by changing Args to be an associative type. BUT, this associative type doesn't have to be in Fn* traits (as we know them) - it could be in a parent trait(s), whose only purpose is to prevent the multiple call signatures. I believe the following should continue to work for Higher-Ranked Trait Bounds. So all current internal/nightly code could continue to work.
EDIT: Sorry, the below doesn't work (that is, it does compile with two impl that we want to conflict). I'll investigate more.
EDIT again: See the following comment for an example.
// This example defines `FnOnce` only, and it omits `call_once`.// The following two lines are here just for minimizing the `unstable` surface of this example, and it allows you to compile it with `stable` Rust toolchain.pubtraitTuple{}impl<T>Tuplefor(T,){}// Internal. Not sure if we need FnOnceAssociated to be sealed more.#[allow(dead_code)]traitFnOnceAssociated<A:Tuple>{typeArgs:Tuple;}pubtraitFnOnce<A:Tuple>:FnOnceAssociated<A>{typeOutput;}// Blanket impl ensures that users/3rd parties can't implement it for FnOnce (and friends)./*impl<F: FnOnce<A>, A: Tuple> FnOnceAssociated<A> for F { type Args = A;}*/// OR, even a total blanket impl - unsure if useful, and possibly confusing:impl<F,A:Tuple>FnOnceAssociated<A>forF{typeArgs = A;}//-------// Usage:pubstructGenericStruct<T>{_t:T,}impl<T>FnOnce<(bool,)>forGenericStruct<T>{typeOutput = bool;}// I've hoped for the following fails to compile, conflicting with the previous impl - but it doesn't...impl<T>FnOnce<(u8,)>forGenericStruct<T>{typeOutput = bool;}
Side note: I'm surprised that the first blanket impl (commented out) in the above example actually compiles. Is it likely to continue to compile with the next trait solver?
The following prevents multiple signatures/multiple impl of FnOnce/FnMut/Fn for the same type, while keeping Args as a generic parameter, hence supporting higher rank trait bounds.
This adds an associative type Args, but not in FnOnce/FnMut/Fn traits, because their generic instantiations are separate and having an associative type in them would not prevent multiple signatures/implementations. So the associative type needs a new trait (a parent trait, or a side kick trait; called FnBase, or FnPreventMultipleSignatures or similar).
It's not ideal, because you need to implement one more trait. But we already have three traits, and this new one is tiny.
That does involve duplication of Args
as a generic param to FnOnce/FnMut/Fn, and
as an associated type in FnBase.
// Out of three existing `Fn*` traits, this example defines `FnOnce` only, and it omits `call_once`.// The following two lines are here just for minimizing the `unstable` surface of this example, and it allows you to compile it with `stable` Rust toolchain.pubtraitTuple{}impl<T>Tuplefor(T,){}impl<T,U>Tuplefor(T,U){}// ...pubtraitFnBase/* or: FnPreventMultipleSignatures or similar */{typeArgs:Tuple;}pubtraitFnOnce<A:Tuple>:FnBase<Args = A>// Or, instead of trait inheritance, have a side kick trait and a bound on Self:////where Self: FnBase< Args = A>{typeOutput;}// Usage:pubstructGenericStruct<T>{_t:T,}impl<T>FnBaseforGenericStruct<T>{typeArgs = (bool,);}impl<T>FnOnce<(bool,)>forGenericStruct<T>{typeOutput = ();}// The following fails to compile - GOOD./*impl<T> FnOnce<(u8,T)> for GenericStruct<T> { type Output = ();}*/
Unfortunately, I don't see a way to have blanket impl for FnBase for any type that implements FnOnce.
Hi all, tracking issues are normally reserved for updates about the development of a feature. To discuss the feature and/or propose extensions, the appropriate venues are the internals forum, Zulip, the RFC PR if it's still open (which isn't the case here), or writing your own RFC.
If you open a relevant Zulip/Internals topic, do post it here so that interested people can come and discuss with you over there.
Activity
nagisa commentedon May 13, 2016
Inability to delegate calls to other FnOnce implementors like this:
is the reason I have a safety issue in libloading.
petrochenkov commentedon Jul 12, 2016
FnOnce::Outputis stabilized in #34365nrc commentedon Aug 17, 2016
Could someone summarise what is blocking stabilisation here please?
nagisa commentedon Aug 18, 2016
@nrc uncertainty about
Argsbeing the right thing given the possibility of variadic generics coming along around 2030 is the most major reason this is unstable.aturon commentedon Aug 27, 2016
@nrc also possibly some questions around the inheritance relationship, see #19032
brunoczim commentedon Jan 18, 2018
There should be a way of casting
fn(A) -> BtoFn(A) -> BSimonSapin commentedon Jan 18, 2018
@brunoczim That coercion already happens implicitly, but
Fn()as a type is a trait object so it needs to be behind some kind of pointer:Michael-F-Bryan commentedon Apr 2, 2018
One issue we've been discussing on TheDan64/inkwell#5 is the ability to mark something as
unsafeto use. What about having anUnsafeFnmarker trait which could be used to tell the compiler a callable isunsafeto call?For context,
inkwellis a wrapper around LLVM and we're trying to figure out how to return a function pointer to a JIT compiled function, when calling the function is fundamentallyunsafefor the same reasons FFI code isunsafeto call.CodeSandwich commentedon May 4, 2018
There is another reason to add
UnsafeFn: currentlyunsafe fns don't implementFn. There is no way to passunsafe fnas a function argument, they are second class citizen: example.UnsafeFncould be implemented for things implementingFn, soFns can be used whereverUnsafeFnis required. There probably also should beUnsafeFnMutandUnsafeFnOnce.alexreg commentedon Aug 20, 2018
@Michael-F-Bryan @CodeSandwich This sounds like something for which an RFC would really be appreciated. It probably wouldn't be an overly long or intricate one to write, even. I would support it, for sure, and judging by an issue I saw about this not long ago (a long-standing one), others would too.
63 remaining items
bjorn3 commentedon Dec 19, 2025
()is not a valid function name. And in any case we have three different traits. They need different method names to avoid ambiguity.EienMiku commentedon Dec 19, 2025
It is indeed illegal. But if modify the compiler to allow it, this would look better than the current syntax to me. Moreover, though we have multiple
Fn*traits, it seems that there might not be ambiguity, as it's unlikely that we would need to implement all of them for a struct.bjorn3 commentedon Dec 19, 2025
Implementing
Fnrequires implementingFnMutandFnOncetoo given that they are supertraits ofFn. If a subtrait and a supertrait have the same method name, I believe rustc doesn't allow calling the method currently for ambiguity reasons.madsmtm commentedon Dec 19, 2025
Also, doing special syntax for builtin operations isn't something that is done elsewhere, for example the
Addtrait has a method calledadd, not+.mikem8891 commentedon Jan 7, 2026
FnOnceandFnMutare supertraits ofFn, but I don't think they should be. I agree that everyFntrait needs to implementsFnMutandFnOnce, butFndoes not rely on anything special about how the other traits are implemented; therefore, they should not be prerequisites to implementingFn. In fact, it would be really annoying if they were implemented and any different than theFnimplementation. Instead, onlyFnshould be implemented and a trivial blanket implementation should be used to implementFnMutandFnOnce, see the example below. The example is theFn*traits using blanket implementations instead of supertraits.play with it (https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=cb845122a8404c17bac1d04a6bdfb20d)
bjorn3 commentedon Jan 7, 2026
I think that would be a breaking change by no longer allowing downcasting from
dyn Fn()todyn FnMut().fogti commentedon Jan 8, 2026
One could easy have both: There should be nothing that prevents one from requiring smth. as a supertrait, and still offering a blanket impl for the supertrait based upon the subtrait.
Perhaps beware of afaik resolution gotchas like #141807
Nekidev commentedon Mar 10, 2026
Is
Fn(A, B)vsFn<(A, B)>still a topic being discussed? I had quite some hard time getting in my head thatFn(A, B)is notFn<A, B>ratherFn<(A, B)>.jeffs commentedon Mar 10, 2026
@Nekidev Variadic generics aren't currently supported by the language, for a number of subtle reasons. See also rust-lang/lang-team#348.
peter-lyons-kehl commentedon Jun 15, 2026
Timeline for variadic generics: Based on how long
constgenerics, and generic associated types, took, is it not likely that this would take many years? Plus complications/interactions that we don't know about yet (with the new trait solver, or anything else new in the compiler).EDIT: Sorry, the below doesn't work (that is, it does compile with two
implthat we want to conflict). I'll investigate more.EDIT again: See the following comment for an example.
@fogti Do you mean when
Argsdepends on any generic argument(s) of the object for whichFn*is implemented? Solution is below.@bjorn3 (If I understand right, and as mentioned by others earlier), we can prevent multiple call signatures by changing
Argsto be an associative type. BUT, this associative type doesn't have to be inFn*traits (as we know them) - it could be in a parent trait(s), whose only purpose is to prevent the multiple call signatures. I believe the following should continue to work for Higher-Ranked Trait Bounds. So all current internal/nightly code could continue to work.EDIT: Sorry, the below doesn't work (that is, it does compile with two
implthat we want to conflict). I'll investigate more.EDIT again: See the following comment for an example.
Side note: I'm surprised that the first blanket impl (commented out) in the above example actually compiles. Is it likely to continue to compile with the next trait solver?
peter-lyons-kehl commentedon Jun 15, 2026
The following prevents multiple signatures/multiple
implofFnOnce/FnMut/Fnfor the same type, while keepingArgsas a generic parameter, hence supporting higher rank trait bounds.This adds an associative type
Args, but not inFnOnce/FnMut/Fntraits, because their generic instantiations are separate and having an associative type in them would not prevent multiple signatures/implementations. So the associative type needs a new trait (a parent trait, or a side kick trait; calledFnBase, orFnPreventMultipleSignaturesor similar).It's not ideal, because you need to implement one more trait. But we already have three traits, and this new one is tiny.
That does involve duplication of
ArgsFnOnce/FnMut/Fn, andFnBase.Unfortunately, I don't see a way to have blanket
implforFnBasefor any type that implementsFnOnce.Nadrieril commentedon Jun 15, 2026
Hi all, tracking issues are normally reserved for updates about the development of a feature. To discuss the feature and/or propose extensions, the appropriate venues are the internals forum, Zulip, the RFC PR if it's still open (which isn't the case here), or writing your own RFC.
If you open a relevant Zulip/Internals topic, do post it here so that interested people can come and discuss with you over there.
peter-lyons-kehl commentedon Jun 16, 2026
Please discuss at https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/Fn.20traits.20.28unboxed_closures.20.26.20fn_traits.20feature.29.