9 Validity Range for Better Type Checking

User-defined attributes, variables, local variables (in rules), parameters and return types of rules, user-defined methods, extevent rules and application functions can be enhanced with a range of validity. This has been introduced so that a stricter type checking can take place during the initial loading process enabling errors in the dialog to be detected early on.

Sample use case: restriction of attributes or variables to objects that are derived from a certain model.

The validity range is an add-on to a "value container" e.g. an attribute or a variable (incl. parameters) and does not form a type of its own. A defined range of validity ensures that only settings that fit within this range are allowed – so the "value container" always has a consistent value. The corresponding tests for this happen during the loading and execution of rule code.

Secondly, the range of validity can also limit further access from the "value container". Access in this sense refers to the access to a child, attribute or method. Such access can lead to the return of a value with a derived range of validity.

Example

dialog D

// Basic model with a child

model window MWi {

  statictext StHeader {}

}

// Derived and expanded model

MWi Wi {

  .StHeader {

    integer Width := 10;

  }

  edittext Et {
  }

}

// A second model

model window MWi2 {}

// Entity from the second model

MWi2 Wi2 {

  // Attribute that can only be contained in MWi2-derived objects

  object[MWi2] Ref := Wi; // Syntax error due to violation of validity range

}

// Rule that can only be used on objects derived from MWi

rule void SetHeader(object[MWi] O, string Header) {

  O.StHeader.text := Header;  // O can never be Wi2!

  O.Et.xauto := 0; // Syntax error due to access violation

  O.StHeader.Width := 20; // Syntax error due to access violation

}

on dialog start {

  variable object[MWi] O; // Variable only for MWi-derived objects

  SetHeader(Wi,"First");

  SetHeader(Wi2,"Second"); // Syntax error due to violation of validity range

  O := D.child[2]; // Dynamic violation of the validity range

}

9.1 Restrictions

The following restrictions are currently possible for the data types listed below

Data Type

Validity Value

Value and Access Restrictions,
Derivation of the Validity Range

string

integer value (>0)

No restrictions. As before this validity value serves to represent the string size that is necessary for the generation of trampoline data for COBOL.

object

object

The value can be null or it must be identical with the validity value or rather be derived from it (comparable to :instance_of method).

Access restrictions to user-defined attributes, children and methods that exist on the object given as validity value.

Derivation of the validity range when accessing a child object.

object

class

The value can be null or it must be an object of the corresponding class.

No access restrictions.

A validity range can be defined in the following cases:

  1. Data type of a user-defined attribute
  2. Index data type of a user-defined associative field
  3. Data type of a global variable
  4. Return type of an application function, named rule or user-defined method
  5. Parameter types of application functions, named rules and user-defined methods as well as event rules
  6. Data types of local variables in named rules and user-defined methods as well as event rules

Example

