4 Data Variables and Data handling

User defined Types

The Eloquence language supports user defined data types. A user defined data type consists of a list of variables, called member variables. When a type is derived it inherits all properties (in this case, the member variables) of the base type. When you derive a type from a base type, you can use the derived type to call functions or subprograms which accept the base type.

Type definition

Type definitions are enclosed in the TYPE .. END TYPE keywords. All variable declarations between will be part of the new data type. When the EXTENDS keyword is present, the new data type is derived from the given base type.

Syntax:

TYPE type_name [EXTENDS base_type_name]

.

.

.

END TYPE

They are different to the string and numeric variable types known in Eloquence, because they have to be defined before they can be used. The standard types are internally defined. The type definition can be compared with a design, as example for a vehicle. With the type definition, it is defined on which parts the vehicle consists. This vehicle has an engine_type, a number of wheels, a colour and so on.

Example:

TYPE Tvehicle
   DIM Engine$[1]
   INTEGER Wheels
   DIM Colour$[20]
   .
   .
   .
END TYPE
In a TYPE constructions only DIM, INTEGER, DINTEGER, SHORT, REAL and Comment lines are allowed.

Exporting Types

Type definitions can be "exported" to lower calling levels. This is done with the new EXPORT TYPE keyword:

TYPE Tname [EXTENDS Tbase]

EXPORT TYPE Tname [EXTENDS Tbase]

IN DATA SET ... DEFINE TYPE Tname [EXTENDS Tbase]

IN DATA SET ... EXPORT TYPE Tname [EXTENDS Tbase]

By default a type definition is local to the current segment. This is also true for types defined in the main segment. Therefore, types used in COM statements must be "exported" in order to be usable in a subprogram. Otherwise a runtime error message will be issued.

NOTE: This is a behaviour change.Initially, all types defined in the main segement were global.

Type scope

A type definition is local by default and is only visible within the local segment. When a type is "exported" it becomes visible to subsequently called levels. When a segment defines a type with a name which has been exported from a higher level, it will temporarily replace the exported type in the current function or subroutine.

When a segment defines and EXPORTs a type with a name which has been exported from a higher level, the newly exported type permanently replaces the former type for all subsequently called lower level segments. If the type which is most recently defined is not EXPORTed, the previously exported type again becomes available to lower called segments.

Derived Types

It is very helpful to create types, which are a superset of an existing type. They are derived from an existing type, called Base-Type. It inherits all the members of the Base-Type and have individuell members added.

In the above example derived types as car, track or motorcycle from the Base-Type Tvehicle are possible. All of them have inherited the members of Tvehicle and some individuell members.

Example:

TYPE Car EXTENDS Tvehicle
   DIM Engine_type$[30]
   INTEGER Power, Persons
END TYPE
A new type can be derived from car again and all members are inherited, the one from the Base-Type Vehicle and the members from car.

Please note, that a base type can be defined after a derived type. It must be defined however before a derived type is instantiated.

Nested types are not supported, this means that it is not possible to define a user defined type as a member of a user defined type.

Type instantiation

Since a type definition is merely a blueprint rather than a real object, it must be instantiated before it can be used. This can either be done before execution by using the COM and DIM statements or at runtime with the NEW statement.

DIM and COM statements:

   COM Instance_name:Type_name
   COM Instance_name AS Type_name
   DIM Instance_name:Type_name
   DIM Instance_name AS Type_name
The NEW statement:

   NEW Instance_name:Type_name
   NEW Instance_name AS Type_name
The Instance_name is the variable name and the Type_name is the name of the data type. The instance name and data type name are either separated by a colon or the keyword AS.

Example

DIM Vehicle AS Tvehicle
or 
DIM Vehicle:Tvehicle
In addition, the NEW STRUCT statement can be used to create a new, identical copy of the referenced object.

NEW STRUCT Instance_name=Instance_Name

The example below creates a new object named Clone. It will be an exact copy of the referenced object Entry.

DIM Entry:Tphone

Entry.Name$="Joe Sample"

Entry.Phone$="(202) 243 1440"

