4.3. Setting properties

Now you have learned how to initialize properties of a new node, and how to read out properties of existing nodes. The latter is done using a syntax with square brackets. This syntax can also be used to set new values for properties. But at first, consider the following example:

Sphere(r) ==> Sphere(r/2);

Obviously, the aim is to divide the radius of each sphere by two. The rule implements this behaviour by replacing each sphere of radius r by a new sphere of radius r/2, using the constructor invocation new Sphere(r/2). Although the rule does its job correctly, there is a better solution: What if we keep the existing original sphere in the graph and just divide its radius by two? This is more efficient, because the existing sphere can be re-used and less changes to the graph have to be done. And there is another advantage: If the original sphere has some other properties which differ from their default values (e.g., a shader has been set), these properties get lost by application of the replacement rule because the rule just uses the radius property of the original sphere. However, if we just modify the radius of the existing sphere, all other properties remain unchanged, so nothing is lost. Here is how the better solution looks like:

x:Sphere ::> x[radius] /= 2;

The most apparent difference to the previous rule is the new arrow symbol ::>: It indicates a new type of rule, namely an execution rule. Execution rules treat their right hand sides as statements which are to be executed for every match of their left hand side. Think of this as a for loop which iterates over all matches and has the right hand side as body:

for (all matches of x:Sphere in graph)
    x[radius] /= 2;

Now the statement x[radius] /= 2; divides x's radius property by two as desired. The execution rule is contained in the method grow of this example. Click here to see a sphere shrinking and a cylinder growing.

You may wonder if it is also possible to write x.setRadius(x[radius]/2); instead of x[radius] /= 2;. In principle, this works. But in this case, GroIMP is not informed about the modification of the radius and, thus, does not redraw the 3D visualization. As a rule of thumb, the modification of properties of nodes which are already part of GroIMP's graph should be done using property assignments as in x[radius] /= 2;. For newly created nodes which are not yet part of GroIMP's graph, it is OK to use setter methods for the purpose of initialization as in Sphere(1).(setShader(RED)).