Disable Implicit Deref Coercions - rust

My question here is quite specific. I want to disable implicit deref coercions (let's say because I don't like them). More specifically, I want this code to fail:
fn main() {
let x = Box::new(0);
let mut y = &x;
y = &mut y;
println!("GOT {}",*y);
}
To my mind, this is a pretty nonsensical example. But, it compiles because (I believe) &mut T coerces to T and, hence, the statement y = &mut y is a nop.
Assuming this is right, how do I prevent Rust from doing this? I tried, for example, using #[no_implicit_prelude] but with no joy.

The code you have given does not actually use any auto-dereferencing. The type of y is &Box<i32> and the println works because the Display formatting for Box is to just delegate to its contents Display implementation.
If I change your example slightly, we can bring auto-dereferencing into play:
fn main() {
let x = Box::new(0);
let mut y: &i32 = &x; // <-- Deref impl is used here
y = &mut y;
println!("GOT {}", y);
}
You cannot disable any traits that are implemented for built-in types. You could make your own Box that doesn't implement Deref:
use std::{boxed, fmt};
struct Box<T>(boxed::Box<T>);
impl<T> Box<T> {
pub fn new(value: T) -> Self {
Self(boxed::Box::new(value))
}
}
impl<T: fmt::Display> fmt::Display for Box<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
Auto-dereferencing does not work:
fn main() {
let x = Box::new(0);
let mut y: &i32 = &x; // <-- Error: expected `i32`, found struct `Box`
y = &mut y;
println!("GOT {}", y);
}
But you can still print the box itself:
fn main() {
let x = Box::new(0);
let mut y = &x;
y = &mut y;
println!("GOT {}", y); // y: &Box<i32>
}
I'm not sure why you would do this though. You will have to re-implement a lot of Box functionality to make this generally useful, and it isn't at all clear what are the advantages of not having a Deref impl.

Related

Implement mem::swap in rust without std lib