NEW STRUCT Clone=Entry

Using member variables

Member variables can be used like any other variable. A member variable is specified by giving the variable name (instance name) and the name of the member variable, separated by a dot.

Vehicle.colour$="red"

PRINT Vehicle.colour$

In addition to accessing single variables, you can specify the whole object at once. The example below prints all member variables of Entry.

PRINT STRUCT Vehicle

The STRUCT statement can also be used to copy the value of an object:

STRUCT A=B

When copying an object to another, both must be compatible.

The STRUCT keyword

The STRUCT keyword can be used with some statements to operate on the whole object instead of

a single member variable. This is similar to the Array(*) notation in Eloquence which causes

an operation on the whole array instead of a single element.

The following statements can be used with STRUCT:

Runtime type identification

The TYPEOF$ function can be used to identify an instance.

X$=TYPEOF$(instance_name)

This returns the type name of the given instance.

The IS A operator can be used to categorize an instance.

IF instance_name IS A type_name THEN ...

If the instance is either of the specified type or derived from it, the IS A operator returns nonzero.

For example:

   TYPE Tbase
      INTEGER A
   END TYPE
   TYPE Tderived EXTENDS Tbase
      INTEGER Q
   END TYPE
!
   DIM Derived:Tderived,Base:Tbase
   DISP "Base is of type ";TYPEOF$(Base)
   DISP "Inst is of type ";TYPEOF$(Derived)
   DISP "Base    is a Tbase    =";Base IS A Tbase
   DISP "Base    is a Tderived =";Base IS A Tderived
   DISP "Derived is a Tbase    =";Derived IS A Tbase
   DISP "Derived is a Tderived =";Derived IS A Tderived
   STOP

Data base integration

The user defined type concept is designed to operate with the Eloquence data base. The IN DATA SET ... DEFINE TYPE statement can be used to define data types from the data base schema at runtime, the PACKFMT, IN DATA SET LIST and IN DATA SET ... USE have been enhanced to support user defined data types. For more information about this statement, see chapter , The IN DATA SET Statement, in the Data Base Manual.

For example:

DBOPEN(Db$,"",1,S(*))
   ...
   IN DATA SET "CUSTOMER" DEFINE TYPE Tcust
   NEW Cust:Tcust
   IN DATA SET "CUSTOMER" USE STRUCT Cust
   ...
   DBGET(Db$,"CUSTOMER",7,S(*),"@",Buf$,Key$)
   ...
Of course, types can also be defined statically in your program:

TYPE Tcust

DIM No$[6]

DIM Name$[30]

...

END TYPE

DIM Cust:Tcust

!

DBOPEN(Db$,"",1,S(*))

...

IN DATA SET "CUSTOMER" USE STRUCT Cust

...

DBGET(Db$,"CUSTOMER",7,S(*),"@",Buf$,Key$)

...

Error Messages

The following runtime errors are used with types:

ERRN Description

13 Array dimensions not specified or undefined type

900 Undefined base type

901 Nested types are not supported

902 Statement not allowed in type definition

903 Illegal or incomplete type definition

905 No such member variable.

This runtime error occurs, whenever a specified member variable

cannot be found.

Example program

This section provides a more useful example. It demonstrates, how user defined types can be used to enhance or replace the current usage of the COMmon block.

! common block
TYPE Tglobal
  INTEGER Iv
  DIM Xv$[18]
  INTEGER A(1:2)
END TYPE
!
COM Global:Tglobal
READ STRUCT Global
DATA 123,"COMMON",1,2
!
PRINT "Global.Iv=";Global.Iv
PRINT "Global.Xv$=";Global.Xv$
PRINT "Global.A(*)=";Global.A(1);Global.A(2)
CALL Sub
STOP
!
SUB Sub
   COM Global:Tglobal
   PRINT "Global.Iv=";Global.Iv
   PRINT "Global.Xv$=";Global.Xv$
   PRINT "Global.A(*)=";Global.A(1);Global.A(2)
SUBEND

Eloquence Language Manual - 19 DEC 2002