Arrays
Structorizer supports the use of arrays, basically of one-dimensional arrays. Technically speaking, Structorizer does not offer multi-dimensional arrays. But if you place arrays into the elements of (one-dimensional) arrays then the behaviour comes near to some approximation of multi-dimensional arrays.
One-dimensional arrays may be introduced in two ways:
1. Element-wise assignment (incremental growth)
As soon as you write an assignment or input instruction and append square brackets with an index expression to the target variable name, the variable will be made an array variable (if it hasn't been already):
names[2] <- "Goofy"
INPUT x[0]
The index range of arrays starts with 0. If you assign something to an array element with larger index than used before, the array will automatically be widened up to the new index. If there are index gaps, then the in-between elements will be filled with 0, e.g. in the first example above, the resulting array names would be filled as follows: {0, 0, "Goofy"}. Note that a reading access with an index larger than the highest index used for assignments or input before will abort the execution with an error message.
2. List initialisation
You may initialise an array variable with a list of element values, enclosed in curly braces (like in C, Java etc.):
values <- {17, 23.4, -9, 13}
friends <- {"Peter", "Paul", "Mary"}
You may combine the initialisation with a declaration in one of several syntactic styles (Pascal or, since version 3.32-04, also Java/C#):
var values: array of int <- {17, 23.4, -9, 13}
string[] friends <- {"Peter", "Paul", "Mary"}
Version 3.24-10 introduced the opportunity to provide such an initialiser expression even in the text field of an input dialog (as popped up by an executed input instruction), this way making the input variable an array variable:
Actually, it is not necessary in Structorizer (though highly recommendable for the processing algorithms), that all elements of an array be of the same type.
Arrays may be passed as arguments to a subroutine (mechanism is call by reference, i.e. changes to the array content will be propagated to and seen by the calling algorithm, unless the argument is an initialiser or the parameter is declared const). Routines may also return arrays as result.
Arrays should not be put into the expression list of an output instruction. An element-wise output is recommended. (Even if Executor may cope with direct output of arrays, code export will usually not produce sensible code in this case.) If a subroutine executed at top-level returns an array, however, then the array contents will be presented in a scrollable list view. This allows separate testing of subroutines requiring some of their parameters to be an array (on top-level execution, parameter values are requested interactively, and the input of a value list in curly braces provides an array, see above) or returning an array. The same holds for record variables or expressions, by the way.
Array variables or braced value lists (aka array initialisation expressions) are the natural things to be used as collections in FOR loops of the TRAVERSING variety (FOR-IN loops), see the FOR loop User Guide page for details.
The following NSD shows some advanced examples of executable and exportable array operations:
As already stated above, you may put entire arrays as elements into other arrays (see fifth instruction in the example diagram above, where one of the elements for mixedArray is the previously filled array named numbers; the second instruction, however, does not show nested arrays but instead the use of an index that has been taken out the same array, which seems somewhat bizarre but is sometimes used for indirection). Hence, it's possible to construct something resembling (though not actually being) a multi-dimensional array. The last instruction above shows the cascading index access to write an element of an inner array. From version 3.32-11 on, you may even write an index list between brackets to abbreviate the chained brackets, such that a[i,j] will be equivalent to a[i][j].
But be aware that Structorizer does not guarantee orthogonal multi-dimensional arrays, where all rows have the same number of columns etc. The "rows" may have different shapes of content, instead. So it is completely up to you to ensure that a combined index access makes sense and is structurally interpretable and correct.
In order to construct a surrogate for a small multi-dimensional array you use a nested array initialisation expression, e.g.:
Then you can access each of the elements and query the length (element number) of an array no matter whether it's nested:
In no case, however, you may incrementally widen an outer array of a "multi-dimensional" conglomerate by attempting to assign a value to a (non-existing) element of a fictitious array at a higher index than already existing:
The last instruction tries to assign value -9 to element 0 of an array assumed to be placed in the non-existent row 3 of the outer array. To widen the outer array automatically would not even help because this does not create the required inner array there. What you would have to do is a two-step sequence in this case:
- Append a new sub-array to matrix2d, e.g.:
matrix2d[3] ← {41, 42, 43, 44, 45}
- Override the element in the interesting (and now existing) place:
matrix2d[3][0] ← -9
Strings
Strings are not handled as arrays in Structorizer. (Instead they behave like objects of Java class java.lang.String, because that is what they actually are.) That means: You may obtain the length of a string s either by applying the Java method length() to it — s.length() — or by using the built-in function length(s). Character access via index brackets is not supported. To access a character in a string s, you may either write s.charAt(i) where i counts from 0 to s.length()-1, or you may use the built-in function copy(s, i, 1), which in fact extracts a substring of length 1 (which is not the same as a character, though) at position i where i ranges from 1 to s.length(); you may also have a FOR-IN loop iterate over a string variable (where the loop variable will get actual characters):
You may not replace a character within the string. You may only form new strings by using the built-in string functions (see reference above) or by concatenating strings with operator +.
Records / Structs
Since release 3.27, Structorizer also supports the use of records (aka structs). Like arrays, records are complex data structures offering the possibility to combine different data within one variable. Unlike arrays, records have got named components, which may explicitly be of different data types. Think of a date of the Gregorian calendar, consisting of a year, a month, and a day number. You might use an array of three numbers in a fixed order for it, but it would be more expressive to access the components via names. The component names and types, of course, must be declared to allow an unambiguous access. Likewise, you might want to combine data about persons, say their name, height, sex, and — hey! — their date of birth. So you should be able to build records on other kinds of records and to give these constructs a unique name.
A type definition syntax was introduced therefore.
Type definitions are to be placed within ordinary elements of Instruction kind, though a type definition doesn't do anything except telling Structorizer how variables of that kind are structured from that element on. The type definition for a record/struct type describes the structure and introduces a user-chosen name for these constructs:
The first two elements show record type definitions. Each starts with the keyword type, then the name for the type is to be specified, followed by an equality sign and one of the equivalent keywords record or struct and the component declarations within curly braces. Each component must be given a name and should be given a type. The third element of the diagram shows a record variable declaration with initialization via a "record literal" (or say an initialization expression). The initializer looks similar to the type specifications but starts with the previously defined type name instead of struct or record. Instead of component type names now appropriate values must be associated to the field names. The order of the fields may be arbitrary.
The fourth element of the diagram screenshot shows a mere declaration (without initialization), whereas separate component assignments to the otherwise uninitialized variable max follow in the fifth instruction element.
From version 3.32-11 on, the element editor supports you with component name suggestions whenever you type a dot after a (possibly complex) variable for which Structorizer infers a record structure from the type definitions and preceding declarations:
You may easily select one of the component names from the pulldown list and insert it into the text area by pressing the <Enter> key.
Since version 3.28-06, "smart" record initializers are supported, the item list of which may contain mere expressions — provided their order corresponds to that of the component declarations in the related record type definition. So variable way_back might also have been initialized as shown by the green instruction in the modified diagram snippet below:
From the first explicitly occurring component name, however, parsing will ignore all remaining values without component name prefix, such that in the example of the red instruction only components year and month of record partial would be assigned, whereas the value 21 will be ignored. (As the tooltip in the screenshot shows, Analyser will warn that the day component isn't going to be initialized.)
From version 3.32.12 on, Structorizer also supports type definitions for array types and alias type definitions:
If you pass variables of certain record type as parameters to a subroutine diagram, then a dilemma occurs: Where to place the type definition, such that the parameter structure would be available in both diagrams? In this case, the type definition can only be placed in an Includable diagram, which is then to be included by both the caller and the called diagram.
Enumerators (versions ≥ 3.30-03)
Often you are confronted with a type of data that is to represent one out of a finite and fix set of categories, e.g. the day of week (Monday / Tuesday / Wednesday / Thursday / Friday /Saturday / Sunday) or a university member status (Student / Assistant / Professor) or something the like. Of course you might code these values with integral numbers, but it would be more readable and intelligible if you could use symbolic designations. To use strings instead may be a bad option as it costs more memory and provides only poor options statically to ensure and check the correctness of such a value (e.g. against wrong spelling). Most programming languages therefore provide the concept of so called enumeration types. Actually, an enumeration type is no more than a set of named integer constants that is introduced by enumerating their identifiers.
You may define an enumeration type in Structorizer in the following way:
type and enum are reserved words, the identifier between type and = becomes the name of the enumeration type, the identifiers listed between the curly braces are the enumerator constants to be defined. Structorizer assigns consecutive integer codes to the enumerator elements in the listed order, i.e. the first name (e.g. Monday) will be associated with 0, the second one with 1, and so on.
If the coding matters in certain case, then you may explicitly assign a code value to some enumerator identifiers as shown in the orange element of the demo diagram below. The required operator symbol is = , the code must be a constant integer value (ideally a literal, like 42), but may be specified as a simple constant expression i.e. an arithmetic computation from integral constants (integer literals or previously defined constants, including enumerator identifiers) as shown below. Subsequent enumerator elements will be coded incrementally from the explicitly assigned element on.
|