Skip to content
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

Tracking issue for Fn traits (`unboxed_closures` feature) #29625

Open
aturon opened this issue Nov 5, 2015 · 24 comments
Open

Tracking issue for Fn traits (`unboxed_closures` feature) #29625

aturon opened this issue Nov 5, 2015 · 24 comments

Comments

@aturon
Copy link
Member

@aturon aturon commented Nov 5, 2015

Tracks stabilization for the Fn* traits.

Random bugs:

  • #45510 – type-based dispatch not working
  • #42736foo() sugar doesn't work where you have &Foo: FnOnce
@nagisa
Copy link
Contributor

@nagisa nagisa commented May 13, 2016

Inability to delegate calls to other FnOnce implementors like this:

struct A<T>(T);

impl<T, Args> FnOnce<Args> for A<T>
where T: FnOnce<Args> {
    type Output = <T as FnOnce<Args>>::Output;
    fn call_once(self, args: Args) -> Self::Output { FnOnce::call_once(self.0, args) }
}

is the reason I have a safety issue in libloading.

@petrochenkov
Copy link
Contributor

@petrochenkov petrochenkov commented Jul 12, 2016

FnOnce::Output is stabilized in #34365

@nrc
Copy link
Member

@nrc nrc commented Aug 17, 2016

Could someone summarise what is blocking stabilisation here please?

@nagisa
Copy link
Contributor

@nagisa nagisa commented Aug 18, 2016

@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.

@aturon
Copy link
Member Author

@aturon aturon commented Aug 27, 2016

@nrc also possibly some questions around the inheritance relationship, see #19032

@brunoczim
Copy link

@brunoczim brunoczim commented Jan 18, 2018

There should be a way of casting fn(A) -> B to Fn(A) -> B

@SimonSapin
Copy link
Contributor

@SimonSapin SimonSapin commented 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:

use std::rc::Rc;
fn main() {
    let _: &Fn() = &main;
    let _: Box<Fn()> = Box::new(main);
    let _: Rc<Fn()> = Rc::new(main);
}
@Michael-F-Bryan
Copy link

@Michael-F-Bryan Michael-F-Bryan commented Apr 2, 2018

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.

@CodeSandwich
Copy link

@CodeSandwich CodeSandwich commented May 4, 2018

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.

@alexreg
Copy link
Contributor

@alexreg alexreg commented 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.

@CodeSandwich
Copy link

@CodeSandwich CodeSandwich commented Aug 21, 2018

@alexreg Ok, I'll prepare it in spare time. Unfortunately I lack knowledge and experience to actually implement it or even fully understand the idea.

@alexreg
Copy link
Contributor

@alexreg alexreg commented Aug 21, 2018

@CodeSandwich Don't worry, so do I! Maybe get yourself on Rust's Discord (#design channel) and we can discuss it with some people who really know the nitty gritty? You can ping me there, same username.

@RalfJung
Copy link
Member

@RalfJung RalfJung commented Aug 22, 2018

With every unsafe function comes a manually written "contract" saying when that function may or may not be called.

With UnsafeFn, who is setting that contract?

@Michael-F-Bryan
Copy link

@Michael-F-Bryan Michael-F-Bryan commented Aug 23, 2018

With UnsafeFn, who is setting that contract?

I'd say this is done on a case-by-case basis. It's really hard to specify the various invariants and assumptions you make in unsafe code in something as rigid as a type system, so anything that accepts an UnsafeFn would probably also need to document its assumptions.

Before writing up a RFC I thought I'd make a post on the internal forum. It'd be nice to hear what opinions other people have on this topic and the different solutions they come up with.

@Vurich
Copy link

@Vurich Vurich commented Nov 5, 2018

I don't know how one would realistically implement this, but probably the ideal semantics is to have any function that takes an unsafe function as an argument to also be unsafe.

@SimonSapin
Copy link
Contributor

@SimonSapin SimonSapin commented Nov 5, 2018

A different interface/API likely requires a separate set of traits. Though multiplying the number of traits doesn’t sound great, especially if we later want to also support const fn closures (and unsafe const fn?).

@audrey-jensen
Copy link

@audrey-jensen audrey-jensen commented Nov 6, 2018

Is there a way to implement these as wrapper traits? Unsafe<T> where T : FnOnce, Const<T> where T : FnOnce, Async<T> where T : FnOnce and so on?

@peterjoel
Copy link
Contributor

@peterjoel peterjoel commented Jan 10, 2019

UnsafeFn sounds like an unsound abstraction. When using an unsafe function, it's your responsibility to read documentation and understand all assumptions and invariants that need to be satisfied. This cannot be abstracted away because those invariants and assumptions are individual to the function in question.

Personally, I think unsafe functions should just not implement any of the Fn traits. It's up to the caller to wrap the unsafe function in another function in order to pass it around. Unsafe code doesn't need to meet the same standards of ergonomics as safe code, provided that it's still possible to get optimal performance.

For example, CodeSandwich's example can be "fixed" using a closure: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=308c3ee61419427c617879fc4cb82738

@alercah
Copy link
Contributor

@alercah alercah commented Jan 14, 2019

I agree. UnsafeFn is meaningless and breaks the mechanics of unsafe proof obligations.

@brunoczim
Copy link

@brunoczim brunoczim commented Feb 13, 2019

I understand the argument against Unsafe Fn. But wouldn't this apply to unsafe fn pointers too?

@peterjoel
Copy link
Contributor

@peterjoel peterjoel commented Feb 13, 2019

I understand the argument against Unsafe Fn. But wouldn't this apply to unsafe fn pointers too?

Yes, I would say so.

@jinfagang
Copy link

@jinfagang jinfagang commented Jul 2, 2019

what does the difference between Fn and fn?

@syntacticsugarglider
Copy link

@syntacticsugarglider syntacticsugarglider commented Feb 5, 2020

What's the status of this? There are a number of F-unboxed_closures issues but this tracking issue doesn't appear to be... well, tracking the issue. I'm currently working with a project that requires erased closure types and supports #![no_std] and SmallBox-style tricks don't really help when I'm writing library code that lacks any information about the maximum size of the closure state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.