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 · 21 comments

Comments

Projects
None yet
@aturon
Copy link
Member

aturon commented Nov 5, 2015

Tracks stabilization for the Fn* traits.

Random bugs:

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Jul 12, 2016

FnOnce::Output is stabilized in #34365

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Aug 17, 2016

Could someone summarise what is blocking stabilisation here please?

@nagisa

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Member Author

aturon commented Aug 27, 2016

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

@brunoczim

This comment has been minimized.

Copy link

brunoczim commented Jan 18, 2018

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

@SimonSapin

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

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?).

@illustrious-you

This comment has been minimized.

Copy link

illustrious-you 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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Contributor

alercah commented Jan 14, 2019

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

@brunoczim

This comment has been minimized.

Copy link

brunoczim commented Feb 13, 2019

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

@peterjoel

This comment has been minimized.

Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.