dialog D
model window MWi {}                                 // Following numbers
MWi Wi {                                            // refer to the
record Rec {                                        // previous list
  object[MWi] Ref := Wi;                            // 1)
  boolean AssArray[object[MWi]];                    // 2)
  .AssArray[Wi] := true;
}

variable object[MWi] GlobalVariable := Wi;          // 3)

function object[color] GetBgc(object[MWi] Window);  // 4), 5)

rule object[MWi] GetModel(object[Wi] P) {           // 4), 5)

  return P.model;

}
on Wi extevent 123 (object[MWi] P) {                // 6

  variable object[MWi] V := P;
}

9.2 Access and Value Tests

Static definitions containing validity ranges are always tested during the loading process. This is also true for assignments and accesses in rules that are recognizable as constants. In this sense object paths (e.g. "Wi" in the example below) are to be seen as a "constant" value that can be tested during the loading process.

A dynamic test always takes place in references to value containers with a set validity range or rather in value calls or accesses from within these, and as a result create a Fail and can be intercepted within the parenthesis of a fail() construct. Call parameters and returns of user-defined methods are possibly only dynamically tested. This is due to the validity information not necessarily being available at loading time when using attributes and methods of imported objects.

As a rule predefined "variables" such as this or thisevent are not bound to a validity range. This is also true for return types and parameters of predefined attributes, methods and built-in functions. Therefore the usage should be carried out with "special cautiousness".

Since the validity range has no type of its own, no type checking or type conversion takes place. A "casting", as is used in other programming languages, is not necessary most of the time. This can take place via the intermediate storage on a variable of the data type object.

The access testing only takes into consideration the actual status (objects, existing children and attributes).

The following short example contains correct and incorrect applications and shows the expected time at which the test is carried out (load time or run time).

dialog D

:

model window MWi { child edittext Et{} }
MWi Wi { child pushbutton Pb {} }
model window MWi2 { }
MWi2 Wi2 { checkbox Cb {} }
:
variable object[MWi] I1 := Wi
variable object[MWi2] I2 := Wi2
variable object O;
:
O := I1;  // Validation test not necessary
I1 := O;  // Validation test during loading process
I2 := I1; // Validation test during loading process – VALIDATION ERROR!
I2 := W1; // Validation test during loading process – VALIDATION ERROR!
:

// Valid/allowed access to child object:
print I1.Et;

print O.Pb;

 

// ACCESS ERROR to child object and its test time period:
print I1.Pb;      // Access test during loading process because I1 possesses validity range

print O.Unknown;  // Access test during loading process

print I2.Cb;      // Access test during loading process
print I2.Unknown; // Access test during loading process
print getvalue(I2,. Unknown); // Access test during loading process

9.3 Derivation of the Validity Range

The validity range is derived further when children and attributes are accessed.

This happens when an attribute with a validity range is accessed. This is also true when access to a child object occurs from a value container with a validity range.

dialog D
model window MWi {

  child groupbox Gb {


    child edittext Et {
      rule void Apply() {}

    }
  }

}
MWi Wi {

  object[MWi] Ref := MWi;

  .Gb {

    checkbox Cb { rule void Apply(); }
  }

  rule void Apply() {

    variable object[MWi] This := this;

    This.Gb.Et:Apply();

    This.Gb.Cb:Apply();     // Access error because Cb is not in MWi.Gb

    this.Ref.Gb.Cb:Apply(); // Access error because Cb is not in MWi.Gb

  }

}

9.4 Enhancement of the IDM Syntax

Syntactic changes to the Rule Language are as follows (highlighted red):

General Definitions

<DataType> ::= anyvalue | attribute | boolean | class | enum | event |
        index | integer | method | object | pointer
<ParameterType> ::= { input } { output }
<ReturnType> ::=  void | <DataType>
<Validity> ::= '[' <ValidityValue> ']'
<ValidityValue> ::= <Class> | <Object> | null | <IntegerValue>
<Object> ::= <Identifier> [ .<Identifier> { :'[' <IntegerValue> ']' } ]

Definitions for Named Rules and Methods

<Rule> ::= { export | reexport } { public } { extern } rule
        <ReturnType> { <Validity> } <Identifier>
        '(' { <Parameter> [ , <Parameter> ] } ')' { <ReposId> }
        <OptionalProgramBlock>
<Parameter> ::=
        <DataType> { <Validity> } <Identifier> { := <Value> } <ParameterType>
<OptionalProgramBlock> ::= ';' | <ProgramBlock>

Definitions for External Events

<ExternalEventRule> ::= on <Object> extevent <ConstantValue>
        { '(' { <Parameter> [ , <Parameter> ] } ')' }
        { <RuleCondition> }
        <ProgramBlock>

Definitions for Local Variables

<VariableStatement> ::= { static } variable <Variable> [ ',' <Variable> ] ';'
<Variable> ::= <DataType> { <Validity> } <Identifier> { := <Value> }

Definitions for Global Variables

<GlobalVariable> ::= { export | reexport } { config } <VariableType> <DataType>
        { <Validity> } <Identifier> { <ReposId> } { := <Value> } ';'
<VariableType> ::= constant | variable

Definitions for User-defined Attributes

<AttributeDefinition> ::=
        <DataType> { <Validity> } <Identifier> <AttributeType> ';'
<AttributeType> ::= <ScalarAttribute> | <IndexedAttribute> |
        <AssociativeAttribute> | <ShadowAttribute>
<ScalarAttribute> ::= { := <Value> } ';'
<IndexedAttribute> ::= '[' <IntegerValue> ']' { := <Value> }
<AssociativeAttribute> ::= '[' <DataType> { <Validity> } ']' { := <Value> }
<ShadowAttribute> ::=
        shadows { instance } <Object> <Attribute> { '[' <Index> ']' }

Definitions for Application Functions

<ApplicationFunction> ::= { export | reexport } function { <Language> }
        <ReturnType> { <Validity> } <Identifier>
        '(' { <FunctionParameter> [ , <FunctionParameter> ] } ')'
        { alias <String> } { <ReposId> } <OptionalProgramBlock>
<FunctionParameter> ::= <Parameter> | <RecordParameter>
<RecordParameter> ::= record <Object> { := <Value> } <ParameterType>

9.5 Attributes in Relation to Validity Ranges

The following attributes exist for querying validity ranges dynamically. Further information can be found at the respective attribute descriptions in the “Attribute Reference”.