-
Notifications
You must be signed in to change notification settings - Fork 17
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
Accessing associated consts (and uncalled function pointers) from a non-const trait #56
Comments
The open question here is one of type system design -- that's why this all already works on nightly; if we do not have to worry about a sane type system that ensures some form of const-safety, this is an easy problem. Specifically, the hard part is: we also will eventually want to have function pointers that can be called in The "use associated const of non-const trait impl" is the exact same problem. That's why I think we should use the same solution for everything, and the current RFC makes that hard. |
What I use for what struct MakeFFIPlugin<T>(T);
impl<T> MakeFFIPlugin<T>
where
T: Plugin
{
const MAKE: FFIPlugin = FFIPlugin {
major: T::VERSION.0,
minor: T::VERSION.1,
do_stuff: Some(do_stuff_callback::<T>),
};
}
struct Foo;
impl Plugin for Foo {
const VERSION: (u32, u32) = (1, 0);
fn do_stuff() {
println!("Hello!");
}
}
#[no_mangle]
static FOO_PLUGIN: FFIPlugin = MakeFFIPlugin::<Foo>::MAKE; I also use another workaround for passing the associated constants of a trait to |
Interesting, thanks @rodrimati1992 - I'm a little surprised that works since your initializers do basically the same amount of compile-time computation, but I'll try switching to that. (I guess the answer is they don't actually do computation, and your approach makes that explicit.) And yeah, wanting to avoid something that turns out to be an unsupportable design is exactly why we want to use stable :) |
Fair, but then just stabilizing what we currently have won't help. ;) |
Associated constants on stable can do a few more things than |
Ah, right, it turns out we're trying to do something more complicated with the type system. There's a large number of functions in We're currently handling that with multiple traits and a builder pattern. The base I don't think I can do that in a static initializer - while you can call I think I can do it with Alternatively, I can do it by asking users to write associated consts of type |
I think this issue can be closed, the example in the original post now compiles on Rust 1.61 (the current beta): https://play.rust-lang.org/?version=beta&mode=debug&edition=2021&gist=ffffcd69b4592ae252f2549ed1f82234 |
(if there's already an issue for this, please let me know - I've been looking around and I haven't quite seen it.)
In stable, you currently can't access associated consts of a trait in a const fn. I see some discussion in the hidden comments of rust-lang/rust#57563 and in #1 about this problem, but they seem geared towards the idea of having a
const trait
. I would like to be able to access associated consts in a non-const trait.Specifically, what I really want is to be able to get a function pointer from a trait, but not actually call the function. (This seems to me like it's basically equivalent to getting an associated const - it's something statically known at compile time.) And I want that function itself to be non-const. I see some discussion in rust-lang/rust#63997, but again, that seems like it's envisioning passing pointers to other const functions into the const function and calling them. I just want the pointer itself, which is const, and I want to let the function
Both of these work in nightly with
#![feature(const_fn)]
, but since the discussion in the above issues is leaning towards const traits and pointers to const fns, I wanted to make sure there was a plan for regular traits and (const) pointers to non-const fns. (Also, it seems to me like this specific case could be stabilized now, though I do see the comments about whether this would imply stabilizing trait bounds without requiring you to specifyconst impl
.)The motivating example here is providing plugins to some existing C program via FFI. Usually you'd register these by making some structure with some metadata and some function pointers, like
This basically perfectly matches Rust's trait concepts, so it'd be nicest to implement this by making a trait:
You want
make_ffi_plugin
to be a const fn so that you can assign it to a static. Sometimes you want this because the interface for loading plugins is to declare a static with a specific name, sometimes you just want this for security hardening (making sure that the resulting FFIPlugin struct is in the read-only section of program memory with a static lifetime and not on the heap):This works great in nightly Rust (playground link). We use this for Linux kernel ops structs (where the
extern "C"
callback function is more complicated than the above examples, and maps appropriately between raw pointers provided by the kernel and safe Rust types in our code).In stable Rust, it complains "trait bounds other than
Sized
on const fn parameters are unstable" and "function pointers in const fn are unstable". I think that's because of the two issues I linked above. But we're not fully using the trait inside the const fn - we're definitely not callingdo_stuff
from constant context - nor are we calling any function pointers. We just need references to them. (And we very much needPlugin
to be a non-const trait.)Would it be possible to stabilize this specific use case? (If this is the sort of thing that wants implementation help, I'd be happy to try!)
Is this resolved by the
?const
syntax from rust-lang/rfcs#2632? It's not clear to me whetherconst fn make_ffi_plugin<T: ?const Plugin>()
would be allowed to access associated consts + function pointers involving type T.The text was updated successfully, but these errors were encountered: