Golden Rules for PROGRES Users
The rules and hints below where collected to advice PROGRES-users in specifying correct and efficient prototype specifications. They represent best practice collected at the Department of Computer Science III, Aachen University of Technology. But be warned, don't follow all the rules slavishly because there might be scenarios where ignoring some of these rules is necessary!
Avoid usage of nondeterministic statements (transformation calls, assignments, ... ) in loops. The PROGRES-internal choice-graph (for backtracking, undo and redo) gets too big. Move the body of your loop into a separate transformation which is deterministic [0:1]. PROGRES then handles "Don't care nondeterminism" inside this transformation more efficiently by using a kind of Prolog "Cut" with dramatic effects concerning the size of the generated choice graph.
Initialize every attribute attached to node types and node classes with its definition. If not initialized like this, you will get a lot of tombstones in a generated prototype and this prototype will not be stable. The corresponding error message reads like "no code for evaluation of attribute".
If you already get such error messages, it is quite easy to localize the corresponding attributes by looking at the generated code. For each missing attribute initialization there is a call to an error handler called "PGCError" generated into the code. As a result, it is possible to search for occurrences of these error handler calls in the generated c-files. The corresponding attribute can identified from a comment nearby.
Initialize all variables defined within a PROGRES specification with their definition. This makes the whole specification more stable with respect to generated prototypes. Unfortunately, this is not possible for node-valued variables. Sets should be initialized to the empty set (nil). If variables are not initialized properly, the generated prototype will (sometimes) use arbitrary values and may crash or behave strangely.
Be careful with attributes and variables used to transfer and store string values. If the strings are getting too long this will lead into trouble (e.g. "S2S FATAL ERROR: ..."). Keep strings as short as possible (less than 251 characters).
Use attribute conditions instead of restrictions whenever possible. If specified correctly, a more efficient algorithm (code) is generated for finding the right nodes (index attribute first, node last). If there are several conditions to check for a single node, do not connect them via logical AND. This would result in the same inefficient code (loop over all nodes of correct type) for the node selection. Always use a separate clause for every condition
- especially for those which have the form:
<node>.<IndexOrKeyAttribute> = <expression>; .
But, conditions are not allowed in combination with optional nodes or node sets. In these cases you have to use restrictions.
If you want to test wether a path expression returns an empty set or at least one node use
choose when (card ( <path expression> ) > 0) then ... end .
Take care that every choose-when-statement contains an else-path that executes successfully if your transaction has to be successful in any case to avoid backtracking. For example
choose ... else skip end
executes successfully in any case!
Use the keyword "index" in front of attributes which identify nodes. This forces GRAS (the underlying database) to create index tables for theses attributes. The result is faster access to nodes if you identify them via these attributes or their values, respectively.
It is best practise to use test/queries instead of def-statements if you want to be sure that a certain graph transformation is executable.
If you need to identify and get a set of nodes according to type and/or the value of an attribute attached to these nodes, best practise is to use a test/query for this purpose. But, take care that you use a set-of-nodes in the corresponding graphical notation. If you just use an "obl_node" then PROGRES will return just a single node (or none of course). Only "obl_set" makes sure that a set of nodes will be returned. This set can be empty again. So, check this if you don't want to fail in a calling transformation.
Remember, the *-operator doesn't make a test/query to return sets! It just says "Try as often as possible." !
Using the keyword "safe" in the definition of graph transformations gives a PROGRES-user the chance to automatically execute a kind of repair action in form of constraint definitions. But, if the execution of any constraint fails, the program execution will be terminated immediately. Therefore, it might be a good idea to include repair actions that might fail into a choose-statement with a else-skip-end path (but only if failling of the repair action doesn't matter to you). There are two different ways to define constraints: global constraints using the corresponding constraint-statement and local constraints via a derived attribute attached to a certain node class or node type.
Be sure that variables used as parameters in a call to a transformation have the right cardinality with respect to the transformation's definition. It does not necessarily produce an error or a warning within PROGRES if a parameter is set-valued and the variable piped in is not, or vice-versa. But, in combination with the UPGRADE framework this often leads into trouble. Therefore, use set-valued variables for set-valued parameters and use normal variables for normal parameters.
Note: Tombstones on the console (xterm etc.) telling something referring to "SetToElem" are a good hint that you have already violated this rule!
Created by: rangerlast modification: Friday 29 of October, 2004 [14:21:42 UTC] by