I am trying to write a mem::swap function without using any std lib functions. i am totally new to rust and still trying to make sense of how to use rust language.
below is my code
fn swap<T: std::fmt::Display>(x: &mut T, y: &mut T) {
unsafe {
// Give ourselves some scratch space to work with
let mut t: &mut T = y;
y = x;
x = t;
}
}
fn main() {
println!("Hello, world!");
let mut x = Box::new(5);
let mut y = Box::new(42);
let mut t = Box::new(0);
swap(&mut x, &mut y);
}
and i am facing below error
error: lifetime may not live long enough
--> src/main.rs:4:29
|
1 | fn swap<T: std::fmt::Display>(x: &mut T, y: &mut T) {
| - - let's call the lifetime of this reference `'2`
| |
| let's call the lifetime of this reference `'1`
...
4 | let mut t: &mut T = y;
| ^ assignment requires that `'2` must outlive `'1`
|
help: consider introducing a named lifetime parameter
|
1 | fn swap<'a, T: std::fmt::Display>(x: &'a mut T, y: &'a mut T) {
| +++ ++ ++
what does 'lifetime may not live long enough' mean ?
is there a simple way to write mem::swap code in rust ?
You need to Copy the data. The reference you're using is useless for this purpose. You need to actually alter what both x and y reference.
For example:
fn swap<T>(a: &mut T, b: &mut T) where T : Copy {
(*a,*b) = (*b, *a)
}
fn main() {
let mut a = 1;
let mut b = 2;
swap(&mut a,&mut b);
println!("a={}, b={}", a, b);
}
If you set up the conditions here, it's really a one-liner, Rust will figure out the "temporary" stuff for you. In fact, having a function to do this is actually kind of overkill, since you can just do that single line anywhere in your code as you would normally.
Maybe you want to optimize this around boxed values, taking Box<T> as an argument instead, in which case you could swap references within the box instead of copying, but that's a specialization.
How about using core::ptr::swap to swap raw pointers *mut T.
use core::ptr::swap;
fn custom_swap<T>(x: &mut T, y: &mut T) {
unsafe {
(x as *mut T).swap(y as *mut T);
}
}
fn main() {
println!("Hello, world!");
let mut x = Box::new(5);
let mut y = Box::new(42);
println!("x={}, y={}", x, y);
custom_swap(&mut x, &mut y);
println!("x={}, y={}", x, y);
}
output
Hello, world!
x=5, y=42
x=42, y=5

Borrow a struct field mutably and pass it to mutable methods

Because rust doesn't track individual field borrows across method calls - it assumes you've borrowed from the whole struct, it's not possible to borrow a field from the struct, return it, and then pass that into other mutable methods. That sounds contrived but I have this exact issue right now.
struct Foo {
x: i32,
y: i32
}
impl Foo {
pub fn borrow_x(&mut self) -> &mut i32 {
&mut self.x
}
pub fn cross_product(&mut self, other: &mut i32) {
self.y *= *other;
*other *= self.y;
}
}
fn main() {
let mut foo = Foo{x: 2, y: 4};
let x_ref = foo.borrow_x();
foo.cross_product(x_ref);
println!("x={} y={}", foo.x, foo.y);
}
This of course isn't permitted in rust, the error from the compiler is:
error[E0499]: cannot borrow `foo` as mutable more than once at a time
--> src/main.rs:20:5
|
19 | let x_ref = foo.borrow_x();
| --- first mutable borrow occurs here
20 | foo.cross_product(x_ref);
| ^^^ ----- first borrow later used here
| |
| second mutable borrow occurs here
My first reaction is to use unsafe to tell the compiler that it doesn't really borrow from self:
pub fn borrow_x<'a>(&mut self) -> &'a mut i32 {
unsafe {
std::mem::transmute::<&mut i32, &'a mut i32>(&mut self.x)
}
}
It works, but it requires that you don't actually break rust's aliasing rules and reference foo.x elsewhere by accident.
Then I thought maybe I could split the struct so that the borrow and cross_product methods are on different sibling structs. This does work:
struct Bar {
x: X,
y: Y,
}
struct X {
inner: i32
}
impl X {
pub fn borrow_x(&mut self) -> &mut i32 {
&mut self.inner
}
}
struct Y {
inner: i32
}
impl Y {
pub fn cross_product(&mut self, other: &mut i32) {
self.inner *= *other;
*other *= self.inner;
}
}
fn main() {
let mut bar = Bar{x: X{inner: 2}, y: Y{inner: 4}};
let x_ref = bar.x.borrow_x();
bar.y.cross_product(x_ref);
println!("x={} y={}", bar.x.inner, bar.y.inner);
}
I think one could ditch the method all-together and pass references to both fields into cross_product as a free function. That should be equivalent to the last solution. I find that kind of ugly though, especially as the number of fields needed from the struct grow.
Are there other solutions to this problem?
The thing to keep in mind is that rust is working at a per-function level.
pub fn cross_product(&mut self, other: &mut i32) {
self.y *= *other;
*other *= self.y;
}
The mutability rules ensure that self.y and other are not the same thing.
If you're not careful you can run into this kind of bug in C++/C/Java quite easily.
i.e. imagine if instead of
let x_ref = foo.borrow_x();
foo.cross_product(x_ref);
you were doing
let y_ref = foo.borrow_y();
foo.cross_product(y_ref);
What value should foo.y end up with? (Allowing these to refer to the same object can cause certain performance optimisations to not be applicable too)
As you mentioned, you could go with a free function
fn cross_product(a: &mut i32, b: &mut i32) {
a *= b;
b *= a;
}
but I'd consider ditching mutability altogether
fn cross_product(a:i32, b:i32) -> (i32,i32) {
(a*b, a*b*b)
}
ASIDE: If the return value seems odd to you (it did to me initially too) and you expected (a*b, a*b) you need to think a little harder... and I'd say that alone is a good reason to avoid the mutable version.
Then I can use it like this
let (_x,_y) = cross_product(foo.x, foo.y);
foo.x = _x;
foo.y = _y;
This is a bit verbose, but when RFC-2909 lands we can instead write:
(foo.y, foo.x) = cross_product(foo.x, foo.y);

Mutable borrow into two parts with cleanup

I have some object that I want to split into two parts via a mutable borrow, then combine those back together into the original object when the split references go out of scope.
The simplified example below is for a Count struct that holds a single i32, which we want to split into two &mut i32s, who are both incorporated back into the original Count when the two mutable references go out of scope.
The approach I am taking below is to use an intermediate object CountSplit which holds a mutable reference to the original Count object and has the Drop trait implemented to do the re-combination logic.
This approach feels kludgy. In particular, this is awkward:
let mut ms = c.make_split();
let (x, y) = ms.split();
Doing this in one line like let (x, y) = c.make_split().split(); is not allowed because the intermediate object must have a longer lifetime. Ideally I would be able to do something like let (x, y) = c.magic_split(); and avoid exposing the intermediate object altogether.
Is there a way to do this which doesn't require doing two let's every time, or some other way to tackle this pattern that would be more idiomatic?
#[derive(Debug)]
struct Count {
val: i32,
}
trait MakeSplit<'a> {
type S: Split<'a>;
fn make_split(&'a mut self) -> Self::S;
}
impl<'a> MakeSplit<'a> for Count {
type S = CountSplit<'a>;
fn make_split(&mut self) -> CountSplit {
CountSplit {
top: self,
second: 0,
}
}
}
struct CountSplit<'a> {
top: &'a mut Count,
second: i32,
}
trait Split<'a> {
fn split(&'a mut self) -> (&'a mut i32, &'a mut i32);
}
impl<'a, 'b> Split<'a> for CountSplit<'b> {
fn split(&mut self) -> (&mut i32, &mut i32) {
(&mut self.top.val, &mut self.second)
}
}
impl<'a> Drop for CountSplit<'a> {
fn drop(&mut self) {
println!("custom drop occurs here");
self.top.val += self.second;
}
}
fn main() {
let mut c = Count { val: 2 };
println!("{:?}", c); // Count { val: 2 }
{
let mut ms = c.make_split();
let (x, y) = ms.split();
println!("split: {} {}", x, y); // split: 2 0
// each of these lines correctly gives a compile-time error
// c.make_split(); // can't borrow c as mutable
// println!("{:?}", c); // or immutable
// ms.split(); // also can't borrow ms
*x += 100;
*y += 5000;
println!("split: {} {}", x, y); // split: 102 5000
} // custom drop occurs here
println!("{:?}", c); // Count { val: 5102 }
}
playground:
I don't think a reference to a temporary value like yours can be made to work in today's Rust.
If it's any help, if you specifically want to call a function with two &mut i32 parameters like you mentioned in the comments, e.g.
fn foo(a: &mut i32, b: &mut i32) {
*a += 1;
*b += 2;
println!("split: {} {}", a, b);
}
you can already do that with the same number of lines as you'd have if your chaining worked.
With the chaining, you'd call
let (x, y) = c.make_split().split();
foo(x, y);
And if you just leave out the conversion to a tuple, it looks like this:
let mut ms = c.make_split();
foo(&mut ms.top.val, &mut ms.second);
You can make it a little prettier by e.g. storing the mutable reference to val directly in CountSplit as first, so that it becomes foo(&mut ms.first, &mut ms.second);. If you want it to feel even more like a tuple, I think you can use DerefMut to be able to write foo(&mut ms.0, &mut ms.1);.
Alternatively, you can of course formulate this as a function taking a function
impl Count {
fn as_split<F: FnMut(&mut i32, &mut i32)>(&mut self, mut f: F) {
let mut second = 0;
f(&mut self.val, &mut second);
self.val += second;
}
}
and then just call
c.as_split(foo);

