-
Notifications
You must be signed in to change notification settings - Fork 1
Conversation
Interesting stuff. [I'm going to try the |
Thats pretty much it. |
Overhead relative to...? |
It seems that |
OK... although what's the problem with RefCell mutation? [Let's pretend performance isn't an issue, at least at this point.] |
Now that I have thought about this in more detail, I have reached the conclusion that there are some wrinkles to address, but I think it can be done. (BTW, I have sort of used this reply as a scratch space to flesh out and develop my ideas, so pardon the text wall) The One issue is the fact that the All this of course has the |
The crux of the matter, I think, is that each Node x would be able to return me an Rc pointing to x? |
Exactly. My next step is to try to implement this and see how things turn out. |
Can I suggest we make the Separately, what's the advantage of |
Make it a method? I don't quite understand.... |
OK -- makes sense. What I mean is that instead of saying |
I already do this mostly; my existing solution is approximately:
|
I see. Makes sense. |
Borrow type aliases renamed.
…at would be more representative of a practical implementation.
Sadly, this is turning out to be trickier than first expected. Constructing a tree based on the above is fine. When a node is constructed, it is immediately wrapped in a Problems arise when we want to mutate the tree structure after its constructed. Lets say we have a branch node, e.g. This leads us to moving all tree structure mutation methods out of the node type - e.g. We then hit another snag; not all nodes have children and those that do may not structure their children in the same way. Leaf nodes - e.g. text nodes for displaying tokens - don't have any children. A column node would need a list of children in a A solution to this problem is to break our node reference types into a type hierarchy in much the same way we do with nodes. In fact, the node reference type hierarchy would mirror that of the node type hierarchy to some extent. We leave the non-tree-structure methods in the node types and have the tree-structure methods in the node reference types. As a consequence, Having a node reference type hierarchy indicates that we must now have a base node reference trait; Unfortunately, this means quite a lot of wrappers. Each node reference is referred to by
Now this is all fine and good. The extra |
I must admit, I no longer know why we split up |
Can we not try this stuff in the context of our simpler tree repo example? I wonder if we are again going into a little too much depth a little too soon. |
OK, I've been thinking about this a bit more, and I'm wondering if we can simplify things to something like: type WrappedNode = Rc<RefCell<Box<Node>>>;
trait Node {
fn get_wrapped(&self) -> WrappedNode;
fn set_parent(&mut self, parent: Node);
}
struct ColumnNode {
self_wrapped : Option<WrappedNode>,
parent: Option<WrappedNode>
}
impl ColumnNode {
fn new(parent: Rc<RefCell<Box<Node>>>) {
let mut s = ColumnNode { self_wrapped: None, parent: parent };
s.self_wrapped = Rc::new(RefCell::new(s));
s
}
}
impl Node for ColumnNode {
fn set_parent(&mut self, parent: Option<WrappedNode>) {
self.parent = parent;
}
} What I'm imagining is each Node being able to give a Wrapped version of itself. The bit I'm a little unsure about is whether the approach I've taken on If we can do something like this, then I can always guarantee to get a reference to the right |
My new solution:
Given that the new ref type is pub fn muzzle<'a, T: ?Sized>(x: &'a T) -> &'a mut T {
return unsafe{transmute(x)};
} Basically, it transmutes an immutable ref into a mutable one. It is to be used sparingly, and never with types that cross a thread boundary. Asides that however, it addresses the problem quite nicely. The |
Is that a static method? Doesn't it also mean that I can now get multiple mutable aliases to a given run-time object? |
Its just a function. You could use it to do such things, yes. |
OK, then we need to think very carefully about this, because it allows us to break many of Rust's rules unknowingly. |
Let's set up some tests where we deliberately alias pointers and see what happens. I think I will need some convincing that we're not going to blow our feet off at some random point. |
I think this PR can be closed? |
Oops, didn't mean to close it quite yet. Geoff, what are your thoughts? |
Yes, we can close it. This was resolved late December when the tree structure stuff was figured out. |
Implemented a benchmark for measuring the performance of various types of element reference. The benchmark can be run with
cargo bench
, although you need to comment and uncomment various blocks of code to try the different reference types. A generics based approach was attempted, but a variety of implementations of it were all failed by the borrow/lifetime checker.To save time, here are the results:
Box<TElement>
: ~49,940,000 ns (Base case; boxed trait)Box<Box<TElement>>
: ~53,300,000 ns (1 additional pointer indirection)RefCell<Box<TElement>>
: ~62,260,000 ns (interior mutability)Rc<Box<TElement>>
: ~62,100,000 ns (multiple ownership, mutate viaRc::get_mut
)Rc<RefCell<Box<TElement>>>
: ~76,880,000 ns (everything)These results are approximately reflected in the War and Peace demo, where layout with the
Box<TElement>
reference type takes ~133ms, and ~200ms with theRc<RefCell<Box<TElement>>>
reference type; approximately an increase of 50%.