Value Types

VTScada script is a dynamically typed language (like Python) that allows variables to hold values of any type and that can hold different types during the execution of a script, unlike statically typed languages such as C, C++ and Java that declare the type with the variable and do not allow the type to be changed during program execution.

The VTScada engine always maintains knowledge of the type of the value in a variable, and when comparing values or providing parameters to functions you must ensure that the correct type is used in every instance. (Implicit conversions will be used where possible. For example, the text "42" will be treated as the number 42 if used in an equation and the number 42 can be concatenated into a sentence of text.)

VTScada has 58 different types as listed in the reference section.

VTScada's function library includes TRUE and FALSE, which also serve as constants. DO NOT declare these keywords as constants in your code.

All variables and constants used in a module must be declared, but the intended value type is not part of the declaration. A value may be assigned as part of the declaration. If your code does not assign a value, the VTScada will assign the value, Invalid.

Additionally, there are a number of keywords that can be used in the declaration for variables that need special handling. For example, constants are declared by using the keyword "Constant" before the declared name.

Declaring Constants

CustomControl    { module name }
(
  parm1          { a parameter to the module };
)
[ { start of variable and constant declaration }
  TotalCount                      { variable, defaults to Invalid  };
  CurrentCount = 0                { variable with an initial value };
  Constant #WarningMsg = "Danger" { constant with a text value     };
]

By convention, constants are often declared with a leading "#", but this is only for the sake of identification. The hash mark has no functional significance.

Several commonly used values such as PI are defined in VTScada for your use. See VTScada Constants and Public Variables for a partial list.

Common Value Types

The most common value types are described in the following table. Types that require longer explanations, including arrays, dictionaries and structures, are described in their own topics.

Invalid

An Invalid value is an unknown value that is distinct from all other value types. Invalid guards the system from performing control action based upon erroneous or bad information. Any variable may have an invalid value.

Any calculation that uses an invalid value produces an invalid result (with a few exceptions). Invalid results are not written to output devices. In addition, any graphic statements that contain invalid variables will not produce any output on the screen. In general, any function that uses an invalid value will have no effect and behave as if it did not exist. For functions that have optional parameters, you can use Invalid to specify that the default value should be used. (Typically done only when you wish to specify a value for a later optional parameter.)

Invalid values may result from tags that are not set to any given value, as when VTScada is first starting up. To avoid this situation, programmers use the PickValid() function to provide a default value to expressions until the variable has a valid value.

Invalid values can also result from setting a variable's value in two or more different statements at the same time. In this situation it is uncertain which value is correct, so the variable will be invalid even if both values are the same. This is known as a "double set". An array reference that has one of its subscripts out of range will have an invalid value. Some programmable controllers flag inputs when they are out of range - when these values are read by VTScada, they are declared to be invalid. Division by 0, taking the square root or logarithm of a negative number, and other illegal mathematical operations result in invalid results. An invalid value can even be purposely set as such by using the Invalid function.

Because calculations using invalid values produce invalid results, invalid values can propagate through the system. The setting of a variable to invalid will cause all other variables that depend upon its value either directly or indirectly to become invalid.

Numbers

Numbers are stored internally in the most efficient form for the value provided. All arithmetic is done with the precision of 8-byte IEEE floating point numbers, regardless of the values provided. The legal value range of values is ±10^307, with a precision of approximately 15 decimal places.

Use a minus sign to indicate negative numbers. A plus sign may not be used in a number. The following formats may be used as needed:

Format Example Description
Scientific notation 23.5e5 Place the letter "e" or "E" after the number, followed by the number to use for the power of 10. For example, 1.23E3 is the same as 1230.0 and 1.23E-3 is the same as 0.00123.
Binary notation 0b1100 Binary integers may be specified using the 0b or 0B prefix and up to 32 digits. Each digit is either a 0 or a 1.
Octal notation 014 Octal integers may be specified using a zero prefix and up to 11 digits. Each digit must be in the range 0 to 7.
Hexadecimal format 0xC Hexadecimal integers may be specified using the 0x prefix and up to 8 digits. Each digit must be a number or a letter in the range A to F (upper or lower case).

Text / String

Text values (also called "text buffers" or "strings") are a series of bytes having a specified length. Text values can hold up to approximately 65,500 characters (just less than 64k characters).

A text value may not hold the ASCII 0 value. To store quotation marks in a text variable or constant, use double-quotes:

