This is an old revision of the document!
Table of Contents
Mistake: Storing Nodes outside of the graph
When developing a complex model in GroIMP, it happens that you want to “store” nodes in an “easy” to access data structure (list, array, map, …), or as fields of other objects (create a module with its parent as field). Such kind of development practice are strongly discouraged, as they are both inefficient and prone to unexpected errors in the project. This tutorial will cover what type of issues this behavior can create, and propose different approaches to properly get to the same goal.
Examples of error
Storing Nodes in arrays
For this example we consider a very simple project of one rgg class with the content:
Node[] mynode = new Node[1]; module A; protected void init () [ Axiom ==> A; ] public void storeNode () [ a:A ::> mynode[0] = a; ] public void queryA() { reset(); derive(); println( (*A*)); }
When the project is initialized (either after compilation, or through manual reset) the main graph contains three nodes: the root, an rggroot, one A. (visible in the picture bellow.
As you can see, the Node A has an id of 193. Let's store that node into the array mynode
by running the method sotreNode
.
Then, let's reset the project through the reset command, which will remove the RGGRoot node from the graph, as well as all its children nodes (in this case the nodes with id 191 ,and 193) will be removed. After a reset, the project automatically add a NEW RGGRoot in the graph and run the init()
method. The init()
method here add an NEW A in the main graph.
Thus, after reset the main graph looks like:
As you can see, the graph is very similar. It contains the same type of nodes: the root, an rggroot, one A. However, the RGGRoot and A have the ids: 194 and 196 respectively. They are different Nodes compared to the previous ones.
Now let's query all Node A
in the graph and print them with println( (*A*) );
. The output result is:
The main graph only contains ONE Node A (with the id 196) as displayed in the 2nd picture. Yet, the query return two A. The current one, and the one stored in the array mynode
.
issue: The queried Nodes and the Nodes contained in the main graph do not match anymore.
Note: The “old” Node A do not need to be added to the main graph first for this issue to appear. If an array is created with an Node in, e.g.
Node[] mynode = new Node[]{new A()};
The Node A would still appear in the queries despite not being part of the main graph
Storing Nodes in fields
Another common example is to store existing Nodes in newly created Nodes at fields. For instance, let's consider a project with the following code:
module B(A parentNode); module A; protected void init () [ Axiom ==> A; ] public void growth()[ a:A ==> B(a); ] public void queryA() { growth(); derive(); println( (*A*)); }
In this example, the module B has an attribute parentNode
of the type A
. Thus, B has a field of type A (in which the parameter parentNode
will be stored).
Similarly to the previous example, the initial state of the main graph contains 3 nodes:
On applying the method growth()
, the Node A is replaced by a newly created B, and the Node B use the old A as parentNode
. Thus, the Node A is replaced by a B which has a field that contains the A.
The main graph now looks like:
The node A of id 276 has been replaced by a B with id 277. The node A is not present in the main graph anymore.
Yet, let's query the Node A and print them with println( (*A*));
:
The Node A of id 276 (the parentNode
of the Node B) is still query-able.
issue: The queried Nodes and the Nodes contained in the main graph do not match anymore.
Cause of the "issue"
The graph queries include Node in the whole project graph. The main graph is only one of the sub-graphs of the project graph. Nodes can exists in the project graph without being part of the main graph. Additionally, when a Node is removed from the main graph, it is not “deleted”. It is simply disconnected from the graph. The garbage collector is the one that actually “delete” the Nodes that are not connected to ANY graph anymore. If Nodes disconnected from the main graph still have a connection to the project graph, they are not completely “disconnected” from the graph. Thus, they are not deleted.
Avoid the issue
Use the Node id
The graph in GroIMP works basically like a HashMap of id and Nodes. It also includes many other features to access the Nodes, but the base data structure is a HashMap. The Node are added and retrieved using the hash of their id. Thus, instead of storing the Nodes themselves, their id should be stored.
For example, the project:
<code java > long[] mynodeid = new long[1];
module B(long parentNode); module A;
protected void init () [
Axiom ==> A;
]
public void dostuff()[ a:A =⇒ B(a.getId())
{mynodeid[0]=a.getId();} ;
]
public void queryA() {
dostuff(); derive(); println( (*A*));
}
public void getTheNode(){
// Get the node from an array graph().getNodeForId((mynodeid[0]));
// Get the parentNode of B [b:B ::> graph().getNodeForId( b.parentNode); ]
}
</code
Instead of