why do we need to create a proxy when we add a new node?
Closed this issue · 2 comments
I can't figure out why should we create "a correct iterator" seems useless? Just want to add a corresponding node in forest?
But why should we need adobe forest if we already have connectable port and connect_graph?
// flexcore/extended/base_node.hpp
template <class node_t, class... Args>
node_t& make_child_impl(node_args nargs, Args&&... args)
{
//first create a proxy node to get the node_args with a correct iterator
node_args n = new_node(std::move(nargs));
//then replace proxy with proper node
*n.self = std::make_unique<node_t>(std::forward<Args>(args)..., n);
return dynamic_cast<node_t&>(**n.self);
}
I can't delete this issue....
Now I know the reason, the proxy is just a container, then we create a real object to replace the thing in it.
// create a container with a fake object
const auto proxy_iter = add_child(std::make_unique<tree_base_node>(args));
args.self = proxy_iter;
// put the real object in
*n.self = std::make_unique<node_t>(std::forward<Args>(args)..., n);
So here's why this was implemented this way: we wanted nodes to be able to encapsulate multiple nodes inside a parent node and we wanted nodes to not live just anywhere, but only in the tree. The goal was to have introspection capability (e.g. iterate over all nodes in the program). Take the following example code (don't remember the specific syntax so the example may be wrong):
class Node : public tree_base_node {
};
class ParentNode : public owning_base_node {
public:
ParentNode(const node_args& args) :
owning_base_node(args),
n1(make_child<Node>()),
n2(make_child<Node>()),
{
}
private:
Node& n1;
Node& n2;
};
This was the desired client code. So we needed to be able to call make_child before the ParentNode constructor is done, and the child nodes may have nested nodes as well. That's why first a proxy node is created, that we can then use to create child nodes inside the ParentNode constructor. If we would directly create the ParentNode inside the forest then there wouldn't be a way to pass the needed forest iterator to the ParentNode constructor to create child nodes (it's an ordering issue: the iterator can't exist before the object exists).
This may not be something you need, but at the time it seemed necessary, and felt like the right design decision.