I have this code:
pub type f_t =
::std::option::Option<extern "C" fn(a: ::std::os::raw::c_int, ...)>;
#[repr(C)]
#[derive(Copy, Clone)]
#[derive(Debug)]
pub struct Foo {
pub f: f_t,
}
fn main() {
}
It does not compile because there is no default Clone implementation for functions with "..." at the end of args.
How does Rust handle this "..." at the end of line, does it do the same thing as "..." in C?
Rust can not compile this code, but if I comment , ..., it compiles fine. What is the difference, why does one class of function pointers implement Clone while the other does not?
How should I implement Clone for such functions?
It means approximately the same as it does in C. Rust does not have native variadic functions (you cannot implement one in Rust itself), but it supports the syntax as a special case for binding to C functions.
Rust does not know what the real signature of the C function is. So you can declare it as whatever you want, but if you get it wrong then calling the function will likely crash at runtime.
It's an unintentional omission, these function pointers are supposed to magically be Clone. On nightly and beta this is already fixed.
Related
What is the idiomatic way in rust for a function accepts a closure as argument or return a closure?
I see it can be done in at least the below 3 ways:
// 1
pub fn run_with_envs_guard1(envs: &HashMap<&str, &str>, f: &dyn FnOnce()) {}
// 2
pub fn run_with_envs_guard2(envs: &HashMap<&str, &str>, f: Box<dyn FnOnce()>) {}
// 3
pub fn run_with_envs_guard3<F: FnOnce()>(envs: &HashMap<&str, &str>, f: F) {}
Are there really some differences among these 3 ways? If yes, pls help to clarify, and which way is more idiomatic i should choose?
I am learning rust still, sorry if all the above ways are some bad/strange things.
Maybe a more specific question, why in way 1 and 2 i need the dyn keyword, but in 3 i don't, from my understanding, these all need dynamic dispatching, is it? as the actual function cannot be determined in compiling time
Abdul answers the first half of your question (and I agree completely with what he said), so I'll take a stab at the second half.
If you want to return a closure from a function, you can't return a type parameter, because that implies that you're returning an instance of any FnOnce, at the caller's choice. You can't return a &FnOnce, because you (usually) need to pass ownership to the caller. You could make it work with Box<FnOnce>, but that tends to just be clunky to work with. When returning closures from functions, I'm partial to the impl trait syntax.
pub fn test() -> impl FnOnce() {
|| { println!("It worked!") }
}
In argument position, writing impl FnOnce() as the type of something is equivalent to defining a type argument, as Abdul did in his answer. However, in return position, it's an entirely new feature that returns an opaque value. It says "I'm returning an FnOnce, and I'm not telling you which one it is". It's the same concept as a trait object, but without the overhead of throwing it in a box.
Responding to your edit
i don't, from my understanding, these all need dynamic dispatching, is it? as the actual function cannot be determined in compiling time
This is actually not necessarily true. If you see the dyn keyword, then there's definitely a dynamic (runtime) dispatch happening. To understand your other example, though, let's consider a simple trait that doesn't have the baggage of FnOnce.
pub trait MyTrait {}
struct Foo;
struct Bar;
impl MyTrait for Foo {}
impl MyTrait for Bar {}
pub fn example<T: MyTrait>(_arg: T) {
println!("It works!");
}
fn main() {
example(Foo);
example(Bar);
}
I claim there's no dynamic dispatch happening here. Rust monomorphizes functions with type parameters. That means that example is like a template function in C++. Every instantiation of it will end up being a separate function. So, really, during Rust's compilation, this will end up being more like
struct Foo;
struct Bar;
pub fn example1(_arg: Foo) {
println!("It works!");
}
pub fn example2(_arg: Foo) {
println!("It works!");
}
fn main() {
example1(Foo);
example2(Bar);
}
Two unrelated functions that happen to do something similar. Rust resolves all of the linkage statically, so there's no dispatch happening at runtime. In fact, we can prove it. Take the code I just posted above and compile it with debugging symbols on (rustc -g filename.rs). Then use a tool like nm (available on most Linux machines by default) to list all of the symbols in the linker table. Assuming you didn't turn any optimizations on, you should see two example functions. This is what they look like in my linker
0000000000005340 t _ZN10code7example17h46383f9ad372dc94E
00000000000053a0 t _ZN10code7example17h97b400359a146fcaE
or, with nm -C to demangle the function names
0000000000005340 t code::example
00000000000053a0 t code::example
Two different functions, each of which takes concrete arguments of specific types.
Your proposed FnOnce would work the same way.
pub fn run_with_envs_guard3<F: FnOnce()>(envs: &HashMap<&str, &str>, f: F) {}
Every closure in Rust has a distinct type, so every time this function is called, a new version of run_with_envs_guard3 will get made, specifically for that closure. That new function will know exactly what to do for the closure you just gave it. In 99% of cases, if you have optimizations turned on, these made-up local functions will get inlined and optimized out, so no harm done. But there's no dynamic dispatch here.
In the other two examples, we have a dyn FnOnce, which is more like what you'd expect coming from a traditionally object-oriented language. dyn FnOnce contains a dynamic pointer to some function somewhere that will be dispatched at runtime, the way you'd expect.
I would prefer the third one. Because the rust documentation suggest to Use FnOnce as a bound when you want to accept a parameter of function-like type and only need to call it once.
pub fn run_with_envs_guard3<F: FnOnce()>(envs: &HashMap<&str, &str>, f: F) {}
This means that the F to be bound by FnOnce(ie, F must implement FnOnce)
I'm reading some code and it has a consume function which makes it possible for me to pass my own function f.
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
where
F: FnOnce(&mut [u8]) -> Result<R>,
I wrote some similar code, but like this:
pub fn phy_receive(
&mut self,
f: &mut dyn FnMut(&[u8])
) -> u8 {
and to be fair I don't know what is the difference, aside from FnOnce vs FnMut. What is the difference between using dyn vs a generic type parameter to specify this function?
Using dyn with types results in dynamic dispatch (hence the dyn keyword), whereas using a (constrained) generic parameter results in monomorphism.
General explanation
Dynamic dispatch
Dynamic dispatch means that a method call is resolved at runtime. It is generally more expensive in terms of runtime resources than monomorphism.
For example, say you have the following trait
trait MyTrait {
fn f(&self);
fn g(&self);
}
and a struct MyStruct which implements that trait. If you use a dyn reference to that trait (e.g. &dyn MyTrait), and pass a reference to a MyStruct object to it, what happens is the following:
A "vtable" data structure is created. This is a table containing pointers to the MyStruct implementations of f and g.
A pointer to this vtable is stored with the &dyn MyTrait reference, hence the reference will be twice its usual size; sometimes &dyn references are called "fat references" for this reason.
Calling f and g will then result in indirect function calls using the pointers stored in the vtable.
Monomorphism
Monomorphism means that the code is generated at compile-time. It's similar to copy and paste. Using MyTrait and MyStruct defined in the previous section, imagine you have a function like the following:
fn sample<T: MyTrait>(t: T) { ... }
And you pass a MyStruct to it:
sample(MyStruct);
What happens is the following:
During compile time, a copy of the sample function is created specifically for the MyStruct type. In very simple terms, this is as if you copied and pasted the sample function definition and replaced T with MyStruct:
fn sample__MyStruct(t: MyStruct) { ... }
The sample(MyStruct) call gets compiled into sample__MyStruct(MyStruct).
This means that in general, monomorphism can be more expensive in terms of binary code size (since you are essentially duplicating similar chunks of code, but for different types), but there's no runtime cost like there is with dynamic dispatch.
Monomorphism is also generally more expensive in terms of compile times: because it essentially does copy-paste of code, codebases that use monomorphism abundantly tend to compile a bit slower.
Your example
Since FnMut is just a trait, the above discussion applies directly to your question. Here's the trait definition:
pub trait FnMut<Args>: FnOnce<Args> {
pub extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
Disregarding the extern "rust-call" weirdness, this is a trait just like MyTrait above. This trait is implemented by certain Rust functions, so any of those functions is analogous to MyStruct from above. Using &dyn FnMut<...> will result in dynamic dispatch, and using <T: FnMut<...>> will result in monomorphism.
My 2 cents and general advice
Certain situations will require you to use a dynamic dispatch. For example, if you have a Vec of external objects implementing a certain trait, you have no choice but to use dynamic dispatch. For example,
Vec<Box<dyn Debug>>. If those objects are internal to your code, though, you could use an enum type and monomorphism.
If your trait contains an associated type or a generic method, you will have to use monomorphism, because such traits are not object safe.
Everything else being equal, my advice is to pick one preference and stick with it in your codebase. From what I've seen, most people tend to prefer defaulting to generics and monomorphism.
From the book:
Rust won’t let us annotate a type with the Copy trait if the type, or any of its parts, has implemented the Drop trait. If the type needs something special to happen when the value goes out of scope and we add the Copy annotation to that type, we’ll get a compile time error.
Why was the design decision made to disallow Copy and Drop on the same type?
The Drop trait is used in an RAII context, typically when some resource needs to be released/closed when the object is destroyed.
In the other hand, a Copy type is a trivial type that can be copied with a memcpy only.
With those two descriptions, it is clearer that they are exclusive: it makes no sense to memcpy nontrivial data: what if we copy the data, and we drop one of the copies? The inner resource of the other copy will not be reliable anymore.
In fact, Copy in not even a "real" trait, in that it does not define any function. It is a special marker that says to the compiler: "you can duplicate myself with a simple bytes copy". So you cannot provide a custom implementation of Copy, because there is no implementation at all. However, you can mark a type as copyable:
impl Copy for Foo {}
or better, with a derive:
#[derive(Clone, Copy)]
struct Foo { /* ... */ }
This builds only if all the fields implement Copy. Otherwise, the compiler refuses to compile because this is unsafe.
For the sake of an example, let's suppose that the File struct implements Copy. Of course, this is not the case, and this example is wrong and cannot compile:
fn drop_copy_type<T>(T x)
where
T: Copy + Drop,
{
// The inner file descriptor is closed there:
std::mem::drop(x);
}
fn main() {
let mut file = File::open("foo.txt").unwrap();
drop_copy_type(file);
let mut contents = String::new();
// Oops, this is unsafe!
// We try to read an already closed file descriptor:
file.read_to_string(&mut contents).unwrap();
}
The other answers here are talking about why we don't usually want to implement both Copy and Drop for the same type, but that's not the same as explaining why it's forbidden. It might seem like a toy example like this should work just fine:
#[derive(Copy, Clone)]
struct Foo {
i: i32,
}
impl Drop for Foo {
fn drop(&mut self) {
// No problematic memory management here. Just print.
println!("{}", self.i);
}
}
fn main() {
let foo1 = Foo { i: 42 };
let foo2 = foo1;
// Shouldn't this just print 42 twice?
}
But indeed, if we try to compile that (using Rust 1.52), it fails as expected:
error[E0184]: the trait `Copy` may not be implemented for this type; the type has a destructor
--> src/main.rs:1:10
|
1 | #[derive(Copy, Clone)]
| ^^^^ Copy not allowed on types with destructors
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0184`.
See the "For more information" note at the bottom? Those are often helpful. Let's run rustc --explain E0184:
The `Copy` trait was implemented on a type with a `Drop` implementation.
Erroneous code example:
```
#[derive(Copy)]
struct Foo; // error!
impl Drop for Foo {
fn drop(&mut self) {
}
}
```
Explicitly implementing both `Drop` and `Copy` trait on a type is currently
disallowed. This feature can make some sense in theory, but the current
implementation is incorrect and can lead to memory unsafety (see
[issue #20126][iss20126]), so it has been disabled for now.
[iss20126]: https://github.com/rust-lang/rust/issues/20126
Following that issue link leads to a discussion of "zeroing-on-drop". Present-day Rust doesn't do this anymore, but up until around 2016 Rust implemented "dynamic drop" by zeroing all the bits of a value when dropping it. But of course that isn't a valid implementation if a type can be both Copy and Drop -- Rust can't zero out a value that you're allowed to keep using -- so implementing both of those traits on the same type was disallowed. The discussion ends with this interesting comment:
Anyhow, it's easiest to forbid it for now. We can always make it legal later if someone comes up with a persuasive use case. Idempotent destructors seem like a bit of an odd thing.
What's above is the explanation for Rust's current behavior, as best I can tell. But I think there's another reason to keep things the way they are, which I haven't seen discussed: Copy currently implies that a value can be both bitwise copied and also bitwise overwritten. Consider this code:
#[derive(Copy, Clone)]
struct Foo {
i: i32,
}
fn main() {
let mut ten_foos = [Foo { i: 42 }; 10];
let ten_more_foos = [Foo { i: 99 }; 10];
// Overwrite all the bytes of the first array with those of the second.
unsafe {
std::ptr::copy_nonoverlapping(&ten_more_foos, &mut ten_foos, 1);
}
}
This unsafe code is totally fine today. In fact, [T]::copy_from_slice will do exactly the same thing for any T: Copy. But would it still be ok, if Foo (or any other Copy type) were allowed to be Drop? Our code here, and the standard library code in copy_from_slice, would be destroying objects without dropping them!
Now, technically, failing to call the destructor of an object is allowed. There was a very interesting discussion back in the day that led to std::mem::forget going from unsafe to safe shortly before Rust 1.0. So it's possible that Rust could allow Copy + Drop without leading to any undefined behavior, despite this issue. But it would be quite surprising that certain (standard!) functions would fail to call the destructors you expect. The property that "Copy objects can be bitwise copied and bitwise overwritten" seems like a good one to keep.
Quoting the documentation.
[...] [A]ny type implementing Drop can't be Copy, because it's managing some resource besides its own size_of::<T> bytes.
Rust has the ptr::NonNull type that represents a non-NULL pointer. Is it safe to use this type in FFI?
Is it guaranteed to have same binary representation (ignoring non-FFI context such as Option optimizations), alignment, register usage as *mut T?
For example, could I implement this interface:
void call_me_from_c(char *without_nulls) __attribute__((nonnull));
with
extern "C" fn call_me_from_c(without_nulls: ptr::NonNull<c_char>)
I don't expect this to do anything (apart from causing UB when misused with NULL ;), but I would like the interface to document that the function requires non-NULL arguments.
It depends on what version of Rust you are compiling with.
Rust 1.29 and up
NonNull now has repr(transparent), so it is safe to use in FFI so long as the wrapped type is safe.
#[stable(feature = "nonnull", since = "1.25.0")]
#[repr(transparent)]
pub struct NonNull<T: ?Sized> {
pointer: NonZero<*const T>,
}
Before Rust 1.29
I would not use it for such. The main reason is due to its definition:
#[stable(feature = "nonnull", since = "1.25.0")]
pub struct NonNull<T: ?Sized> {
pointer: NonZero<*const T>,
}
More specifically, I'm concerned about what's not in the definition: #[repr(transparent)] (emphasis mine):
Structs with this representation have the same layout and ABI as the single non-zero sized field.
I've experienced miscompilation due to putting newtypes in a FFI function that were solved by repr(transparent), so this isn't just an academic exercise.
I have written a problem solver in Rust which as a subroutine needs to make calls to a function which is given as a black box (essentially I would like to give an argument of type Fn(f64) -> f64).
Essentially I have a function defined as fn solve<F>(f: F) where F : Fn(f64) -> f64 { ... } which means that I can call solve like this:
solve(|x| x);
What I would like to do is to pass a more complex function to the solver, i.e. a function which depends on multiple parameters etc.
I would like to be able to pass a struct with a suitable trait implementation to the solver. I tried the following:
struct Test;
impl Fn<(f64,)> for Test {}
This yield the following error:
error: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625)
I would also like to add a trait which includes the Fn trait (which I don't know how to define, unfortunately). Is that possible as well?
Edit:
Just to clarify: I have been developing in C++ for quite a while, the C++ solution would be to overload the operator()(args). In that case I could use a struct or class like a function. I would like to be able to
Pass both functions and structs to the solver as arguments.
Have an easy way to call the functions. Calling obj.method(args) is more complicated than obj(args) (in C++). But it seems that this behavior is not achievable currently.
The direct answer is to do exactly as the error message says:
Use parenthetical notation instead
That is, instead of Fn<(A, B)>, use Fn(A, B)
The real problem is that you are not allowed to implement the Fn* family of traits yourself in stable Rust.
The real question you are asking is harder to be sure of because you haven't provided a MCVE, so we are reduced to guessing. I'd say you should flip it around the other way; create a new trait, implement it for closures and your type:
trait Solve {
type Output;
fn solve(&mut self) -> Self::Output;
}
impl<F, T> Solve for F
where
F: FnMut() -> T,
{
type Output = T;
fn solve(&mut self) -> Self::Output {
(self)()
}
}
struct Test;
impl Solve for Test {
// interesting things
}
fn main() {}