Unable to hold/pass reference of parent to the composition object - rust

In C++ it would something like struct A is composed of struct B and some function of B takes a pointer to the parent object A. So function of A calling that function of B will simply pass the this pointer to it. I'm trying this in Rust but failing to get it to work - this is what I want to achieve:
struct A<Type: T> {
composition: Type,
value: usize,
}
impl<Type> A<Type> where Type: T {
fn new(obj: Type) -> A<Type> {
A {
composition: obj,
value: 999,
}
}
fn f(&mut self) {
println!("Value: {:?}", self.value);
}
fn call(&mut self) {
self.composition.f(&mut self);
}
}
trait T {
fn f(&mut self, &mut A<Self>);
}
struct B {
value: usize,
}
impl B {
fn new() -> B {
B { value: 0, }
}
}
impl T for B {
fn f(&mut self, parent: &mut A<B>) {
println!("B::f");
parent.f();
}
}
fn main() {
let objA = A::new(B::new());
// I want call sequence -> A::call() -> B::f() -> A::f()
objA.call();
}
Note that i require mutability in all the functions although in example above it might seem that &mut self in most function parameters don't make much sense. How do it do this in Rust?

This cannot work because you're violating mutable aliasing requirements - you're trying to mutably borrow A and its substructure at the same time:
self.composition.f(self);
// roughtly equivalent to:
let c = &mut self.composition; // borrow substructure
c.f(self /* borrow self */);
(I've removed explicit &mut self because it is incorrect (as it gives you &mut &mut A<...>, but it does not change the whole picture at all.)
This is a natural error in Rust framework. Suppose that f implementation on this particular composition X rewrites composition field on the passed object:
impl T for X {
fn f(&mut self, a: &mut A<X>) {
a.composition = create_x_somehow();
}
}
And suddenly the object this method is called on is destroyed, and self is invalidated!
Naturally, the compiler prevents you from doing this even if you know that you don't modify composition, because such kind of knowledge cannot be encoded statically (especially given that this is a trait method which can be implemented by anyone having access to your trait).
You have essentially two choices in such situations:
reformulate the problem so it does not require such architecture anymore, or
use special language/library constructs to work around such static checks.
The second point is about using such things as Cell/RefCell (they are safe, i.e. don't require unsafe blocks, but they can panic at runtime - probably these can work in your case) or, if nothing else helps, dropping to raw pointers and unsafe code. But, frankly, the first option usually is better: if you design your code based on ownership semantics and aliasing rules enforced by the compiler, almost always the resulting architecture would be of much better quality.

Related

By-value methods on trait objects [duplicate]

I was writing some code and had a trait with a method that takes self by value. I want to call this method on a Box'd trait object (consuming the Box and its value). Is this possible? If so, how?
In terms of code, a minimal example looks like the following (incomplete) code:
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(ptr: Box<dyn Consumable>) -> u64 {
//what can I put here?
}
My question is how to fill in the function consume_box with the specified signature so that the value returned is whatever value would be gotten by calling consume on the Box'd value.
I had initially written
ptr.consume()
as the body of the function, though I realize this isn't quite the right idea, since it doesn't get across the fact that I want the Box to be consumed, not just its contents, but it's the only thing I could think of. This does not compile, giving an error:
cannot move a value of type dyn Consumable: the size of dyn Consumable cannot be statically determined
This was somewhat surprising to me, being new to Rust, I had thought that maybe the self argument was passed similarly to an rvalue reference in C++ (which is really what I want - in C++, I would probably implement this by a method with the signature virtual std::uint64_t consume() &&, letting a std::unique_ptr clean up the moved-from object via a virtual destructor), but I guess Rust is truly passing by value, moving the argument into place prior - so it's reasonable that it rejects the code.
Trouble is, I'm not sure how to get the behavior I want, where I can consume a Box'd trait object. I tried adding a method to the trait with a default implementation, thinking that might get me something useful in the vtable:
trait Consumable {
fn consume(self) -> u64;
fn consume_box(me: Box<Self>) -> u64 {
me.consume()
}
}
However, this then yields the error
the trait Consumable cannot be made into an object
when I mention the Box<dyn Consumable> type - which is not so surprising, since the compiler figuring out what to do with a function whose argument type varied with Self would have been miraculous.
Is it possible to implement the function consume_box with the provided signature - even modifying the trait if necessary?
If it's useful, more specifically, this is part of a sort of representation of some mathematical expressions - maybe a toy model would be that specific implementations that look roughly like:
impl Consumable for u64 {
fn consume(self) -> u64 {
self
}
}
struct Sum<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Sum<A, B> {
fn consume(self) -> u64 {
self.0.consume() + self.1.consume()
}
}
struct Product<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Product<A, B> {
fn consume(self) -> u64 {
self.0.consume() * self.1.consume()
}
}
fn parse(&str) -> Option<Box<dyn Consumable> > {
//do fancy stuff
}
where, for the most part, things are plain old data (but arbitrarily large blocks of it, potentially, due to the generics), but to also have this be compatible with passing around more opaque handles to these sorts of things - hence the desire to be able to work with Box<dyn Consumable>. At least at the language level, this is a good model of what sort of things I'm up to - the only resources owned by these objects are pieces of memory (nothing to do with multithreading and no self-referential shenanigans) - although this model doesn't capture that the use case I have is one where it's useful for the implementation to consume the object rather than to merely read it nor does it appropriately model that I want an "open" class of possible segments rather than a finite set of possiblities (making it hard to do something like an enum that represents a tree directly) - hence why I'm asking about passing by value rather than trying to rewrite it to pass by reference.
You can consume from a Box<dyn Trait> if the parameter is self: Box<Self>:
trait Consumable {
fn consume(self) -> u64;
fn consume_box(self: Box<Self>) -> u64;
}
struct Foo;
impl Consumable for Foo {
fn consume(self) -> u64 {
42
}
fn consume_box(self: Box<Self>) -> u64 {
self.consume()
}
}
fn main() {
let ptr: Box<dyn Consumable> = Box::new(Foo);
println!("result is {}", ptr.consume_box());
}
However, this does have the annoying boilerplate of having to implement consume_box() for each implementation; trying to define a default implementation will run into a "cannot move value of type Self - the size of Self cannot be statically determined" error.
In general though this is not supported. A dyn Consumable represents an unsized type which are very limited except through indirection (via references or Box-like structs). It works for the above case because Box is a bit special (is the only dispatchable type you can take ownership from) and the consume_box method does not put self on the stack as a dynamic trait object (only in each implementation where its concrete).
However there is RFC 1909: Unsized RValues which hopes to loosen some of these limits. One being able to pass unsized function parameters, like self in this case. The current implementation of this RFC accepts your initial code when compiled on nightly with unsized_fn_params:
#![feature(unsized_fn_params)]
trait Consumable {
fn consume(self) -> u64;
}
struct Foo;
impl Consumable for Foo {
fn consume(self) -> u64 {
42
}
}
fn main () {
let ptr: Box<dyn Consumable> = Box::new(Foo);
println!("result is {}", ptr.consume());
}
See on the playground.
I believe
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(val: impl Consumable) -> u64 {
val.consume()
}
might do what you want. I'm all but a Rust expert - or C++ expert for that matter -, but I think it should be working pretty much like the move-semantics in C++ you mentioned in terms of memory behavior. From what I understand it is a form of generic where Rust implements the Function for every type you call it with.
If you don't use nightly Rust, I wrote a macro here. It generates the second trait function automatically.
trait Consumable {
fn consume(self) -> u64;
fn consume_box(me: Box<Self>) -> u64 ;
}

How to pass a boxed trait object by value in Rust?

I was writing some code and had a trait with a method that takes self by value. I want to call this method on a Box'd trait object (consuming the Box and its value). Is this possible? If so, how?
In terms of code, a minimal example looks like the following (incomplete) code:
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(ptr: Box<dyn Consumable>) -> u64 {
//what can I put here?
}
My question is how to fill in the function consume_box with the specified signature so that the value returned is whatever value would be gotten by calling consume on the Box'd value.
I had initially written
ptr.consume()
as the body of the function, though I realize this isn't quite the right idea, since it doesn't get across the fact that I want the Box to be consumed, not just its contents, but it's the only thing I could think of. This does not compile, giving an error:
cannot move a value of type dyn Consumable: the size of dyn Consumable cannot be statically determined
This was somewhat surprising to me, being new to Rust, I had thought that maybe the self argument was passed similarly to an rvalue reference in C++ (which is really what I want - in C++, I would probably implement this by a method with the signature virtual std::uint64_t consume() &&, letting a std::unique_ptr clean up the moved-from object via a virtual destructor), but I guess Rust is truly passing by value, moving the argument into place prior - so it's reasonable that it rejects the code.
Trouble is, I'm not sure how to get the behavior I want, where I can consume a Box'd trait object. I tried adding a method to the trait with a default implementation, thinking that might get me something useful in the vtable:
trait Consumable {
fn consume(self) -> u64;
fn consume_box(me: Box<Self>) -> u64 {
me.consume()
}
}
However, this then yields the error
the trait Consumable cannot be made into an object
when I mention the Box<dyn Consumable> type - which is not so surprising, since the compiler figuring out what to do with a function whose argument type varied with Self would have been miraculous.
Is it possible to implement the function consume_box with the provided signature - even modifying the trait if necessary?
If it's useful, more specifically, this is part of a sort of representation of some mathematical expressions - maybe a toy model would be that specific implementations that look roughly like:
impl Consumable for u64 {
fn consume(self) -> u64 {
self
}
}
struct Sum<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Sum<A, B> {
fn consume(self) -> u64 {
self.0.consume() + self.1.consume()
}
}
struct Product<A, B>(A, B);
impl<A: Consumable, B: Consumable> Consumable for Product<A, B> {
fn consume(self) -> u64 {
self.0.consume() * self.1.consume()
}
}
fn parse(&str) -> Option<Box<dyn Consumable> > {
//do fancy stuff
}
where, for the most part, things are plain old data (but arbitrarily large blocks of it, potentially, due to the generics), but to also have this be compatible with passing around more opaque handles to these sorts of things - hence the desire to be able to work with Box<dyn Consumable>. At least at the language level, this is a good model of what sort of things I'm up to - the only resources owned by these objects are pieces of memory (nothing to do with multithreading and no self-referential shenanigans) - although this model doesn't capture that the use case I have is one where it's useful for the implementation to consume the object rather than to merely read it nor does it appropriately model that I want an "open" class of possible segments rather than a finite set of possiblities (making it hard to do something like an enum that represents a tree directly) - hence why I'm asking about passing by value rather than trying to rewrite it to pass by reference.
You can consume from a Box<dyn Trait> if the parameter is self: Box<Self>:
trait Consumable {
fn consume(self) -> u64;
fn consume_box(self: Box<Self>) -> u64;
}
struct Foo;
impl Consumable for Foo {
fn consume(self) -> u64 {
42
}
fn consume_box(self: Box<Self>) -> u64 {
self.consume()
}
}
fn main() {
let ptr: Box<dyn Consumable> = Box::new(Foo);
println!("result is {}", ptr.consume_box());
}
However, this does have the annoying boilerplate of having to implement consume_box() for each implementation; trying to define a default implementation will run into a "cannot move value of type Self - the size of Self cannot be statically determined" error.
In general though this is not supported. A dyn Consumable represents an unsized type which are very limited except through indirection (via references or Box-like structs). It works for the above case because Box is a bit special (is the only dispatchable type you can take ownership from) and the consume_box method does not put self on the stack as a dynamic trait object (only in each implementation where its concrete).
However there is RFC 1909: Unsized RValues which hopes to loosen some of these limits. One being able to pass unsized function parameters, like self in this case. The current implementation of this RFC accepts your initial code when compiled on nightly with unsized_fn_params:
#![feature(unsized_fn_params)]
trait Consumable {
fn consume(self) -> u64;
}
struct Foo;
impl Consumable for Foo {
fn consume(self) -> u64 {
42
}
}
fn main () {
let ptr: Box<dyn Consumable> = Box::new(Foo);
println!("result is {}", ptr.consume());
}
See on the playground.
I believe
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(val: impl Consumable) -> u64 {
val.consume()
}
might do what you want. I'm all but a Rust expert - or C++ expert for that matter -, but I think it should be working pretty much like the move-semantics in C++ you mentioned in terms of memory behavior. From what I understand it is a form of generic where Rust implements the Function for every type you call it with.
If you don't use nightly Rust, I wrote a macro here. It generates the second trait function automatically.
trait Consumable {
fn consume(self) -> u64;
fn consume_box(me: Box<Self>) -> u64 ;
}

call callback with reference to field

Consider such code:
trait OnUpdate {
fn on_update(&mut self, x: &i32);
}
struct Foo {
field: i32,
cbs: Vec<Box<OnUpdate>>,
}
impl Foo {
fn subscribe(&mut self, cb: Box<OnUpdate>) {
self.cbs.push(cb);
}
fn set_x(&mut self, v: i32) {
self.field = v;
//variant 1
//self.call_callbacks(|v| v.on_update(&self.field));
//variant 2
let f_ref = &self.field;
for item in &mut self.cbs {
item.on_update(f_ref);
}
}
fn call_callbacks<CB: FnMut(&mut Box<OnUpdate>)>(&mut self, mut cb: CB) {
for item in &mut self.cbs {
cb(item);
}
}
}
If I comment variant 2 and uncomment variant 1,
it doesn't compiles, because of I need &Foo and &mut Foo at the same time.
But I really need function in this place, because of I need the same
code to call callbacks in several places.
So do I need macros here to call callbacks, or may be another solution?
Side notes: in real code I use big structure instead of i32,
so I can not copy it. Also I have several methods in OnUpdate,
so I need FnMut in call_callbacks.
An important rule of Rust's borrow checker is, mutable access is exclusive access.
In variant 2, this rule is upheld because the reference to self.field and to mut self.cbs never really overlap. The for loop implicitly invokes into_iter on &mut Vec, which returns a std::slice::IterMut object that references the vector, but not the rest of Foo. In other words, the for loop does not really contain a mutable borrow of self.
In variant 1, there is a call_callbacks which does retain a mutable borrow of self, which means it cannot receive (directly on indirectly) another borrow of self. In other words, at the same time:
It accepts a mutable reference to self, which allows it to modify all its fields, including self.field.
It accepts a closure that also refers to self, because it uses the expression self.field.
Letting this compile would allow call_callbacks to mutate self.field without the closure being aware of it. In case of an integer it might not sound like a big deal, but for other data this would lead to bugs that Rust's borrow checker is explicitly designed to prevent. For example, Rust relies on these properties to prevent unsafe iteration over mutating containers or data races in multi-threaded programs.
In your case it is straightforward to avoid the above situation. set_x is in control both of the contents of the closure and of the mutation to self.field. It could be restated to pass a temporary variable to the closure, and then update self.field, like this:
impl Foo {
fn subscribe(&mut self, cb: Box<OnUpdate>) {
self.cbs.push(cb);
}
fn set_x(&mut self, v: i32) {
self.call_callbacks(|cb| cb.on_update(&v));
self.field = v;
}
fn call_callbacks<OP>(&mut self, mut operation: OP)
where OP: FnMut(&mut OnUpdate)
{
for cb in self.cbs.iter_mut() {
operation(&mut **cb);
}
}
}
Rust has no problem with this code, and effect is the same.
As an exercise, it is possible to write a version of call_callbacks that works like variant 2. In that case, it needs to accept an iterator into the cbs Vec, much like the for loop does, and it must not accept &self at all:
fn set_x(&mut self, v: i32) {
self.field = v;
let fref = &self.field;
Foo::call_callbacks(&mut self.cbs.iter_mut(),
|cb| cb.on_update(fref));
}
fn call_callbacks<OP>(it: &mut Iterator<Item=&mut Box<OnUpdate>>,
mut operation: OP)
where OP: FnMut(&mut OnUpdate)
{
for cb in it {
operation(&mut **cb);
}
}

Interior mutability vs data hiding to hold fixed the referant of a mutable borrow

If we run this then we correctly get the error "cannot assign to immutable field a.x".
If we remove the two // comments, and comment out this bad line, then we get the error "cannot assign to data in a & reference". This makes sense because &mut does not provide interior mutability. We can reborrow an &A freely, so this must not give mutable access, ala &&mut is &&.
If we remove both the // comments and the /* */ comments, then the whole thing compiles, permitting the bad line that violates our invariant that a.x must never be pointed to anything else.
pub struct A<'a> {
pub x: &'a mut [u8; 3],
}
fn main() {
let y = &mut [7u8; 3];
let /*mut*/ a = A { x: &mut [0u8; 3] };
a.x[0] = 3;
a.x = y; //// This must be prevented!
{
// let b = &/*mut*/ a;
// b.x[1] = 2;
}
println!("{:?}", a.x);
}
How should one maintain this invariant that x must not be changed? We could make the field private while providing public dereferencing methods, except writing constructors for A in unacceptable.
We can avoid the obnoxious constructor by making a A a private member of a wrapper struct AA(A) which itself hosts the public dereferencing methods. Now AA needs a trivial constructor, but it does not need arguments for all fields of A, does not impact order of execution, etc. This becomes painful if we need some traits implemented for both A and AA though.
Yet, another approach would be to use interior mutability by working with Cell<A>, accessing it with Cell::replace, and putting it back later. This sounds highly problematic, but shows that more solutions exist.
Any cleaner approaches?
Rather than use a Cell<A> you could make the array inside the A contain Cell<u8>s:
use std::cell::Cell;
pub struct A<'a> {
x: &'a [Cell<u8>; 3],
}
fn main() {
// let y = &mut [7u8; 3];
let a = A { x: &[Cell::new(0u8), Cell::new(0u8), Cell::new(0u8)] };
a.x[0].set(3);
// a.x = y;
{
let b = &a;
b.x[1].set(2);
}
println!("{:?}", a.x);
}
This will still behave how you want, with the same performance, but now the a variable is immutable, so you can't change a.x. You also don't need to make the array reference mutable either.
The slight downside with your example is that you can't use the array repetition syntax, since Cell<T> does not implement Copy. This seems like an omission, but there is some explanation as to why that is here.
Another approach is to define
pub struct A<'a> { pub x: HideMut<'a,[u8; 3]> }
where
use std::ops::{Deref,DerefMut};
struct HideMut<'a,T>(&'a mut T) where T: ?Sized + 'a;
impl<'a,T> HideMut<'a,T> where T: ?Sized {
pub fn new(m: &'a mut T) -> HideMut<'a,T> { HideMut(m) }
}
impl<'a,T> Deref for HideMut<'a,T> where T: ?Sized {
type Target = T;
fn deref(&self) -> &T { self.0 }
}
impl<'a,T> DerefMut for HideMut<'a,T> where T: ?Sized {
fn deref_mut(&mut self) -> &mut T { self.0 }
}
As written, this does not prevent the problem per se, but it requires you call the HideMut::new() constructor to violate it.
Now if we define HideMut in the same module as A, and maybe do not even export it, then we actually do achieve the desired hiding without any interior mutability.
This second form fails my original requirements because now you cannot use the constructor A { }, but depending upon your reasons for not wanting to write a constructor for A it may work out.
In either form, this avoids borrowing the whole of A as a method would do.

Generic function for modifying scalars and slices in place

I don't understand some basics in Rust. I want to compute a function sinc(x), with x being a scalar or a slice, which modifies the values in place. I can implement methods for both types, calling them with x.sinc(), but I find it more convenient (and easier to read in long formulas) to make a function, e.g. sinc(&mut x). So how do you do that properly?
pub trait ToSinc<T> {
fn sinc(self: &mut Self) -> &mut Self;
}
pub fn sinc<T: ToSinc<T>>(y: &mut T) -> &mut T {
y.sinc()
}
impl ToSinc<f64> for f64 {
fn sinc(self: &mut Self) -> &mut Self {
*self = // omitted
self
}
}
impl<'a> ToSinc<&'a mut [f64]> for &'a mut [f64] {
fn sinc(self: &mut Self) -> &mut Self {
for yi in (**self).iter_mut() { ... }
self
}
}
This seems to work, but isn't the "double indirection" in the last impl costly? I also thought about doing
pub trait ToSinc<T> {
fn sinc(self: Self) -> Self;
}
pub fn sinc<T: ToSinc<T>>(y: T) -> T {
y.sinc()
}
impl<'a> ToSinc<&'a mut f64> for &'a mut f64 {
fn sinc(self) -> Self {
*self = ...
self
}
}
impl<'a> ToSinc<&'a mut [f64]> for &'a mut [f64] {
fn sinc(self) -> Self {
for yi in (*self).iter_mut() { ... }
self
}
}
This also works, the difference is that if x is a &mut [f64] slice, I can call sinc(x) instead of sinc(&mut x). So I have the impression there is less indirection going on in the second one, and I think that's good. Am I on the wrong track here?
I find it highly unlikely that any differences from the double-indirection won't be inlined away in this case, but you're right that the second is to be preferred.
You have ToSinc<T>, but don't use T. Drop the template parameter.
That said, ToSinc should almost certainly be by-value for f64s:
impl ToSinc for f64 {
fn sinc(self) -> Self {
...
}
}
You might also want ToSinc for &mut [T] where T: ToSinc.
You might well say, "ah - one of these is by value, and the other by mutable reference; isn't that inconsistent?"
The answer depends on what you're actually intend the trait to be used as.
An interface for sinc-able types
If your interface represents those types that you can run sinc over, as traits of this kind are intended to be used, the goal would be to write functions
fn do_stuff<T: ToSinc>(value: T) { ... }
Now note that the interface is by-value. ToSinc takes self and returns Self: that is a value-to-value function. In fact, even when T is instantiated to some mutable reference, like &mut [f64], the function is unable to observe any mutation to the underlying memory.
In essence, these functions treat the underlying memory as an allocation source, and to value transformations on the data held in these allocations, much like a Box → Box operation is a by-value transformation of heap memory. Only the caller is able to observe mutations to the memory, but even then implementations which treat their input as a value type will return a pointer that prevents needing to access the data in this memory. The caller can just treat the source data as opaque in the same way that an allocator is.
Operations which depend on mutability, like writing to buffers, should probably not be using such an interface. Sometimes to support these cases it makes sense to build a mutating basis and a convenient by-value accessor. ToString is an interesting example of this, as it's just a wrapper over Display.
pub trait ToSinc: Sized {
fn sinc_in_place(&mut self);
fn sinc(mut self) -> Self {
self.sinc_in_place();
self
}
}
where impls mostly just implement sinc_in_place and users tend to prefer sinc.
As fakery for ad-hoc overloading
In this case, one doesn't care if the trait is actually usable generically, or even that it's consistent. sinc("foo") might do a sing and dance, for all we care.
As such, although the trait is needed it should be defined as weakly as possible:
pub trait Sincable {
type Out;
fn sinc(self) -> Self::Out;
}
Then your function is far more generic:
pub fn sinc<T: Sincable>(val: T) -> T::Out {
val.sinc()
}
To implement a by-value function you do
impl Sincable for f64 {
type Out = f64;
fn sinc(self) -> f64 {
0.4324
}
}
and a by-mut-reference one is just
impl<'a, T> Sincable for &'a mut [T]
where T: Sincable<Out=T> + Copy
{
type Out = ();
fn sinc(self) {
for i in self {
*i = sinc(*i);
}
}
}
since () is the default empty type. This acts just like an ad-hoc overloading would.
Playpen example of emulated ad-hoc overloading.

Resources