Selfreference with Arrays of Functional Classes in Gupta

Recently I showed how to implement a Functional Class in Gupta that contains „itself“ as an Instance Variable. You just have to initialize it with OBJ_Null.

SomeClass: class1 = OBJ_Null

Martin asked me then if it is possible to have an array of Functional Classes of the same type as an Instance Variable. This kind datastructure is very useful e.g. if you want to represent a tree structure like a filesystem.

SomeClass: aClasses[*]

Unfortunately TeamDeveloper redeems that with an error while compiling: „Error: Circularly defined class.“ Martin found an artful approach to outsmart TD: First write SomeClass c = OBJ_Null afterwards replace = OBJ_Null through [*]. But that doesn’t work on my machine. It crashes when I access an element of the array.
Another solution to that problem is to define an additional listclass:
Based on a datatype (Functional Class) called „Node“ an additional class „ListNodes“ is created. This one contains an array of „Node“ as an Instance Variable and an internal counter:

Functional Class: ListNodes
 Instance Variables
  Node: __nodes[*]
  Number: __nCountNodes

This listclass can be used in class „Node“ as an Instance Variable when initialized with OBJ_Null:

Functional Class: Node
 Instance Variables
  ListNodes: __listChildNodes = OBJ_Null

If one adds some access functions to class „Node“ it becomes really useful:

 

Function: AddChildNode
 Returns
 Parameters
  Node: node
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   Set __listChildNodes = new ListNodes
  Set __listChildNodes.aNodes[__listChildNodes.nCountNodes] = node
  Set __listChildNodes.nCountNodes = __listChildNodes.nCountNodes + 1
Function: CountChildNodes
 Returns
 Parameters
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   Return 0
  Else
   Return __listChildNodes.nCountNodes
Function: GetChildNode
 Returns
  Node:
 Parameters
  Number: nIdx
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   Return OBJ_Null
  Else
   If ( (nIdx >= 0) AND (nIdx < __listChildNodes.nCountNodes) )
    Return __listChildNodes.aNodes[nIdx]
   Else
    Return OBJ_Null
Function: RemoveChildNode
 Returns
 Parameters
  Number: nIdx
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   ! do nothing
  Else
   If ( (nIdx >= 0) AND (nIdx < __listChildNodes.nCountNodes) )
    While ( nIdx < __listChildNodes.nCountNodes - 1)
     Set __listChildNodes.aNodes[nIdx] = __listChildNodes.aNodes[nIdx +1 ]
     Set nIdx = nIdx + 1
    Set __listChildNodes.aNodes[__listChildNodes.nCountNodes] = OBJ_Null
    Set __listChildNodes.nCountNodes = __listChildNodes.nCountNodes - 1
In the attachment is an example that reads the whole directory-structure of drive C: (it may run some time to gather all information).
DirectoryTree.zip
Happy Coding

Selbstreferenz mit Arrays aus Functional Classes in Gupta

Neulich hatte ich gezeigt, wie in Gupta eine Functional Class „sich selbst“ als Instance Variable enthalten kann. Man muss sie lediglich mit OBJ_Null initialisieren.
SomeClass: class1 = OBJ_Null
Martin fragte mich daraufhin, ob es auch möglich sei, ein Array der Functional Class als Instance Variable zu verwenden. Diese Datenstruktur ist äußerst nützlich, wenn man z.B. eine Baumstruktur abbilden möchte, wie sie in Dateisystemen vorkommt.
SomeClass: aClasses[*]
Leider quittiert der TeamDeveloper das mit einer Fehlermeldung beim Kompilieren. „Error: Circularly defined class.“ Martin hat daraufhin eine listige Lösung gefunden, den TD auszutricksen. Allerdings produziert dieser in meiner Entwicklungsumgebung Abstürze, wenn ich auf ein Arrayelement zugegriffen habe.
Eine andere Lösung für das Problem ist, eine weitere Listenklasse zu definieren:
Ausgehend von einem Datentyp (Functional Class) namens „Node“ wird eine weitere Klasse „ListNodes“ erstellt, die als Instance Variablen ein Array aus Nodes sowie einen internen Zähler enthält:
Functional Class: ListNodes
 Instance Variables
  Node: __nodes[*]
  Number: __nCountNodes
Diese Listenklasse kann nun in der Klasse „Node“ als Instance Variable verwendet werden, wenn sie mit OBJ_Null initialisiert wird:
Functional Class: Node
 Instance Variables
  ListNodes: __listChildNodes = OBJ_Null
Fügt man noch ein paar Zugriffsfunktionen hinzu, kann man damit richtig gut arbeiten:
Function: AddChildNode
 Returns
 Parameters
  Node: node
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   Set __listChildNodes = new ListNodes
  Set __listChildNodes.aNodes[__listChildNodes.nCountNodes] = node
  Set __listChildNodes.nCountNodes = __listChildNodes.nCountNodes + 1
Function: CountChildNodes
 Returns
 Parameters
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   Return 0
  Else
   Return __listChildNodes.nCountNodes
Function: GetChildNode
 Returns
  Node:
 Parameters
  Number: nIdx
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   Return OBJ_Null
  Else
   If ( (nIdx >= 0) AND (nIdx < __listChildNodes.nCountNodes) )
    Return __listChildNodes.aNodes[nIdx]
   Else
    Return OBJ_Null
Function: RemoveChildNode
 Returns
 Parameters
  Number: nIdx
 Local variables
 Actions
  If ( __listChildNodes = OBJ_Null )
   ! do nothing
  Else
   If ( (nIdx >= 0) AND (nIdx < __listChildNodes.nCountNodes) )
    While ( nIdx < __listChildNodes.nCountNodes - 1)
     Set __listChildNodes.aNodes[nIdx] = __listChildNodes.aNodes[nIdx +1 ]
     Set nIdx = nIdx + 1
    Set __listChildNodes.aNodes[__listChildNodes.nCountNodes] = OBJ_Null
    Set __listChildNodes.nCountNodes = __listChildNodes.nCountNodes - 1
Im Anhang ist ein Beispiel, das die Directory-Struktur des Laufwerks C: ausliest (es kann allerdings eine Weile dauern, bis alle Informationen ausgelesen sind).
Happy Coding