This simple program:
fn main() {
let b: Box<i32> = Box::new(1);
b.into_raw();
}
Produces this inconvenient error when compiled with Rust 1.12.0:
error: no method named `into_raw` found for type `Box<i32>` in the current scope
--> <anon>:3:7
|
3 | b.into_raw();
| ^^^^^^^^
|
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
= note: candidate #1 is defined in an impl for the type `Box<_>`
This is because into_raw is not defined to take self as parameter, but instead is defined as:
impl Box<T: ?Sized> {
fn into_raw(b: Box<T>) -> *mut T;
}
This seems inconvenient, and I cannot find a rationale.
So... why?
Because 99.995% of the time (statistic totally made up), you expect method calls to happen to the thing being pointed to, not to the pointer itself. As a result, the "smart pointer" types in Rust generally avoid doing anything to break that expectation. An obvious exception would be something like Rc/Arc implementing Clone directly.
Box implements Deref, which means that all methods that are enclosed by the Box are automatically made available; from the outside, Box<T> and T look and act the same.
If into_raw were a method instead of an associated function, it would shadow any into_raw method on the contained type.
There are other examples of these enhancing associated functions on Rc, such as downgrade or try_unwrap, or on Arc, such as make_mut.
Related
I have been writing a program in Rust where I encountered an error relating to moving the data of a Shared Reference.
I made some research, but I was unable to find the cause of the error in the program I have written. Here is the simplified version of the program:
enum A {
Won = 1,
}
struct B {
result: A,
}
fn print_game(game: &B) {
println!("{}", game.result as u32);
}
fn main() {
let game: B = B { result: A::Won };
print_game(&game);
}
The above program when compiled, throws the below error:
error[E0507]: cannot move out of `game.result` which is behind a shared reference
--> src/main.rs:10:20
|
10 | println!("{}", game.result as u32);
| ^^^^^^^^^^^ move occurs because `game.result` has type `A`, which does not implement the `Copy` trait
From the error I can infer that the data in game.result is moved, but, I am not sure where it is moved and why it's been moved.
In rust, default behaviour for custom type is 'move' unless you implement Copy trait for the type.
If the value bound to a variable moves, the variable can not be used anymore. Developers new to Rust must get used to it.
Move is attempted in 'game.result as i32' portion of your code. Type casting is also counted as move for value of 'move' type.
I agree with the solution already mentioned above, just add the line
#[derive(Clone, Copy)]
Rust Playground
Traits like Deref, Into, From etc. could also be relevant, but depends...
By 'move' compiler means just transfer of ownership, not the change of data location in memory.
Suppose we have a variable v bound to a 'move' data. In a type casting like 'v as T' the ownership of data is detached from v and the bytes are reinterpreted as type T.
But why is this casting not allowed in your example?
Actual cause of error is that 'game' is a shared reference of type &B and you tried to use it to detach original ownership of data referred by it.
Shared reference can never be used to move referred data or part of it. <<
In this case I think your enum A just needs a #[derive(Clone, Copy)].
Rust Playground Example
Another option would be to refactor the program to only print what is actually needed:
…
fn main() {
let game: B = B { result: A::Won };
print_result(game.result);
}
Playground
This function returns a closure. Using impl Fn() as the closure type is OK:
fn foo() -> impl Fn() {
|| ()
}
But this won't work:
fn foo<T: Fn()>() -> T {
|| ()
}
Nor this:
fn foo<T>() -> T
where
T: Fn(),
{
|| ()
}
Why do the last two examples not work?
In both of the "non-working" examples, it might be helpful to think about why T is called a type parameter.
It's up to the caller of a function to determine its arguments, and it's the same with types. Sometimes they are specified explicitly and sometimes they are inferred, but it's always the caller that gets to say what they are and the implementation must work for all possible types. This is sometimes called universal quantification (in mathematics, ∀T).
However, the type of the closure in your examples cannot be provided by the caller because it is an implementation detail of the function body. The type of the closure is fixed by the function and it doesn't make sense for the caller to specify a different type.
In your first example, it works because impl Fn() in return position means exactly what is happening. That is, from the caller's perspective the concrete type is unknown but it's uniquely determined by the implementation. That's known as existentially quantified (in mathematics, ∃T) - a type that we can be confident exists, though we can't necessarily know what it actually is.
This is so, because foo<T> means that the caller chooses what type T is. And since each closure has it's own type caller cannot pick it. This is exactly why impl Trait was created for.
Generics need to be specified by the caller. They cannot be specified from within your function implementation.
In general, there are four ways of returning a function in Rust:
Via full type specification. This isn't possible in your case because closures types are anonymous and cannot be written in code. This is only possible with references to functions that are not closures.
Via impl Fn, as you implemented it. This is the most common way.
Via Box<dyn Fn>. It has the advantage that it doesn't require an impl, but apart from a couple of corner cases, this is rarely necessary.
Via function pointer. This is rarely used for closures because it only works if the closure is non-capturing. But technically it is another way of returning a closure.
Just for completeness, here is the version with Box<dyn Fn>:
fn foo() -> Box<dyn Fn()> {
Box::new(|| ())
}
And here is the version with a function pointer:
fn foo() -> fn() {
|| ()
}
Explanation:
impl Fn is kind of like an internally-defined generic. The return value compiles to a real type, but all the caller has to know that this real type implements Fn. It has very low overhead because the actual type is known to the compiler (even if it isn't known to the user) and it will be able to resolve calling its methods at compile time.
Box<dyn Fn>. Unlike impl Fn, this is not a real type, but a trait object. The compiler looses the knowledge about the actual type behind it. All it knows is that it implements the trait Fn, and calling its method will cause a runtime lookup in its vtable to call the correct method.
A fn function pointer. Unlike dyn Fn, which is a fat pointer with a vtable, this is just a normal thin pointer. Therefore it can't store any meta-information and can only hold functions that have no internal state. In the case of generics, this means it can only hold generics that don't capture any variables.
I was experimenting with function pointer magic in Rust and ended up with a code snippet which I have absolutely no explanation for why it compiles and even more, why it runs.
fn foo() {
println!("This is really weird...");
}
fn caller<F>() where F: FnMut() {
let closure_ptr = 0 as *mut F;
let closure = unsafe { &mut *closure_ptr };
closure();
}
fn create<F>(_: F) where F: FnMut() {
caller::<F>();
}
fn main() {
create(foo);
create(|| println!("Okay..."));
let val = 42;
create(|| println!("This will seg fault: {}", val));
}
I cannot explain why foo is being invoked by casting a null pointer in caller(...) to an instance of type F. I would have thought that functions may only be called through corresponding function pointers, but that clearly can't be the case given that the pointer itself is null. With that being said, it seems that I clearly misunderstand an important piece of Rust's type system.
Example on Playground
This program never actually constructs a function pointer at all- it always invokes foo and those two closures directly.
Every Rust function, whether it's a closure or a fn item, has a unique, anonymous type. This type implements the Fn/FnMut/FnOnce traits, as appropriate. The anonymous type of a fn item is zero-sized, just like the type of a closure with no captures.
Thus, the expression create(foo) instantiates create's parameter F with foo's type- this is not the function pointer type fn(), but an anonymous, zero-sized type just for foo. In error messages, rustc calls this type fn() {foo}, as you can see this error message.
Inside create::<fn() {foo}> (using the name from the error message), the expression caller::<F>() forwards this type to caller without giving it a value of that type.
Finally, in caller::<fn() {foo}> the expression closure() desugars to FnMut::call_mut(closure). Because closure has type &mut F where F is just the zero-sized type fn() {foo}, the 0 value of closure itself is simply never used1, and the program calls foo directly.
The same logic applies to the closure || println!("Okay..."), which like foo has an anonymous zero-sized type, this time called something like [closure#src/main.rs:2:14: 2:36].
The second closure is not so lucky- its type is not zero-sized, because it must contain a reference to the variable val. This time, FnMut::call_mut(closure) actually needs to dereference closure to do its job. So it crashes2.
1 Constructing a null reference like this is technically undefined behavior, so the compiler makes no promises about this program's overall behavior. However, replacing 0 with some other "address" with the alignment of F avoids that problem for zero-sized types like fn() {foo}, and gives the same behavior!)
2 Again, constructing a null (or dangling) reference is the operation that actually takes the blame here- after that, anything goes. A segfault is just one possibility- a future version of rustc, or the same version when run on a slightly different program, might do something else entirely!
The type of fn foo() {...} is not a function pointer fn(), it's actually a unique type specific to foo. As long as you carry that type along (here as F), the compiler knows how to call it without needing any extra pointers (a value of such a type carries no data). A closure that doesn't capture anything works the same way. It only gets dicey when the last closure tries to look up val because you put a 0 where (presumably) the pointer to val was supposed to be.
You can observe this with size_of, in the first two calls, the size of closure is zero, but in the last call with something captured in the closure, the size is 8 (at least on the playground). If the size is 0, the program doesn't have to load anything from the NULL pointer.
The effective cast of a NULL pointer to a reference is still undefined behavior, but because of type shenanigans and not because of memory access shenanigans: having references that are really NULL is in itself illegal, because memory layout of types like Option<&T> relies on the assumption that the value of a reference is never NULL. Here's an example of how it can go wrong:
unsafe fn null<T>(_: T) -> &'static mut T {
&mut *(0 as *mut T)
}
fn foo() {
println!("Hello, world!");
}
fn main() {
unsafe {
let x = null(foo);
x(); // prints "Hello, world!"
let y = Some(x);
println!("{:?}", y.is_some()); // prints "false", y is None!
}
}
Given that rust is built on top of LLVM, and that what you're doing is guaranteed UB, you're likely hitting something similar to https://kristerw.blogspot.com/2017/09/why-undefined-behavior-may-call-never.html. This is one of many reasons why safe rust works to eliminate all UB.
Although this is entirely up to UB, here's what I assume might be happening in the two cases:
The type F is a closure with no data. This is equivalent to a function, which means that F is a function item. What this means is that the compiler can optimize any call to an F into a call to whatever function produced F (without ever making a function pointer). See this for an example of the different names for these things.
The compiler sees that val is always 42, and hence it can optimize it into a constant. If that's the case, then the closure passed into create is again a closure with no captured items, and hence we can follow the ideas in #1.
Additionally, I say this is UB, however please note something critical about UB: If you invoke UB and the compiler takes advantage of it in an unexpected way, it is not trying to mess you up, it is trying to optimize your code. UB after all, is about the compiler mis-optimizing things because you've broken some expectations it has. It is hence, completely logical that the compiler optimizes this way. It would also be completely logical that the compiler doesn't optimize this way and instead takes advantage of the UB.
This is "working" because fn() {foo} and the first closure are zero-sized types. Extended answer:
If this program ends up executed in Miri (Undefined behaviour checker), it ends up failing because NULL pointer is dereferenced. NULL pointer cannot ever be dereferenced, even for zero-sized types. However, undefined behaviour can do anything, so compiler makes no promises about the behavior, and this means it can break in the future release of Rust.
error: Undefined Behavior: memory access failed: 0x0 is not a valid pointer
--> src/main.rs:7:28
|
7 | let closure = unsafe { &mut *closure_ptr };
| ^^^^^^^^^^^^^^^^^ memory access failed: 0x0 is not a valid pointer
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `caller::<fn() {foo}>` at src/main.rs:7:28
note: inside `create::<fn() {foo}>` at src/main.rs:13:5
--> src/main.rs:13:5
|
13 | func_ptr();
| ^^^^^^^^^^
note: inside `main` at src/main.rs:17:5
--> src/main.rs:17:5
|
17 | create(foo);
| ^^^^^^^^^^^
This issue can be easily fixed by writing let closure_ptr = 1 as *mut F;, then it will only fail on line 22 with the second closure that will segfault.
error: Undefined Behavior: inbounds test failed: 0x1 is not a valid pointer
--> src/main.rs:7:28
|
7 | let closure = unsafe { &mut *closure_ptr };
| ^^^^^^^^^^^^^^^^^ inbounds test failed: 0x1 is not a valid pointer
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `caller::<[closure#src/main.rs:22:12: 22:55 val:&i32]>` at src/main.rs:7:28
note: inside `create::<[closure#src/main.rs:22:12: 22:55 val:&i32]>` at src/main.rs:13:5
--> src/main.rs:13:5
|
13 | func_ptr();
| ^^^^^^^^^^
note: inside `main` at src/main.rs:22:5
--> src/main.rs:22:5
|
22 | create(|| println!("This will seg fault: {}", val));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Why it didn't complain about foo or || println!("Okay...")? Well, because they don't store any data. When referring to a function, you don't get a function pointer but rather a zero-sized type representing that specific function - this helps with monomorphization, as each function is distinct. A structure not storing any data can be created from aligned dangling pointer.
However, if you explicitly say the function is a function pointer by saying create::<fn()>(foo) then the program will stop working.
I have a piece of code like this:
use std::cell::RefCell;
use std::rc::Rc;
struct A(bool);
impl A {
fn get_ref(&self) -> &Rc<RefCell<bool>> {
&Rc::new(RefCell::new(self.0))
}
fn copy_ref(&self) -> &Rc<RefCell<bool>> {
Rc::clone(self.get_ref())
}
}
fn main() {
let a = A(true);
a.copy_ref();
}
and I received warning complaining about the Rc::clone function not getting a reference:
error[E0308]: mismatched types
--> src/main.rs:12:9
|
12 | Rc::clone(self.get_ref())
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `std::rc::Rc`
|
= note: expected type `&std::rc::Rc<std::cell::RefCell<bool>>`
found type `std::rc::Rc<std::cell::RefCell<bool>>`
I have been working on this all night but I cannot get it to work. The method get_ref is already typed as returning &Rc<RefCell<bool>>, but why would the compiler give the error?
The error is not talking about the argument you put into Arc::clone(), but the whole expression Rc::clone(...) which has a different type (Rc<...>) than the return type of your function (&Rc<...>).
If you were passing a wrong argument to Rc::clone, it would like look this:
--> src/main.rs:13:19
|
13 | Rc::clone(false)
| ^^^^^ expected reference, found bool
|
= note: expected type `&std::rc::Rc<_>`
found type `bool`
So the naive way to fix the type error is to write &Rc::clone(...) instead. Then the last expression of your function has the same type as your function's declared return type. But as you will notice, you will get other errors afterwards.
Let's take a step back to see that your approach is flawed here. For the most important point, please see "Is there any way to return a reference to a variable created in a function?". Spoiler: you really don't want to. So constructs like your get_ref() just don't make sense, as you return a reference to a variable you create inside your function (a variable of type Rc).
In your case the direct solution is probably pretty simple: just remove the reference. Rc<T> is already a pointer/reference type, so there is no need (in general) to have a reference to it.
However, since you are using Rc, you are probably interested in reference counting. So in that case, you probably shouldn't create a new Rc every time the function is called. Otherwise you could end up with a bunch of Rcs with reference count 1, which is not really the point. So instead, your type A should already store an Rc<RefCell<bool>>.
But all I'm doing here is guessing what you actually want to do which is not clear from your question. Maybe you can ask a different question, or add the information to this question, or explain this in the comments.
I'm reading through the Rust documentation on lifetimes. I tried something like:
struct S {
x: i8,
}
impl S {
fn fun(self) {}
fn print(&self) {
println!("{}", self.x);
}
}
fn main() {
let s = S { x: 1 };
s.fun();
s.print();
}
I get the following error:
error[E0382]: borrow of moved value: `s`
--> src/main.rs:16:5
|
15 | s.fun();
| - value moved here
16 | s.print();
| ^ value borrowed here after move
|
= note: move occurs because `s` has type `S`, which does not implement the `Copy` trait
This is because the fun(self) method takes ownership of the s instance. This is solved by changing to fun(&self).
I can't see why you would ever want to have a method on an object take control of itself. I can think of only one example, a destructor method, but if you wanted to do dispose of the object then it would be taken care of by the owner of the object anyway (i.e. scope of main in this example).
Why is it possible to write a method that takes ownership of the struct? Is there ever any circumstance where you would want this?
The idiomatic way to refer to a method that "takes control" of self in the Rust standard library documentation is to say that it "consumes" it. If you search for this, you should find some examples:
Option::unwrap_or_default
A lot in the Iterator trait.
As to why: you can try rewriting Iterator::map — you would end up having a lifetime parameter wandering around that would quickly become unmanageable. Why? Because the Map iterator is based upon the previous one, so the borrow checker will enforce that you can only use one of the two at the same time.
Conversion from type A to type B commonly involves functions taking self by value. See the implementors of Into and From traits for concrete examples.