Function Pointer cast
Function Pointer cast
Posted Jan 30, 2024 15:52 UTC (Tue) by tialaramex (subscriber, #21167)In reply to: Function Pointer cast by khim
Parent article: Defining the Rust 2024 edition
What you've got there is just a function pointer, of type fn(i32, i32) -> i32 Although Rust doesn't have the uh, exciting variety of integer coercions of C, it does have coercions, and in particular what your snippet does is coerce the two ZSTs (which are distinct types) into merely function pointers (which are compatible if the functions have the same signature). Watch what happens if we modify your code a little:
fn main() { let mut add_or_sub = add; add_or_sub = if std::env::args().len() % 2 == 0 { add } else { sub }; println!("{}", add_or_sub(42, 2)); }
error[E0308]: mismatched types --> src/main.rs:3:68 | 3 | add_or_sub = if std::env::args().len() % 2 == 0 { add } else { sub }; | ^^^ expected fn item, found a different fn item | = note: expected fn item `fn(_, _) -> _ {add}` found fn item `fn(_, _) -> _ {sub}` = note: different fn items have unique types, even if their signatures are the same = help: consider casting both fn items to fn pointers using `as fn(i32, i32) -> i32`
Posted Jan 30, 2024 16:59 UTC (Tue)
by khim (subscriber, #9252)
[Link] (1 responses)
But isn't the fact that you now have
Posted Jan 30, 2024 18:18 UTC (Tue)
by tialaramex (subscriber, #21167)
[Link]
But in my response add_or_sub is now a function item, a Zero Size variable which is always (in this particular case) our add function. ZSTs have a singular value, which is why we don't need storage space for them, the value of the (now mis-named) add_or_sub is always just add, a specific function we wrote to add numbers together. Even another function with not just the same signature, but exactly the same body and resulting machine code is a different function and so cannot be assigned to the (again, now misnamed) add_or_sub variable.
Transmute is a red herring, transmuting things into a ZST is silly. If you can *spell* the ZST then you're welcome to have one, since it has only a single value the compiler knows from the type what its value is, we don't need to "transmute" it. However like a lambda type these function items are unnameable, so you can't do that.
Function pointers are very nameable, and I'd guess you've been thinking about function pointers all along, but I wanted to emphasise that Rust does have (and make good use of) types signifying specifically the function, not just a pointer.
Yes I imagine you can take a magic integer (with some well chosen value) and transmute it into a function pointer, and (on a typical modern computer) you could call the function via that pointer and it'd work. I am not surprised that MIRI cannot justify this, and I think there aren't a lot cases where anybody has a good reason to do it, so if "Miri doesn't like it" dissuades someone from doing this that's probably good.
Function Pointer cast
add_or_sub
which is not “a mere function pointer” means that you actually can make these (with transmute
) e.g.?Function Pointer cast