(Original creator: Gerton)
Hi bloggers, For the ones that do not know me, I'm Gerton Leijdekker, Usability Consultant and Lead Developer for the Uniface product line in the Uniface Lab in Amsterdam. My intention is to blog about technical subjects, so this first blog will be about the Struct. With Uniface we always try to keep things simple with the intention to keep it a productive tool; don't bother with complex stuff, simply plug in the features you need, some ProcScript to glue them together, and done. But simplicity also has a downside, because now and then you just need more… Some features take the enablement approach, where the functionality can be used to solve a wide range of problems. But where simplicity adds limitations, flexibility adds complexity and complex things are most of the time harder to understand. The Struct is one of them: powerful, flexible, useful … but complex. The Struct is introduced in Uniface 9.5 and can solve a variation of challenges, like data transformations, data communication, and data processing. The Struct has no format limitations and therefore can handle any data format, whether it is Entities, XML, JSON, or your own custom format. But in all cases it helps if you fully understand what a Struct is and how it works. Currently, I'm working on the new Uniface 10 IDE and we use the Struct for almost everything. It replaces entity, occurrence, list, and xmlstream parameters and is heavily used for data cashing purposes. But although I was involved during the original design of the Struct, now that I need to use it, I still find it a challenging thing to use and it took me some time to fully grasp its concepts. In this first blog, I will focus on its core technical concepts being the Struct itself, the Struct Node, the Struct Variable, and the Struct Node Reference. To me it was very helpful once I fully understood those. The info in this blog is also being used to update the Uniface Library, but remember, you read it here first. :)
The Struct is a collection of objects, called Struct Nodes. These Struct Nodes are hierarchically organized, hence the term 'struct'. Every Struct Node can have i/o refers to 0, 1, or more child Struct Nodes. The Struct always has only one root Struct Node. The image shows two Structs as the reside somewhere in Uniface memory:
The Struct Variable
You can declare a struct variable the way you like any other variables, but unlike to variables of type String, Numeric, or Boolean, the Struct Variable does NOT contain the data itself; the Struct Variable only refers to the struct data that (as said) resides somewhere in Uniface memory. To be more specific, a Struct Variable refers to the root Struct Node of a struct dataset making this dataset the thing we call 'Struct'. The image shows two Struct variables referring to the root node of a Struct.
A Struct Variable can actually refer to multiple Structs or to none at all. To be specific, a Struct Variable can refer to 0, 1, or more Structs. The image shows a single Struct Variable containing 2 references to two Structs.
The opposite is also possible: multiple references to the same Struct. The image shows two Struct Variables referring to the same Struct. One has to refer to the root node, the other refers to some node in the same Struct making it a kind of sub-Struct or nested Struct. More about this construction later.
Struct Variable declaration
The declaration of a Struct Variable, does not create the Struct, it only creates a Struct Variable with zero references. This variable can now be used to either create a Struct from scratch or have it referred to an already existing Struct. The image shows two Struct Variables that do not refer to any Struct.
There are two ways to create a Struct. The first is by making use of the Proc function $newstruct. This Proc function creates a single Struct Node and returns a reference to it. If this reference is then assigned to a Struct Variable, a Struct consisting of a single node, has been created. The image shows the code used create a Struct with only one node. This Struct is now accessible via the Struct Variable.
The second is by making use of the conversion Proc statements like componenttostruct, xmltostruct, and jsontostruct. Maybe more conversion statements will follow in the future. A struct conversion function uses the provided data in some external format and generates a (huge) set of hierarchical related Struct nodes that logically represent the data. The Proc instruction returns a reference to the root node of this Struct which is typically assigned to a Struct Variable. This Struct is now accessible via the Struct Variable.
Struct member creation
To create a sub node, or a Struct member, you also use the Proc function $newstruct, but instead of assigning the newly created node to a Struct Variable, you assign it to a member a specified by its name. The image shows the code used create the initial Struct and then how members are created. The image also shows how an existing member is assigned to a Struct Variable, creating a sub-struct or nested Struct.
A Struct that is no longer referenced by a Struct Variable, and therefore not accessible, is automatically deleted from Uniface memory. The image shows that setting "" to the Struct Variable that refers the root node of the Struct will have as a consequence that the Struct will deleted. A Struct Variable running out of scope has the same effect.
The image shows that deleting a Struct does not affect any sub or nested Structs. The sub Struct, or nested Struct, has its own variable referring to its root node (this is what makes it a Struct) and therefore is still referenced and not deleted.
Uniface also supports Struct Parameters. The Struct Parameter is like the Struct Variable, it works with references. Image a Proc function that takes one struct parameter as input, it checks all members of the referenced Struct and returns references to the members that are leaves as Struct out parameter. The image shows the result after calling this function, where myStructVar1 refers to the root node of the Struct and myStructVar2 refers to all leaves in the same Struct as detected by the function. But more about Struct Parameters next time.