Discussion:
[rust-dev] Implementing a clone trait on &mut struct.
Paul Nathan
2014-08-04 02:02:09 UTC
Permalink
Hi,

I've gotten myself in a bit of a bind.

As part of my work with shared memory with workers, I've implemented a
(relatively leaky at the moment) abstraction over Arc<RWLock<T>>, called
Pool.

Part of my abstraction requires the Clone trait be implemented for T.

However, up in the user layer, I have something that looks roughly like this

struct Agent { ... }

struct Tracker {
Pool<&'r mut Agent>
}

At which point, the type checker complains and asks me to implement
something of this signature:

impl<'r> Clone for &'r mut Agent {

Which seems quite patently ridiculous - as if I understand things
something, I'm being asked to return a reference to something on the
*stack* of the fn clone() function. Something smells fishy here...

Some assistance and clarification would be appreciated.

Regards,
Paul
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140803/71fa8084/attachment.html>
Vladimir Matveev
2014-08-04 06:31:25 UTC
Permalink
Forgot to send a copy to mailing list.
Hi, Paul,
The problem with Clone implementation for mutable reference is not
that it does not make sense at all; after all, it is just an integer
value behind the fancy name, and, for example, plain & references [are
cloneable](http://doc.rust-lang.org/std/clone/trait.Clone.html).
However, Clone can't be implemented for mutable references because
&mut is unaliasable - there can't be more than one mutable reference
pointing to the same thing at the same time, but Clone does exactly
this.
Moreover, you say that `Pool<T>` is an abstraction over
`Arc<RWLock<T>>`, right? This means that `T` should also be Share +
Send, and while references are Share, they are not Send - you can't
send a reference to another task because it can point to original
task's stack, and if that original task exits, the reference may
become invalid. So it is likely that your overall design is incorrect.
It's hard to say more without more details on what you want to do.
Post by Paul Nathan
Hi,
I've gotten myself in a bit of a bind.
As part of my work with shared memory with workers, I've implemented a
(relatively leaky at the moment) abstraction over Arc<RWLock<T>>, called
Pool.
Part of my abstraction requires the Clone trait be implemented for T.
However, up in the user layer, I have something that looks roughly like this
struct Agent { ... }
struct Tracker {
Pool<&'r mut Agent>
}
At which point, the type checker complains and asks me to implement
impl<'r> Clone for &'r mut Agent {
Which seems quite patently ridiculous - as if I understand things something,
I'm being asked to return a reference to something on the *stack* of the fn
clone() function. Something smells fishy here...
Some assistance and clarification would be appreciated.
Regards,
Paul
_______________________________________________
Rust-dev mailing list
Rust-dev at mozilla.org
https://mail.mozilla.org/listinfo/rust-dev
Paul Nathan
2014-08-04 06:59:45 UTC
Permalink
Vladimir,

Without going into too much detail (as it it is tedious and not terribly
useful), what I am doing is building an instance of the classic
master/worker distributed system design[1] where the master sets up some
memory, shares it out to the workers, which then start working on it while
the master reads the progress of the workers. After a period of time, the
workers finish and the master takes over writing the work out to whatever
long-term storage it uses.

Two collections are at play here: the job list collection, and the worker
collection. A given job gets instantiated into a specific activation record
as it gets worked on. Both the job list and the worker need a path in
memory to the (same) activation record as they roll along. Only one Rust
task gets to write to the data at a time, by definition of the problem set
up.

So you see, mutable pointers out to the data blocks are key here.

several key points are to be made here:

1. message passing is *not* desirable - there's no need to have copies of
this (presumably large) data floating around. Indeed, sharing the state
between tasks is the key aspect in this exercise.
1a. Setting up to use channels in an actorish system here is an exercise in
yarn untangling. It devolved into building a closure which had two
half-duplex channels, implementing a mini-server in-code to communicate
with other objects. It could probably be cleaned up considerably with some
care and feeding of a macro... but nonetheless, it was ugly and carried a
high cognitive budget to consider.

2. Atomic barriers need to gate the shared data, as it will be both read
and written periodically.

3. Where the memory lives is largely immaterial. The main task can be
assumed to allocate adequate memory - either in the heap or in its own
stack - and this is passed around.


Regards,
Paul

[1] It's actually a continuous integration server with a master and
workers, as my patience with Jenkins oddities has fairly well run out.



On Sun, Aug 3, 2014 at 11:30 PM, Vladimir Matveev <dpx.infinity at gmail.com>
Hi, Paul,
The problem with Clone implementation for mutable reference is not
that it does not make sense at all; after all, it is just an integer
value behind the fancy name, and, for example, plain & references [are
cloneable](http://doc.rust-lang.org/std/clone/trait.Clone.html).
However, Clone can't be implemented for mutable references because
&mut is unaliasable - there can't be more than one mutable reference
pointing to the same thing at the same time, but Clone does exactly
this.
Moreover, you say that `Pool<T>` is an abstraction over
`Arc<RWLock<T>>`, right? This means that `T` should also be Share +
Send, and while references are Share, they are not Send - you can't
send a reference to another task because it can point to original
task's stack, and if that original task exits, the reference may
become invalid. So it is likely that your overall design is incorrect.
It's hard to say more without more details on what you want to do.
Post by Paul Nathan
Hi,
I've gotten myself in a bit of a bind.
As part of my work with shared memory with workers, I've implemented a
(relatively leaky at the moment) abstraction over Arc<RWLock<T>>, called
Pool.
Part of my abstraction requires the Clone trait be implemented for T.
However, up in the user layer, I have something that looks roughly like
this
Post by Paul Nathan
struct Agent { ... }
struct Tracker {
Pool<&'r mut Agent>
}
At which point, the type checker complains and asks me to implement
impl<'r> Clone for &'r mut Agent {
Which seems quite patently ridiculous - as if I understand things
something,
Post by Paul Nathan
I'm being asked to return a reference to something on the *stack* of the
fn
Post by Paul Nathan
clone() function. Something smells fishy here...
Some assistance and clarification would be appreciated.
Regards,
Paul
_______________________________________________
Rust-dev mailing list
Rust-dev at mozilla.org
https://mail.mozilla.org/listinfo/rust-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140803/a89eb24f/attachment.html>
Loading...