Quote = """We lived for days on nothing but food and water."" W.C. Fields";

The term, "null string" refers to a text value having zero characters.

Logical Values

(also, "status value" or "Boolean")

A logical value is a true or false value. A false value is indicated by the number 0 or the function, FALSE. A true value is indicated by any valid number other than 0, (typically a 1) or by the function, TRUE.

In general, it is better coding practice to use the functions TRUE and FALSE than 1 and 0.

Pointers

A pointer is a variable that holds a memory address. A pointer references or "points to" a value in a specific memory location.

A variable that points to an address does not have the properties of the value type in that address and cannot be converted to another value type.

A pointer is made to reference the memory address of a variable by using the Address operator "&". For example:

y = 4;    { y holds the value 4 }
ptr = &y; { ptr holds the memory address where that 4 is stored }

Before the data referenced by a pointer can be used, the pointer must be dereferenced using the "*" operator. See: Dereference (pointer dereference)Dereference (pointer dereference).

x = *ptr  { x holds the value 4 }

Object Variables

The object type is used to access public members of a module instance (aka, "object"). Each object variable references exactly one module instance. Every active module call creates a new separate copy, or instance, of that module and its member variables. Each module instance operates independently of the other instances.

By using an object variable and the scope resolution operator (a backslash character or dot according to your purpose), public functions and variables of the module instance may be accessed. For example:

Obj = Driver();
Obj\Read();

The first line starts the Driver module and assigns its return value to Obj. Note the term "return value". This must be supplied by the module being referenced. This is commonly done by using the Self function. Suppose that the Driver module executes the statement:

Return(Self());

Now Obj has the value referencing the copy of the Driver module that was started in the first line of the example above. The second line uses the scope resolution operator (\) with the Obj variable to indicate that the Read module is inside of Driver. When Read starts, it will inherit the member variables of this instance of the Driver module. This means that all the variables of Driver can be used by Read and the values that this Read will see are those copies that are created by the starting the Driver in the first line of the example.

Further statements using the Obj variable may reference other variables and modules within the Driver module. For example, statements such as:

Obj\Read();
Obj\Write();
Output(0, 0, 1, 0, 0, Obj\Error, 15, 0, 0, 0, 0);

may be added to start additional copies of the modules within the Driver module and to access public variables within the module (such as Error).

Object variables may be assigned to other object variables, passed as parameters to modules or used as return values from modules. For example, assume a second object variable called Second has been defined. The statements:

Second = Obj;
Second\Read();

will copy the reference to Driver held in Obj to Second. The last statement here will start a new copy of Read within the same copy of Driver as started in the first line of the examples. If the assignment to Second were changed to:

Second = Driver();

then, Second would be referring to an independent instance of Driver.

The Launch function will also return the launched object value, which you can assign to a variable.

Object variables are often used as a parameter to a module or function, since this provides a way to pass in a way to access other modules.

Object parameters are unique in that they allow access to actions (modules) that can change from one module call to the next. One example might be in a parameterized module which transmits a packet for an I/O driver. Assume this module is called Communicate. Assume Communicate has an object type parameter called TheCaller. This module might handle all of the communication details but not handle the building of the packets. Read and Write modules calling this module might pass an object parameter Self (Self) to this communications module. Each of these calling modules might contain a child module called Build. Within the Communicate module, a call of the form:

TheCaller\Build();

could be used to access the appropriate packet building module which would be different for Read and Write.

An object value will automatically become invalid if the module instance it refers to stops running. This feature can be used to determine when a launched module stops. Also, when the module instance that generated a particular object value is stopped, all object variables containing that object value become invalid, and all descendant module instances of that module are stopped. All scope resolutions to member variable values will return invalid values.

Object variables cannot be compared or printed. Their actual values are meaningless.

Graphic Variables

VTScada uses a set of variable types for graphics that are unique to VTScada. These value types are used by all layered graphics functions, and by the functions that create them. All of these values are valid only so long as the function that created them is active.

You generally do not want to access these values directly. Instead, (and as an example), it is better to pass Path() calls directly into GUIPolygon, etc.

This set of value types includes Point, Vertex, Path, Normalize, Rotate, and Trajectory Variables

Streams

Stream values are a complex type, which refer to a read/write stream. Streams are a very convenient way of performing formatted input and output. Examples of streams include buffer streams attached to text values, file streams attached to disk files, and pipe streams attached to operating system pipes. There are a wide variety of functions related to streams.

Most streams contain a position pointer that indicates where in the stream the next read or write will take place. This pointer is automatically positioned after a read or write to the stream and may be positioned by the Seek function, which also returns the current position in characters from the beginning of the stream.

Streams also offer faster file access than FRead and FWrite, which open and close the file after every access, because a stream leaves a file open. Another advantage of streams is that you can use the Flush function, which is the recommended way to reduce the chance that a write fails to make it to disk before a power loss or PC crash. The Flush function only works with streams, not with files modified using FWrite.

Many functions are available to help you work with streams. See: Stream And Socket functions.

Value Type Conversions

Occasionally, data may be the wrong type. For example, an addition may be performed on two variables, one containing a number, the other containing a text value. VTScada handles this situation by performing a conversion of the unexpected data to the type of data expected, if possible. The type expected may vary according to the operation.

A = 5;
B = "4";
C = A + B;

In this example, two numbers are expected. One variable is already a number and the other variable containing text is converted by VTScada to a number. This is done by reading an ASCII number from the text. If successful, the converted number is used and if unsuccessful, an invalid value is returned. This process is referred to as "type conversion".

Table of VTScada Value and Type Conversions

Convert From Convert To Condition of Original Value Returned Value
Code Pointer Module Valid value Valid value
Module State Valid value Valid value
Module State Statement Valid value Valid value
Object Valid value Valid value
Text Valid value Name of module
Double Long Valid value Valid value
Short Valid value Valid value
Status Valid value Valid value
Text Valid value String representing numeric value
Edit Block Stream May only be used in SRead with % option, or in StrLen Valid value
Long Double Valid value Valid value
Short Valid value Valid value
Status Valid value Valid value
Text Valid value String representing numeric value
Module Text Valid value Name of module
Module State Module Valid value Valid value
Text Valid value Name of module
Module State Statement Module Valid value Valid value
Module State Valid value Valid value
Text Valid value Name of module
Normalize Double Valid value The scaled value
Long In the range of -2 147 483 648 to 2 147 483 647 The value
Short In the range of -32 767 to 32 767 The value
Outside of range Invalid
Status 0 0 (false)
Non-0 1 (true)
Text Valid value String representing scaled value
Object Module State Valid value Module and state in which that object exists
Statement Valid value Module state and statement number that object is executing
Text Valid value Name of the module of which that object is an instance
Short Double Valid value Valid value
Long Valid value Valid value
Status Valid value Valid value
Text Valid value String representing numeric value
Status Double Unconnected socket 1
Connected socket Invalid
Long Unconnected socket 1
Connected socket Invalid
Short Unconnected socket 1
Connected socket Invalid
Status Unconnected socket 1
Connected socket Invalid
Text Unconnected socket "1"
Connected socket String of stream contents
Tag Double Valid value The scaled value
Long In the range of -2 147 483 648 to 2 147 483 647 The value
Outside the range Invalid
Short In the range of -32 767 to 32 767 The value
Outside the range Invalid
Status 0 0 (false)
Non-0 1 (true)
Text Valid value String representing scaled value
Text Double Number string Number in string
Long Number string Number in string
Short Number string Number in string
Status Non-0 number string 0 (false)
0 number string 1 (true)
Variable Module Module variable The module in which the module variable resides
Text Valid value Name of variable

Experiment with Variables

Preparation: Create a new script application, but do not run it immediately.

  1. Open the application's AppRoot.SRC file using a text editor.
  2. Edit the Graphics module as follows:
<
{============================= System\Graphics ===============}
{ This module handles all of the graphics for the application }
{=============================================================}
Graphics
( )
[ 
  X = 2   { one numeric value to display                      };
  Y = 2   { another numeric value.                            };
]
Main [
   ZText(100, 100, X, 15, 0);
   ZText(100, 120, Y, 15, 0);
   ZText(100, 140, X + Y, 15, 0);
]
{ End of System\Graphics }
>
  1. Compile (Import file changes) and run the application.
  2. Try the following values for X and Y. You will need to stop the application, import file changes and restart between each change. Try experimenting with additional types.
  X = 2;
  Y = "2";
  X = "2";
  Y = "2";
  X = 2.01;
  Y = 2;
  X = "two";
  Y = "two";
  X;
  Y = 2;

If X is "2" and Y is "2" the + operator will perform string concatenation and return "22". If you are uncertain about what value type will be passed to your function, it is worth using the Cast() function to try to force it to the correct type.