Datatype Element/en: Unterschied zwischen den Versionen

Aus expecco Wiki (Version 2.x)
Zur Navigation springen Zur Suche springen
(35 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 16: Zeile 16:
:the "struct" singleton type (i.e. there is only one such type) represents arbitrary compound values, whose field names are defined at runtime. These can be used for compound objects, whose structure is not known in advance (for example, which are returned by an XML-RPC call). Technically, instances are represented as Dictionary (HashTable) instances. In a textual type definition, use the keyword "struct".
:the "struct" singleton type (i.e. there is only one such type) represents arbitrary compound values, whose field names are defined at runtime. These can be used for compound objects, whose structure is not known in advance (for example, which are returned by an XML-RPC call). Technically, instances are represented as Dictionary (HashTable) instances. In a textual type definition, use the keyword "struct".


==== Common Predefined Primary Types ====
==== Predefined Primary Types ====


The following well known types are predefined and guaranteed to be present in any expecco, without a need for a special type definition.
The following well known types are predefined and guaranteed to be present in any expecco, without a need for a special type definition.
They all refer to instances of standard classes of the underlying Smalltalk runtime system.
They all refer to instances of standard classes of the underlying Smalltalk runtime system.
More information is found in [[Expecco_API/en#Builtin Data Types|Expecco API document]] and the
More information is found in the [[Expecco_API/en#Builtin Data Types|"Expecco API"]] document and the
[http://live.exept.de/doc/online/english/classDoc/TOP.html Smalltalk Class Documentation] of the [http://live.exept.de/doc/online/english/TOP.html Smalltalk/X online documentation]. A good entry point for further learning is the [http://live.exept.de/doc/online/english/overview/basicClasses/TOP.html Smalltalk/X Basic Classes Overview Document], which provides links to the most heavily used classes and more detailed information.
[http://live.exept.de/doc/online/english/classDoc/TOP.html "Smalltalk Class Documentation"] of the [http://live.exept.de/doc/online/english/TOP.html "Smalltalk/X Online Documentation"].

A good entry point to the documentation is the [http://live.exept.de/doc/online/english/overview/basicClasses/TOP.html "Smalltalk/X Basic Classes Overview"] document, which provides links to the most heavily used classes and more detailed information.


===== Numeric Types =====
===== Numeric Types =====


;Integer
;Integer
:an integral number of arbitrary size (i.e. only limited by memory). Operations on integers automatically care for overflow and reserve more memory if required (i.e. there is no 32- or 64-bit overflow as in most other programming languages). If required to reproduce invalid numeric operations of other programming languages (i.e. C, C++, Java or C#), modulu operations which wrap the result within the 32bit range are provided in the standard library and/or the underlying Smalltalk library.
:an integral number of arbitrary size (i.e. only limited by memory). Operations on integers automatically care for overflow and reserve more memory if required (i.e. there is no 32- or 64-bit overflow as in most other programming languages). If required to reproduce invalid numeric operations of other programming languages (i.e. C, C++, Java or C#), modulu operations which wrap the result within the 32bit range are provided in the standard library and/or the underlying Smalltalk library.<br>Details in [http://live.exept.de/ClassDoc/classDocOf:,Integer Integer].


;Float
;Float
:an IEEE rational number with double-precision (64bit).
:an IEEE rational number with double-precision (64bit).
:[[Datei:bull.png|16px]]'''Be careful when using floats!'''<br>Floats sometimes show surprising behavior. E.g. the sum of 10 floats of 0.1 does not result in an exact 1.0, but in 0.99999999999999989 due to rounding errors. Any number which is not exactly a sum of power-of-two fractions is not representable exactly as float and suffers from this rounding error. This is not a problem or deficiency specific to expecco or its implementation, but a general problem of floating point numbers. Therefore, never use floats when you need exact (e.g. monetary) values. Read [http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems Wikipedia] for background information. There are extra blocks for fuzzy comparing float values in the Standard Library.
:[[Datei:point_right.png|20px]] '''Be careful when using floats!'''[[Datei:point_left.png|20px]]<br>Floats sometimes show surprising behavior. E.g. the sum of 10 floats of 0.1 does not result in an exact 1.0, but in 0.99999999999999989 due to rounding errors. Any number which is not exactly a sum of power-of-two fractions is not representable exactly as float and suffers from this rounding error. This is not a problem or deficiency specific to expecco or its implementation, but a general problem of floating point numbers. Therefore, never use floats when you need exact (e.g. monetary) values. Read [http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems Wikipedia] for background information. There are extra blocks for fuzzy comparing float values in the Standard Library.<br>Class details in [http://live.exept.de/ClassDoc/classDocOf:,Float Float].


;Fraction
;Fraction
:an exact fraction. These can result from dividing two integers. Operations on fractions are exact (without rounding errors). When possible, results are reduced and if possible converted to integral results (i.e. (1/3) * (1/3) * 9 -> 1, exact).
:an exact fraction. These can result from dividing two integers. Operations on fractions are exact (without rounding errors). When possible, results are reduced and if possible converted to integral results (i.e. (1/3) * (1/3) * 9 -> 1, exact).<br>Class details in [http://live.exept.de/ClassDoc/classDocOf:,Fraction Fraction].


;FixedPoint
;FixedPoint
:a decimal number which presents itself rounded to a given scale (= number of post-decimal digits). Although presenting its value rounded to a number of post-decimal digits, the exact value is kept internally for arithmetic operations, to prevent accumulating rounding errors. These are useful when monetary values are to be processed.
:a decimal number which presents itself rounded to a given scale (= number of post-decimal digits). Although presenting its value rounded to a number of post-decimal digits, the exact value is kept internally for arithmetic operations, to prevent accumulating rounding errors. These are useful when monetary values are to be processed.<br>Class details in [http://live.exept.de/ClassDoc/classDocOf:,FixedPoint FixedPoint].

;Complex
:a complex number consisting of a real- and an imaginary part.<br>Class details in [http://live.exept.de/ClassDoc/classDocOf:,Complex Complex].


;Number
;Number
:any numeric value (integer, float or fraction). Most arithmetic action blocks allow for mixed mode arithmetic; i.e. it is possible to add integer values to fractions, floats and vice versa. The resulting value's representation depends on the combination of input values, and will usually be the one with less exactness. I.e. when addinf an exact integer or fraction to an inexact float, the result will be an inexact float.
:any numeric value (integer, float or fraction). Most arithmetic action blocks allow for mixed mode arithmetic; i.e. it is possible to add integer values to fractions, floats and vice versa. The resulting value's representation depends on the combination of input values, and will usually be the one with less exactness. I.e. when addinf an exact integer or fraction to an inexact float, the result will be an inexact float.<br>Class details in [http://live.exept.de/ClassDoc/classDocOf:,Number Number].


===== Text Types =====
===== Text Types =====

;Filename
:represents a path/file name. Filename instances know how to construct sub- and parent folder names, provide check for file existence and size queries, etc. If used inside an elementary block, the full protocol of the [http://live.exept.de/ClassDoc/classDocOf:,Filename Filename class] can be used on them.


;String
;String
:a collection of characters of the Unicode character set. For a full protocol description, see [http://live.exept.de/ClassDoc/classDocOf:,String String class documentation]. Notice that String inherits a lot of functionality from its superclasses [http://live.exept.de/ClassDoc/classDocOf:,CharacterArray CharacterArray], [http://live.exept.de/ClassDoc/classDocOf:,SequenceableCollection SequenceableCollection] and [http://live.exept.de/ClassDoc/classDocOf:,Collection Collection], most of it is also useful for String instances.
:a collection of characters of the Unicode character set. For a full protocol description, see [http://live.exept.de/ClassDoc/classDocOf:,String String class documentation]. Notice that String inherits a lot of functionality from its superclasses [http://live.exept.de/ClassDoc/classDocOf:,CharacterArray CharacterArray], [http://live.exept.de/ClassDoc/classDocOf:,SequenceableCollection SequenceableCollection] and [http://live.exept.de/ClassDoc/classDocOf:,Collection Collection], most of it is also useful for String instances.

;Password
:same as String (above), but the string is not shown in the log or in the report.


;StringCollection
;StringCollection
:a collection of lines, typically as read from a file. StringCollections inherit from OrderedCollection, this any operation which is possible for OrderedCollections is also valid for StringCollections. See [http://live.exept.de/ClassDoc/classDocOf:,StringCollection StringCollection] for more info.
:a collection of lines, typically as read from a file. StringCollections inherit from OrderedCollection, this any operation which is possible for OrderedCollections is also valid for StringCollections. See [http://live.exept.de/ClassDoc/classDocOf:,StringCollection StringCollection] for more info.

;Filename
:represents a path/file name. Filename instances know how to construct sub- and parent folder names, provide check for file existence and size queries, etc. If used inside an elementary block, the full protocol of the [http://live.exept.de/ClassDoc/classDocOf:,Filename Filename class] can be used on them. In a freeze value of this type, $(xxx) patterns are expanded as described in the [[ElementaryBlock_Element/en#Execution_Directory | "ElementaryBlock Element Documentation"]].


;StringOrFilename
;StringOrFilename
:a union type which can be either a Filename object, or a String. This is used as input type of many file-handling actions, which will accept both. If required, those actions convert the string to a Filename instance automatically, before performing their action.
:a union type which can be either a Filename object, or a String. This is used as input type of many file-handling actions, which will accept both. If required, those actions convert the string to a Filename instance automatically, before performing their action. In a freeze value of this type, $(xxx) patterns are expanded as described in the [[ElementaryBlock_Element/en#Execution_Directory | "ElementaryBlock Element Documentation"]].


;UnicodeString
;UnicodeString
Zeile 70: Zeile 78:


;HexString
;HexString
:same as ByteArray, for TTCN3 compatibility
:an alias for ByteArray, for TTCN3 compatibility


;Collection
;Collection
Zeile 79: Zeile 87:


;OctetString
;OctetString
:same as ByteArray, for TTCN3 compatibility
:alias for ByteArray, for TTCN3 compatibility


;OrderedCollection
;OrderedCollection
Zeile 99: Zeile 107:


;DateTime
;DateTime
:represents both date and time (aka: timestamp) with at least millisecond resolution (actually, instances can hold a much better resolution, but not all operating systems will provide such high resolution timestamps). DateTime is an alias for the Timestamp class of Smalltalk. See [http://live.exept.de/ClassDoc/classDocOf:,Timestamp Timestamp].<br>Timestamps are not limited to the 1970..2039 range as in many Unix systems, or the 1900.. range, as in MS Windows. However, they do not correctly handle the Julian-Gregorian calendar change (e.g. when asked for weekday, leap year etc., they will simply extrapolate the Gregorian calendar [https://en.wikipedia.org/wiki/Gregorian_calendar]).
:represents both date and time (aka: timestamp) with at least millisecond resolution (actually, instances can hold a much better resolution, but not all operating systems will provide such high resolution timestamps). DateTime is an alias for the Timestamp class of Smalltalk. See [http://live.exept.de/ClassDoc/classDocOf:,Timestamp Timestamp].<p>Timestamps are not limited to the 1970..2039 range as in many Unix systems, or the 1900.. range, as in MS Windows. However, they do not correctly handle the Julian-Gregorian calendar change (e.g. when asked for weekday, leap year etc., they will simply extrapolate the Gregorian calendar [https://en.wikipedia.org/wiki/Gregorian_calendar]).<p>[[Datei:point_right.png|20px]] Timestamps will be represented either as UTC-timestamps, local timestamps or as TZ-timestamps, depending on the information which was present when it was created. When reading from a string, any timezone information there is preserved and the timestamp will present itself with that information. Thus, if a timestamp was read from an ISO8601 string with a "Z"-timezone, it will be a UTC-timestamp, and present itself as such. If the string ended with a "+/-hh" timezone delta, it will be a TZ-timestamp. Without timezone information, it will be interpreted as a local timestamp. You can always convert timestamps among the above representations, but internally they will all hold the UTC time, so the result of comparisons (before/after) and the sort order is always correct (i.e. based on the UTC time).


;Time
;Time
Zeile 106: Zeile 114:
<DIV ID="TimeDuration"> </DIV>
<DIV ID="TimeDuration"> </DIV>
;TimeDuration
;TimeDuration
:a time-delta (eg. 10m, 1h or 3d) with at least millisecond resolution. See [http://live.exept.de/ClassDoc/classDocOf:,TimeDuration TimeDuration].
:a time-delta (eg. "100ms", "0.4s", "10m", "1h" or "3d") with at least millisecond resolution. See [http://live.exept.de/ClassDoc/classDocOf:,TimeDuration TimeDuration].


===== Often Useful Types =====
===== Often Useful Types =====
Zeile 151: Zeile 159:


;Library
;Library
:Instances represent imported libraries. Pins of this type can only be frozen to a library; these are used to define which concrete library is to be used for a bundle of virtual actions. Similar to performer pins, these define at execution time which concrete actions are to be used for virtual actions (in this case: all virtual actions from a particular library).
:Instances represent imported libraries


;Performer
;Performer
:Instances represent [[Block_Element|action blocks]]. Their primary use is as input value of a [[VirtualBlock_Element|virtual block]], in order to define which concrete block is to be executed. Constant values (freeze values) of this type are kept as GUID (Globally Unique Identifier) of the referred-to block. The id of the block is found via the block's selection menu in the project tree, or in the documentation page of the block's editor.
:Instances represent [[Block_Element|action blocks]]. Their primary use is as input value of a [[VirtualBlock_Element|virtual block]], in order to define which concrete block is to be executed. Constant values (freeze values) of this type are kept as UUID (Universal Unique Identifier) of the referred-to block. The id of the block is found via the block's selection menu in the project tree, or in the documentation page of the block's editor.<P>Performer types can also be constrained to only allow for actions with a defined interface to be connected. This type is used with performer input pins, and the constraint is used to ensure that only references to allowed actions (i.e. implementing that interface) are delivered to the pin.
<!--:Instanzen dieses Typs repräsentieren eine Bausteindefinition. Diese werden primär als Eingabewert eines virtuellen Schrittes benötigt, damit dieser festlegen kann, welchen konkreten Baustein dieser ausführen soll. Konstanten von diesem Typ (Vorgabewerte) werden als GUID (Globally Unique Identifier) des Bausteins dargestellt. Diese ID eines Bausteins erhält man entweder über eine Menüfunktion im Projektbaum, oder in der Dokumentationsseite des Bausteineditors.-->
<!--:Instanzen dieses Typs repräsentieren eine Bausteindefinition. Diese werden primär als Eingabewert eines virtuellen Schrittes benötigt, damit dieser festlegen kann, welchen konkreten Baustein dieser ausführen soll. Konstanten von diesem Typ (Vorgabewerte) werden als GUID (Globally Unique Identifier) des Bausteins dargestellt. Diese ID eines Bausteins erhält man entweder über eine Menüfunktion im Projektbaum, oder in der Dokumentationsseite des Bausteineditors.-->


Zeile 287: Zeile 295:
)
)
</PRE></CODE>
</PRE></CODE>

Individual elements are pure symbolic tokens by default; however, it is possible to associate a numeric value to the elements by adding "<code> = &lt;val&gt;</code>" after the element(s). Without such a value declaration, each element gets numerically increasing integer values, starting at 0.


==== Datatype Types ====
==== Datatype Types ====
Zeile 379: Zeile 389:
===== Memory Management =====
===== Memory Management =====


By default, a CDatum's underlying memory is allocated with malloc() on the C-heap,
By default, a CDatum's underlying memory is allocated on the C-heap by <code>gcMalloc()</code>, which uses the standard <code>malloc()</code> function.
and automatically freed when there is no longer any reference to it from expecco.
It will be automatically freed, when there is no longer any reference to it from expecco.


This scheme works in most situations, except when the datum is to be given to an external C-function which frees the data after use (for example, in a message queue-like framework, where data-buffers are passed to a C-function which frees the data, when done).
This scheme works in most situations, except when the datum is to be given to an external C-function which frees the data after use or which holds on the data for an unknown time period. An example is a message queue-like framework, where data-buffers are passed to a C-function which frees the data, when done. Another example might be a framework where data is passed to a C-library which frees it later, when a release/cleanup/shutdown function is called.


In this case, expecco should not free the data.
In this case, expecco should not free the data, because it does not know about any pending references inside the called C code.
To prevent this, send a "protectFromGC" message to the CDatum:
To prevent this, either send a "<code>protectFromGC()</code>" message to the allocated CDatum:
<CODE><PRE>
<CODE><PRE>
inst.protectFromGC();
inst.protectFromGC();
</PRE></CODE>
</PRE></CODE>
or allocate it using "<code>malloc()</code>" instead of "<code>gcMalloc()</code>".


The opposite is to explicitly free the underlying emory,
Your program (or suite) has to explicitly free the underlying emory at some time (maybe as a post-action of either the test plan or the unload actions of your project).
which is useful if a big memory block should be released as soo as possible:
Explicit freeing is also useful if a big gcMalloc'd memory block should be released as soon as possible:
<CODE><PRE>
<CODE><PRE>
inst.free();
inst.free();
Zeile 461: Zeile 472:


So here follows example code for an action to instantiate and initialize an instance of the above data structure. To make the example a little shorter, not all fields are initialized; the action block is assumed to have input pins for Address, Length and Port values (all defined as Integer or unsigned long typed pins) and additional pins named pID0, param0 and pid1, param1 to preset two of the inner structures's elements:
So here follows example code for an action to instantiate and initialize an instance of the above data structure. To make the example a little shorter, not all fields are initialized; the action block is assumed to have input pins for Address, Length and Port values (all defined as Integer or unsigned long typed pins) and additional pins named pID0, param0 and pid1, param1 to preset two of the inner structures's elements:
<br>[[Datei:New_struct_s_action.png]]
<br>[[Datei:New_struct_s_action.png|350px]]


and its execution code is:
and its execution code is:
Zeile 502: Zeile 513:
===== Dealing with Pointers =====
===== Dealing with Pointers =====


Warning: the previous expecco releases (pre 2.12) do not handle embedded structure pointers correctly.
Warning: the previous expecco releases (pre 18.1) do not handle embedded structure pointers correctly.
The example below will only work in 2.12 and later versions.
The example below will only work in 18.1 and later versions.


Consider the following two type definition, which are used in an expecco type definition (of type CType):
Consider the following two type definition, which are used in an expecco type definition (of type CType):
Zeile 526: Zeile 537:
first notice that there are two structures in one type definition. In this case, the expecco type item (in the tree) represents the last of the defined types - in this case the "''struct b''".
first notice that there are two structures in one type definition. In this case, the expecco type item (in the tree) represents the last of the defined types - in this case the "''struct b''".


Let's assume, that we have to allocate an instance of "struct b" in an instance creation block (which has a single pin named "''newInst''" of type "struct b":
Let's assume, that we have to allocate an instance of "<code>struct b</code>" in an instance creation block (which has a single pin named "''newInst''" of type "<code>struct b</code>":


[[Datei:new_struct_b_action.png]]
[[Datei:new_struct_b_action.png|350px]]


and the following code:
and the following code:


<CODE><PRE>
<CODE><PRE>
execute
execute() {
|structB_t newInstOfB|
var structB_t, newInstOfB;


structB_t := newInst datatype.
structB_t = newInst.datatype();
newInstOfB := structB_t gcMalloc.
newInstOfB = structB_t.gcMalloc();
newInst value:newInstOfB. "/ write the pin
newInst.value(newInstOfB); // write the pin
}
</PRE></CODE>
</PRE></CODE>


Zeile 545: Zeile 557:




[[Datei:new_struct_b_action_output.png]]
[[Datei:new_struct_b_action_output.png|500px]]


As seen, the "struct a"-pointer in "aPtr" is NULL.
As seen, the "<code>struct a</code>"-pointer in "<code>aPtr</code>" is NULL.
An instance needs to be allocated separately and a pointer to it must be placed into the pointer field.
An instance needs to be allocated separately and a pointer to it must be placed into the pointer field.
To get the pointer-field's type, we can ask the "struct b" instance for its "aPtr" field definition: <CODE>(newInstOfB type fieldNamed:'aPtr')</CODE> and then ask this field information about the fields type.
To get the pointer-field's type, we can ask the "<code>struct b</code>" instance for its "<code>aPtr</code>" field definition: <CODE>(newInstOfB type fieldNamed:'aPtr')</CODE> and then ask this field information about the fields type.
Thus, we acquire the aPtr-fields type (i.e. the "struct a"-type) with:
Thus, we acquire the aPtr-fields type (i.e. the "<code>struct a</code>"-type) with:


<CODE><PRE>
<CODE><PRE>
structAPtr_t := (newInstOfB type fieldNamed:'aPtr') type.
structAPtr_t = (newInstOfB.type.fieldNamed("aPtr").type;
</PRE></CODE>
</PRE></CODE>
Notice, that this gives us a '''pointer''' to "struct a" type - not the "struct a" type.
Notice, that this gives us a '''reference''' to the "struct a" type - not an instance of a "<code>struct a</code>" type.
Thus,
Thus,
<CODE><PRE>
<CODE><PRE>
structA_t := structAPtr_t baseType.
structA_t = structAPtr_t.baseType;
</PRE></CODE>
</PRE></CODE>
and in the same way as above, we allocate an instance of it with:
and in the same way as above, we allocate an instance of it with:
<CODE><PRE>
<CODE><PRE>
newInstOfA := structA_t gcMalloc.
newInstOfA = structA_t.gcMalloc();
</PRE></CODE>
</PRE></CODE>
Finally, the new instance is stored into the pointer field with:
Finally, the new instance is stored into the pointer field with:
<CODE><PRE>
<CODE><PRE>
newInstOfB aPtr: newInstOfA.
newInstOfB.aPtr( newInstOfA );
</PRE></CODE>
</PRE></CODE>


Zeile 572: Zeile 584:


<CODE><PRE>
<CODE><PRE>
execute
execute() {
|structB_t newInstOfA newInstOfB structAPtr_t structA_t|
var structB_t, newInstOfA, newInstOfB, structAPtr_t, structA_t;


"/ fetch the "struct b"-type from the pin's datatype
// fetch the "struct b"-type from the pin's datatype
structB_t := newInst datatype.
structB_t = newInst.datatype;
"/ get a new instance of "struct b"
// get a new instance of "struct b"
newInstOfB := structB_t gcMalloc.
newInstOfB = structB_t.gcMalloc();
newInstOfB i2:22.
newInstOfB.i2(22);
newInstOfB f2:22.2.
newInstOfB.f2(22.2);
newInstOfB d2:22.22.
newInstOfB.d2(22.22);


"/ fetch the "pointer-to-struct a"-type from the field
// fetch the "pointer-to-struct a"-type from the field
structAPtr_t := (newInstOfB type fieldNamed:'aPtr') type.
structAPtr_t = (newInstOfB.type.fieldNamed("aPtr").type;
"/ dereference the type, getting the "struct a"-type
// dereference the type, getting the "struct a"-type
structA_t := structAPtr_t baseType.
structA_t = structAPtr_t.baseType;


"/ get a new instance of "struct a"
// get a new instance of "struct a"
newInstOfA := structA_t gcMalloc.
newInstOfA = structA_t.gcMalloc();
newInstOfA i1:11.
newInstOfA.i1(11);
newInstOfA f1:11.1.
newInstOfA.f1(11.1);
newInstOfA d1:11.11.
newInstOfA.d1(11.11);
newInstOfA c:'hello1'.
newInstOfA.c("hello1");
"/ store the pointer
// store the pointer
newInstOfB aPtr:newInstOfA.
newInstOfB.aPtr(newInstOfA);


"/ send it to the pin
"/ send it to the pin
Zeile 605: Zeile 617:




[[Datei:new_struct_b_action_output2.png]]
[[Datei:new_struct_b_action_output2.png|500px]]


=== Special Types ===
=== Special Types ===
Zeile 655: Zeile 667:


However, when connecting, binding is only allowed to types which are compatible with a <code>Collection</code> type.
However, when connecting, binding is only allowed to types which are compatible with a <code>Collection</code> type.

==== Performer Type ====

Instances of ''Performer Type'' represent a reference to an expecco action.
Performer types can also be specific to only allow references to actions which implement a particular interface.
Examples:
Performer

Performer ( 'Name of Virtual Action' )

Performer ( interface: UUID-of Virtual Action )


=== Formal (BNF) Syntax of Type Declarations ===
=== Formal (BNF) Syntax of Type Declarations ===

Version vom 8. November 2018, 23:23 Uhr

Introduction[Bearbeiten]

A datatype element is used to define additional datatypes which are not available in the default set of provided datatypes. They can be modified in the datatype editor. Beside user defined types, a number of builtin (predefined) types are available. Those are not found in the navigation tree, but will be presented in the datatype chooser-menus.

Standard (Predefined) Types[Bearbeiten]

A number of types are already built into and well-known to expecco. These are:

General Types[Bearbeiten]

Any
any object. Useful when the exact type is not known/not relevant. Instances can be of any other type. But please read "Any Type Considered Harmful" before defining an output pin, or freezing an input pin with this type
struct
the "struct" singleton type (i.e. there is only one such type) represents arbitrary compound values, whose field names are defined at runtime. These can be used for compound objects, whose structure is not known in advance (for example, which are returned by an XML-RPC call). Technically, instances are represented as Dictionary (HashTable) instances. In a textual type definition, use the keyword "struct".

Predefined Primary Types[Bearbeiten]

The following well known types are predefined and guaranteed to be present in any expecco, without a need for a special type definition. They all refer to instances of standard classes of the underlying Smalltalk runtime system. More information is found in the "Expecco API" document and the "Smalltalk Class Documentation" of the "Smalltalk/X Online Documentation".

A good entry point to the documentation is the "Smalltalk/X Basic Classes Overview" document, which provides links to the most heavily used classes and more detailed information.

Numeric Types[Bearbeiten]
Integer
an integral number of arbitrary size (i.e. only limited by memory). Operations on integers automatically care for overflow and reserve more memory if required (i.e. there is no 32- or 64-bit overflow as in most other programming languages). If required to reproduce invalid numeric operations of other programming languages (i.e. C, C++, Java or C#), modulu operations which wrap the result within the 32bit range are provided in the standard library and/or the underlying Smalltalk library.
Details in Integer.
Float
an IEEE rational number with double-precision (64bit).
Point right.png Be careful when using floats!Point left.png
Floats sometimes show surprising behavior. E.g. the sum of 10 floats of 0.1 does not result in an exact 1.0, but in 0.99999999999999989 due to rounding errors. Any number which is not exactly a sum of power-of-two fractions is not representable exactly as float and suffers from this rounding error. This is not a problem or deficiency specific to expecco or its implementation, but a general problem of floating point numbers. Therefore, never use floats when you need exact (e.g. monetary) values. Read Wikipedia for background information. There are extra blocks for fuzzy comparing float values in the Standard Library.
Class details in Float.
Fraction
an exact fraction. These can result from dividing two integers. Operations on fractions are exact (without rounding errors). When possible, results are reduced and if possible converted to integral results (i.e. (1/3) * (1/3) * 9 -> 1, exact).
Class details in Fraction.
FixedPoint
a decimal number which presents itself rounded to a given scale (= number of post-decimal digits). Although presenting its value rounded to a number of post-decimal digits, the exact value is kept internally for arithmetic operations, to prevent accumulating rounding errors. These are useful when monetary values are to be processed.
Class details in FixedPoint.
Complex
a complex number consisting of a real- and an imaginary part.
Class details in Complex.
Number
any numeric value (integer, float or fraction). Most arithmetic action blocks allow for mixed mode arithmetic; i.e. it is possible to add integer values to fractions, floats and vice versa. The resulting value's representation depends on the combination of input values, and will usually be the one with less exactness. I.e. when addinf an exact integer or fraction to an inexact float, the result will be an inexact float.
Class details in Number.
Text Types[Bearbeiten]
String
a collection of characters of the Unicode character set. For a full protocol description, see String class documentation. Notice that String inherits a lot of functionality from its superclasses CharacterArray, SequenceableCollection and Collection, most of it is also useful for String instances.
Password
same as String (above), but the string is not shown in the log or in the report.
StringCollection
a collection of lines, typically as read from a file. StringCollections inherit from OrderedCollection, this any operation which is possible for OrderedCollections is also valid for StringCollections. See StringCollection for more info.
Filename
represents a path/file name. Filename instances know how to construct sub- and parent folder names, provide check for file existence and size queries, etc. If used inside an elementary block, the full protocol of the Filename class can be used on them. In a freeze value of this type, $(xxx) patterns are expanded as described in the "ElementaryBlock Element Documentation".
StringOrFilename
a union type which can be either a Filename object, or a String. This is used as input type of many file-handling actions, which will accept both. If required, those actions convert the string to a Filename instance automatically, before performing their action. In a freeze value of this type, $(xxx) patterns are expanded as described in the "ElementaryBlock Element Documentation".
UnicodeString
now obsolete, as String has been generalized to include both single-byte and wide characters. The type is still present for backward compatibility, but should not be used explicitly in new projects.
URL
URLs (Universal Resource Locators) are used in web browsers to address web documents and to locate web services. Instances know how to extract host, port, access method and path. See URL for more info.
Container Types[Bearbeiten]
BitString
an array of bits. The elements are integers in the range {0..1}. See BitArray for more info.
ByteArray
an array of bytes. The elements are integers in the range {0..255}. See ByteArray .
HexString
an alias for ByteArray, for TTCN3 compatibility
Collection
a collection of any other object (possibly unordered). Collection is an abstract superclass covering all other container types. This includes ordered and unordered collections, Strings, Sets and Dictionaries. See Collection for more info.
Dictionary (HashTable)
a mapped collection, where the key/index may be any arbitrary object. The Java name of this is "Hashtable". See Dictionary for more info.
OctetString
alias for ByteArray, for TTCN3 compatibility
OrderedCollection
a growable (variable sized) collection of arbitrary objects which is indexed by a numeric index. See OrderedCollection for more info.
SequenceableCollection
any collection, with integral index (possibly non-growing). See SequenceableCollection for more info.
Set
an unordered collection, where every object occurs at most once. See Set for more info.

The system contains many more collection types, such as Bags, BTrees, LinkedLists, etc. For more information refer to the ["Smalltalk/X Online Documentation"] or open a class browser and look at the subclasses of the "Collection" class.

Time and Date[Bearbeiten]
Date
represents a date (dd-mm-yy). See Date.
DateTime
represents both date and time (aka: timestamp) with at least millisecond resolution (actually, instances can hold a much better resolution, but not all operating systems will provide such high resolution timestamps). DateTime is an alias for the Timestamp class of Smalltalk. See Timestamp.

Timestamps are not limited to the 1970..2039 range as in many Unix systems, or the 1900.. range, as in MS Windows. However, they do not correctly handle the Julian-Gregorian calendar change (e.g. when asked for weekday, leap year etc., they will simply extrapolate the Gregorian calendar [1]).

Point right.png Timestamps will be represented either as UTC-timestamps, local timestamps or as TZ-timestamps, depending on the information which was present when it was created. When reading from a string, any timezone information there is preserved and the timestamp will present itself with that information. Thus, if a timestamp was read from an ISO8601 string with a "Z"-timezone, it will be a UTC-timestamp, and present itself as such. If the string ended with a "+/-hh" timezone delta, it will be a TZ-timestamp. Without timezone information, it will be interpreted as a local timestamp. You can always convert timestamps among the above representations, but internally they will all hold the UTC time, so the result of comparisons (before/after) and the sort order is always correct (i.e. based on the UTC time).

Time
a time of the day (hh:mm:ss). See Time.
TimeDuration
a time-delta (eg. "100ms", "0.4s", "10m", "1h" or "3d") with at least millisecond resolution. See TimeDuration.
Often Useful Types[Bearbeiten]
Boolean
boolean truth values: true and false. See Boolean.
IPAddress
represents an ipv4 or ipv6 address. See SocketAddress.
Socket
represents a socket connection stream. See Socket. Notice that sockets inherit from Stream, so all operations defined there are also useful when writing elementary code for socket connections.
Stream
any stream. See Stream and its subclasses, especially PositionableStream, ReadStream, WriteStream and ExternalStream, which is the superclass of FileStream.
UUID
a globally unique identifier. See UUID.
Special Low Level Types (not normally used)[Bearbeiten]
ExternalAddress
a pointer to external data (C pointer). Instances are typically allocated using malloc/free and are passed to/returned from calls to C library functions (via DLL action blocks).
Handle
a handle as returned by some operating-system calls. For example, window handles and open file handles are represented by them.

Expecco Types[Bearbeiten]

These represent objects as used or generated by expecco itself.

ActivityLog
Represents detail information of a test- or block execution. In particular, pin values, log-messages, caller and called actions are recorded in here.
Datatype
a meta type; instances are datatypes themselves. These are most useful as a pin type of an instance creation block. For example, in the collection-instantiation blocks, a type pin defines what type of collection is to be created.

Datatype-types can be constraint (a so called "constraint datatype-type") to a subset of types which match a particular query.
This is e.g. useful to specify that the frozen type must be a subclass of Collection.

Details are found in the datatype editor's documentation.

Error & Exception
Additional details of an exception (provided at exception output pins)
GUI Aspect
used with GUI block descriptions
Library
Instances represent imported libraries. Pins of this type can only be frozen to a library; these are used to define which concrete library is to be used for a bundle of virtual actions. Similar to performer pins, these define at execution time which concrete actions are to be used for virtual actions (in this case: all virtual actions from a particular library).
Performer
Instances represent action blocks. Their primary use is as input value of a virtual block, in order to define which concrete block is to be executed. Constant values (freeze values) of this type are kept as UUID (Universal Unique Identifier) of the referred-to block. The id of the block is found via the block's selection menu in the project tree, or in the documentation page of the block's editor.

Performer types can also be constrained to only allow for actions with a defined interface to be connected. This type is used with performer input pins, and the constraint is used to ensure that only references to allowed actions (i.e. implementing that interface) are delivered to the pin.

Report Template
Instances represent Report Templates
Resource
Represents a device, a human operator or any other resource.
SUnit TestResult
represents test results as generated by an internal unit test execution
Symbol
unique symbols of the underlying Smalltalk runtime system. These are used as hash key when naming classes, methods, UI aspects and others. Also, all enum values are internally represented as instances of Symbol. Symbols inherit from the String class and can thus be used (readonly) wherever strings can be used; in particular, with the formatting and string concatenation functions.
Verdict
Instances represent a test- or block execution's outcome (PASS, FAIL, ERROR or INCONCLUSIVE)

User Defined Types[Bearbeiten]

New user defined types can be constructed by a number of different mechanisms:

Primary Types[Bearbeiten]

Primary types represent existing classes of the underlying Smalltalk VM (virtual machine). These are the classes as described in the "Smalltalk/X Online Documentation", in addition to any classes which have been loaded dynamically via the plugin mechanism or as extension classes. Notice that all of the above listed builtin types are actually predefined well-known primary types and a placeholders/aliases for the corresponding underlying Smalltalk classes. You can browse the system for all classes using the system browser (found in the "Tools" menu); however, you must have installed the source code (in the installation procedure) to see the code.

Tuple Types[Bearbeiten]

A tuple type consists of a fixed number of fields which are accessed by a numeric index, where each field is defined by its (individual) type. For example, an object which associates a name with an age and a gender could be represented by a tuple instance as:

tuple type:

    (
        String
        Integer
        enum(M|F)
    )

when instantiated, fixed sizes arrays are created for tuple instances. Given a tuple type T, it can be instantiated with:

    inst = T.new();

and the fields can be set with:

    inst[1] = "Andy";
    inst[2] = 45;
    inst[3] = 'M'.asSymbol();

In most cases, compound types are a better choice to tuples: due to the naming of fields, compounds are less error prone and more self-describing.

Compound Types[Bearbeiten]

A compound type consists of a number of named fields, each defined by its type. For example, a customer record could be represented by a compound type instance as a structure consisting of individual fields:

compound type:

    {
        firstName: String
        lastName: String
        zip: Integer
        age: Integer
    }

when instantiated, an anonymous class is created for instances of compound types. These objects provide virtual accessor functions (getters and setters), which are named as the field names. Thus, given a compound type T, it can be instantiated with:

    inst = T.new();

and the fields can be set with:

    inst.firstName( "Andy" );
    inst.lastName( "Miller" );
    inst.age ( 41 );

Enumeration Types[Bearbeiten]

An instance of an enumerated type can take a value from a defined list of values. For example, a test-outcome could be defined as an enumerated type:

enum type:

    (
        pass | fail | inconclusive
    )

(notice, that there is already a Verdict type present in the set of standard types, so the above example is somewhat unrealistic).

Internally, enum values are kept as instances of the underlying Smalltalk Symbol class, which itself derives from String. Thus, an enum value can be fed to any input which accepts strings. Be aware of this: if you define an enum type as "( 1 | 2 | 3)", the enum-elements will be the strings "1", "2" and "3" - not integers.

A freeze value editor presents the enum values as a combolist, which presents the values as a list from which the user chooses the desired item. The organization of this list can be specified in the datatype editor to better meet UI requirements (for example, as hierarchical menu, sorted etc.)

The following section is only value for expecco version starting with 2.8:

Enum values can have an associated integer value, which is useful, if the type is actually a mapping of a corresponding C or Java type.
For this, add an "= <integerValue>" after the element's name to the above definition. I.e.:

enum type:

    (
        pass = 10 | fail = 20 | inconclusive = 30
    )

Without explicit integer value, elements get auto-incremented values, starting with 0 (zero) assigned implicitly.

Subrange Types[Bearbeiten]

A subrange of the set of values of either the integer- or the character type. A subrange type defines the minimum and maximum values from the base type's set of values.

For example, a type to describe byte-valued integers could be described as:

range( Integer : 0 .. 255 )

Union Types[Bearbeiten]

A union type represents a number of alternative fields. The selection of which field is actually valid within a union must be done elsewhere (or, via reflection, by asking the object dynamically).

For example, a type to describe an object which is either numeric or a string, could be described as:

union type:

    (
        String | Integer
    )

Individual elements are pure symbolic tokens by default; however, it is possible to associate a numeric value to the elements by adding " = <val>" after the element(s). Without such a value declaration, each element gets numerically increasing integer values, starting at 0.

Datatype Types[Bearbeiten]

A type representing other types

The type definition:

datatype

defines a type which can represent any other type.

Datatype types can be constraint as described in more detail below. For example, a type to represent all types which are CTypes can be described as:

datatype( isCTypeType )

These types are useful as pinType of instance creators, especially because the freeze-value men provides useful selection lists.

Constraint Datatype Type[Bearbeiten]

Starting with expecco 2.8, a datatype type can be constraint to a subset of types, by defining it as:

datatype ( <constraint> )

where constraint a selector from one of:

  • isArrayType - for types which have integer-indexable slots
  • isCTypeType - for C-defined types
  • isCEnumType - for C enum types (2.12)
  • isCStructType - for C-defined struct types (2.12)
  • isCUnionType - for C-defined union types (2.12)
  • isCollectionPrimaryType - for subtypes of Collection (i.e. Dictionary, Set, OrderedCollection etc.)
  • isCompoundType - for compound types
  • isEnumType - for enum types
  • isNumberPrimaryType - for subtypes of Number (i.e. Float, Integer, Fraction, FixedPoint)
  • isPrimaryType - for any primary type
  • isStreamPrimaryType - for subtypes of Stream
  • isTupleType - for any tuple type
  • isUnionType - for any union type
  • isUserDefinedDatatype - for all user defined types
  • isWellKnownDatatype - for all builtin (i.e. not user defined) type

or a selector plus string argument from one of (expecco vsn >= 2.12):

  • nameMatches: 'globPattern'
  • nameMatchesRegex: 'regexPattern'

Constrained datatypes should be used by the StandardLibraries only, and are used to limit the input values of some instance creation actions. For example, the "New Collection" action has an input pin, which defines the type of collection to be created. This pin has the type: "datatype( isCollectionPrimaryType )".

Examples:

datatype ( Integer ) -- a type whose instances are all datatypes which are compatible with the Integer class
datatype ( isCTypeType ) -- a type whose instances are all known C-types
datatype ( isCStructType ) -- a type representing all known C struct types
datatype ( nameMatches: 'DPU*' ) -- a type representing all types which match this name

CTypes[Bearbeiten]

A CType is similar to a compound type; however, a data representation is used, which is compatible to structures of the C programming language. This representation is mapped onto a byte container, such as a ByteArray or a malloc'd chunk of memory, and can be passed to/from external C functions.

Be aware, that by default, C data is allocated on the C heap using malloc() and released by free(). Therefore, the overhead in terms of memory use and processing power is much higher, when compared to normal compound or primary instances (i.e. normal expecco objects). You should therefore only use CType instances when data has to be exchanged with C programs (typically via a DLL-call action block).

A CType's definition is given in C syntax.
For example, the above customer record could be represented as the following C structure:

    /* C: */
    struct {
        char firstName[20];
        char lastName[20];
        int zip;
        short age;
    }

Notice the "/* C: */"-comment in the first line, which is obligatory to mark C type definitions. Also notice the explicit dimension of the strings. These are required to define the C structure's exact size. When instantiated, an object is created, which has the underlying C structure layout, and which is not moved in memory by the garbage collector (i.e. its address remains constant). It can therefore be passed to a called C function, for example in a DLL call.

Similar to compound types, instances of CTypes understand accessor functions.
Given a CType in variable T, it can be instantiated with:

    inst = T.new();

a good trick to get hold of the datatype is to fetch it from an output pin, as in:

    inst = aCtypeOutputPin.datatype.new();

Then, the fields can be set with:

    inst.firstName( "Andy" );
    inst.lastName( "Miller" );
    inst.age ( 41 );
Memory Management[Bearbeiten]

By default, a CDatum's underlying memory is allocated on the C-heap by gcMalloc(), which uses the standard malloc() function. It will be automatically freed, when there is no longer any reference to it from expecco.

This scheme works in most situations, except when the datum is to be given to an external C-function which frees the data after use or which holds on the data for an unknown time period. An example is a message queue-like framework, where data-buffers are passed to a C-function which frees the data, when done. Another example might be a framework where data is passed to a C-library which frees it later, when a release/cleanup/shutdown function is called.

In this case, expecco should not free the data, because it does not know about any pending references inside the called C code. To prevent this, either send a "protectFromGC()" message to the allocated CDatum:

    inst.protectFromGC();

or allocate it using "malloc()" instead of "gcMalloc()".

Your program (or suite) has to explicitly free the underlying emory at some time (maybe as a post-action of either the test plan or the unload actions of your project). Explicit freeing is also useful if a big gcMalloc'd memory block should be released as soon as possible:

    inst.free();
Nested Structures and Arrays of Structures[Bearbeiten]

Some care is required when C structures are nested or if arrays of structures/unions are used, as in the following structure:

/* C: */
struct s {
    unsigned long Address;
    unsigned long Length;
    unsigned long PortAddress;
    struct p {
        unsigned char ProtocolID;
        union u {
            uint16 InOutAreaSize;
            uint16 InAreaSize;
        } Parameter;
    } Protocol[4];
};

Assuming, that the above type is referred to as T (acquired usually by getting a pin's datatype), a new instance is created as usual with:

    T = outputPin.datatype;
    inst = T.new();

and gives you a C-datum of size 40 (on a 64 bit machine).

and the fields can be set with:

    inst.Address( 1234 );
    inst.Length( 100 );
    inst.PortAddress ( 40 );

or (in JavaScript) with:

    inst.Address = 1234;
    inst.Length = 100;
    inst.PortAddress = 40;

The accessor functions will always extract (copy) out values from the C datum. Therefore, the inner fields of (say) parameter cannot be accessed directly using code like:

    this does not work!!!

    inst.Protocol[0].ProtocolID = 17;
    inst.Protocol[0].Parameter.InOutAreaSize = 20;

does not work, because it would first extract the Protocol-substructure (Protocol[0]) as a copy of the inner structure, and then access the ProtocolID and Parameter values there, instead of setting fields in the original datum.

To set those inner fields, you need to first get a pointer to the inner structure, and then refer to the fields via the pointer, as in:

    // the following gives us a pointer to the Protocol field...
    pProtocol = _newInst.refMemberAt('Protocol');

    // a pointer to the first element there...
    pProtocol0 = pProtocol.refAt(0);

and then manipulate fields via those pointers:

    pProtocol0.ProtocolID = 17;
    pProtocol0.Parameter.InOutAreaSize = 20;

So here follows example code for an action to instantiate and initialize an instance of the above data structure. To make the example a little shorter, not all fields are initialized; the action block is assumed to have input pins for Address, Length and Port values (all defined as Integer or unsigned long typed pins) and additional pins named pID0, param0 and pid1, param1 to preset two of the inner structures's elements:
New struct s action.png

and its execution code is:

execute() {
    // Generates a new instance of struct s

    var structType;
    var newInst;
    var pProtocol, pProtocol0, pProtocol1;
    
    structType = new_struct_s.datatype;
    newInst = structType.new;

    newInst.Address = Address.value;
    newInst.Length = Length.value;
    newInst.PortAddress = Port.value;

    // the following gives us a pointer to the Protocol field...
    pProtocol = newInst.refMemberAt('Protocol');
    // a pointer to the first element...
    pProtocol0 = pProtocol.refAt(0);

    // set those values from pin values
    pProtocol0.ProtocolID = pID0.value;
    pProtocol0.Parameter.dpInAreaSize = param0.value;
    
    // a pointer to the 2nd element...
    pProtocol1 = pProtocol.refAt(1);

    // set those values from pin values
    pProtocol1.ProtocolID = pID1.value;
    pProtocol1.Parameter.dpInAreaSize = param1.value;

    // write it to the output pin
    new_struct_s.value(newInst);
}
Dealing with Pointers[Bearbeiten]

Warning: the previous expecco releases (pre 18.1) do not handle embedded structure pointers correctly. The example below will only work in 18.1 and later versions.

Consider the following two type definition, which are used in an expecco type definition (of type CType):

/* C: */
struct a {
    int i1;
    float f1;
    double d1;
    char c[20];
};

struct b {
    int i2;
    float f2;
    double d2;
    struct a *aPtr;
};

first notice that there are two structures in one type definition. In this case, the expecco type item (in the tree) represents the last of the defined types - in this case the "struct b".

Let's assume, that we have to allocate an instance of "struct b" in an instance creation block (which has a single pin named "newInst" of type "struct b":

New struct b action.png

and the following code:

execute() {
    var structB_t, newInstOfB;

    structB_t = newInst.datatype();
    newInstOfB = structB_t.gcMalloc();
    
    newInst.value(newInstOfB); // write the pin
}

then, when executed, the output pin "newInst" will generate the following value:


New struct b action output.png

As seen, the "struct a"-pointer in "aPtr" is NULL. An instance needs to be allocated separately and a pointer to it must be placed into the pointer field. To get the pointer-field's type, we can ask the "struct b" instance for its "aPtr" field definition: (newInstOfB type fieldNamed:'aPtr') and then ask this field information about the fields type. Thus, we acquire the aPtr-fields type (i.e. the "struct a"-type) with:

structAPtr_t = (newInstOfB.type.fieldNamed("aPtr").type;

Notice, that this gives us a reference to the "struct a" type - not an instance of a "struct a" type. Thus,

structA_t = structAPtr_t.baseType;

and in the same way as above, we allocate an instance of it with:

newInstOfA = structA_t.gcMalloc();

Finally, the new instance is stored into the pointer field with:

newInstOfB.aPtr( newInstOfA );

So the final code to instantiate the two structs and link them via the pointer will be:

execute() {
    var structB_t, newInstOfA, newInstOfB, structAPtr_t, structA_t;

   // fetch the "struct b"-type from the pin's datatype
    structB_t = newInst.datatype;
    // get a new instance of "struct b"
    newInstOfB = structB_t.gcMalloc();
    newInstOfB.i2(22);
    newInstOfB.f2(22.2);
    newInstOfB.d2(22.22);

    // fetch the "pointer-to-struct a"-type from the field
    structAPtr_t = (newInstOfB.type.fieldNamed("aPtr").type;
    // dereference the type, getting the "struct a"-type
    structA_t = structAPtr_t.baseType;

    // get a new instance of "struct a"
    newInstOfA = structA_t.gcMalloc();
    newInstOfA.i1(11);
    newInstOfA.f1(11.1);
    newInstOfA.d1(11.11);
    newInstOfA.c("hello1");
    
    // store the pointer
    newInstOfB.aPtr(newInstOfA);

    "/ send it to the pin
    newInst value:newInstOfB.

when this version is executed, the output pin "newInst" will generate the following value:


New struct b action output2.png

Special Types[Bearbeiten]

The following two types are useful as a pin datatype. They are usually not declared as elements in the project tree, but attached to a pin type (i.e. they are usually anonymous).

Template Types[Bearbeiten]

Template types allow for type save declaration of polymorphic operations.

Template types are a kind of placeholder-type, which will be bound to a real type as soon as a pin is connected. Template types are initially unbound. When a pin with an unbound template type is connected to a real typed pin, the template becomes bound and is treated like a pin of the other type. If a bound template typed pin is connected, the usual type compatibility checks are performed against the underlying real type. Template types have a special name, consisting of a "#"-character followed by a number (i.e. "#1", "#2" etc.). Within the set of pins of a single step, all template types with the same name are unified; i.e. bound together.

For example, assume that we have a block which takes an input value and, depending on a control input, sends its input value to one of two outputs. Let's call this a "multiplexer" block. This block's operation is independent of the input type: it could handle any datum. This might lead us to declare the value input and output pins as "Any":

        +-----+
Any --->| MUX |
Bool -->|     |---> Any
        +-----+

However, having an "Any"-output prevents it from being connected to any non-Any input. You will need a lot of type-cast blocks, to downcast from the very general "Any" to whatever type is actually passed. What we really want to say is that the output's type should always be the same as the input's type, and vice versa. I.e. if the input is connected to a Number-typed output, the multiplexer's output should also be of Number-type. If connected to a String-pin, the output should have String-type, and so on.

        +-----+
#1  --->| MUX |
Bool -->|     |---> #1
        +-----+

Exactly that is what a template type does: it states, that whatever type is connected to the input pin, will be the type of the output pin.

Template types can be embedded in a user-defined type: for example, a block which takes three inputs of arbitrary type, and generates a tuple of these values on its output, could be defined as:

       +--------+
#1 --->|        |
#2 --->| Tupler |---> (#1 #2 #3)
#3 --->|        |
       +--------+

If the inputs are connected to [Bool, Bool, String], it will only be possible to connect to blocks which accept tuples like (Bool, Bool, Number) or more general tuples, such as (Bool, Bool, Any), but not to more specific typed tuples, such as (Bool, Bool, Integer).

Please also read the motivation for template types in "Any Type Considered Harmful".

Constraint Template Types[Bearbeiten]

Constraint Template Types are similar to template types, in that they are initially unbound and bind to a concrete type when connected. However, they restrict the set of possible types which can be bound. For example, if some pin expects the type to be a kind of collection, the datatype can be defined as "#1(Collection)". Similar to a regular template type, this initially unbound type will be bound whenever a pin gets connected. Also, other "#1(Collection)" types at the same step are unified with this type.

However, when connecting, binding is only allowed to types which are compatible with a Collection type.

Performer Type[Bearbeiten]

Instances of Performer Type represent a reference to an expecco action. Performer types can also be specific to only allow references to actions which implement a particular interface. Examples:

Performer
Performer ( 'Name of Virtual Action' )
Performer ( interface: UUID-of Virtual Action )

Formal (BNF) Syntax of Type Declarations[Bearbeiten]

Please refer to the "Formal BNF Description of the Expecco Type Syntax" in the datatype editor documentation.

Defining & Loading new Classes (Primary Types)[Bearbeiten]

Knowledgeable users can define their own classes, bundle them in a package, and load them into expecco; both dynamically during a test run or at expecco startup time. The procedure to generate such class libraries is described in the separate document: "Creating new Class Library Packages/en".

   


A description of the underlying Smalltalk class library is found in "Smalltalk/X Online Documentation"
The full online documentation can be found under: Online Documentation



Copyright © 2014-2024 eXept Software AG