Assignment of references in Rust

The following code doesn't compile, because x is used after move (since x has type &mut u8, which does not implement the Copy trait)
fn main() {
let mut a: u8 = 1;
let x: &mut u8 = &mut a;
let y = x;
x;
}
And as I understand y implicitly has type &mut u8
But if I specify the type of y explicitly it compiles. The following code compiles
fn main() {
let mut a: u8 = 1;
let x: &mut u8 = &mut a;
let y: &mut u8 = x;
x;
}
By the way if I change let y: &mut u8 = x; to let y: &u8 = x; it also compiles.
It seems to me nothing has changed, y is &mut u8 in the first example and it is &mut u8 in the second but the former doesn't compile and the latter does compile.
Why? What's the difference?
&mut u8 is not a complete type. All reference types must have a lifetime parameter on them. When you elide it, the Rust compiler must infer it, and it will pick the shortest lifetime possible. In your first example, the first step of desugaring is (using a fake syntax from the Rustonomicon):
fn main() {
let mut a: u8 = 1;
'a: {
let x: &'a mut u8 = &'a mut a; // the lifetime of x must last until it's use at the end
let y = x;
x;
}
}
This is still not completely explicit, since the type of y is still not known. What is it? Well, since it's being assigned from x, which is a &'a mut u8, it should also be a &'a mut u8. Note that this is not following the "shortest lifetime possible" rule of lifetime elision. You didn't elide a lifetime, you elided the whole type, which is reconstructed by type inference.
fn main() {
let mut a: u8 = 1;
'a: {
let x: &'a mut u8 = &'a mut a; // the lifetime of x must last until its use at the end
let y: &'a mut u8 = x;
x;
}
}
Well, that's no good. Since y has the same lifetime as x, its creation involves moving the reference in x and making x invalid. The program is thus rejected for trying to use x.
Adding the signature to y essentially gives the compiler a new place where it can infer lifetimes. Before, normal type inference made y have the same type as x, which meant it lasted as long as x and made x unusable. Now, y doesn't need to have the same type as x; the lifetime of the borrow can be different. In particular, it is made shorter.
fn main() {
let mut a: u8 = 1;
'a: {
let x: &'a mut u8 = &'a mut a; // the lifetime of x must last until it's use at the end
'b: {
let y: &'b mut u8 = x; // y and x can now have different lifetimes, *x is reborrowed here
}
x; // x not moved from, still valid
}
}
Now, instead of moving the reference x into y and making it invalid, the value *x is temporarily "reborrowed" to make y, as by let y: &'b mut u8 = &'b mut *x.
The other possible fix is to explicitly say "borrow *x again with a different lifetime":
fn main() {
let mut a: u8 = 1;
let x: &mut u8 = &mut a;
let y = &mut *x;
x;
}
The principle is the same as before: saying & more often gives the compiler more places where it can massage the lifetimes in the program to make everything work.

How can I reborrow a mutable reference without passing it to a function?

I have found a case where manually inlining a function changes the way the borrow-checker treats it, such that it no longer compiles. Presumably it is relying on the information in the function signature. How can I provide this information in the inlined version?
How I think it's working
Let 'a and 'b be lifetimes with 'a shorter than 'b (which can be written 'b: 'a).
Suppose I have a p: &'b mut f32. I can borrow p briefly (with &mut p) to obtain q: &'a mut &'b mut f32.
Have I correctly understood that &'a mut &'b mut f32 is equivalent to &'a mut &'a mut f32 because 'b: 'a?
I can then dereference q (with *q) to obtain r: &'a mut f32. I can write to the f32 via r (with *r = something), and I can later (outside lifetime 'a) read back the value via p (with *p).
With a function call
Here is some working code that I think uses the above sequence:
fn reborrow<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
*q
}
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = reborrow(q);
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
(Replacing *q with q in the body of reborrow() also works, because Rust inserts the necessary dereference if it is missing).
Manually inlined
If I manually inline the reborrow() call, it no longer compiles:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = *q; <-- ERROR REPORTED HERE.
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
error[E0507]: cannot move out of borrowed content
Who took away my toys? What is the type inference thinking/missing?
Can I annotate the let binding somehow to make the compiler infer the same types as in the previous version?
Some other attempts
Here's another version that works, but which doesn't define the name r:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
**q = 2.718;
}
assert_eq!(*p, 2.718);
}
Here's a work-around that defines the name r and works, but does not use the same sequence of borrows and dereferences:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = &mut **q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
I made a playground combining all four versions.
The obvious solution works, as one could expect:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
It seems relatively intuitive and is what I would expect a newcomer to end up with.
If you start thinking about it, however, it will not make sense. As described, it looks like:
let r: &mut f32 = p; moves out of p
and yet we use p later in assert_eq!(*p, 2.718);
A reasonable explanation would be that p is Copy, however it's not1!
The answer is that, implicitly, Rust is performing a re-borrowing behind the scenes. That is, the explicit code is:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = &mut *p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
We can check this by attempting to read p after re-borrowing it, and check the compiler error:
error[E0502]: cannot borrow `p` as immutable because `*p` is also borrowed as mutable
--> <anon>:6:24
|
5 | let r: &mut f32 = p;
| - mutable borrow occurs here
6 | println!("{}", p);
| ^ immutable borrow occurs here
7 | *r = 2.718;
8 | }
| - mutable borrow ends here
error: aborting due to previous error
Which confirms that p is indeed only borrowed mutably, and not moved, cloned or copied.
1 A mutable reference cannot be Copy or even Clone as it would violate the Aliasing XOR Mutability principle which underpins Rust safety.
I can't possibly begin to explain this, but you can do a similar trick as the implicit dereference and say that r is &mut f32:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r: &mut f32 = q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}

Resources