Variables

Variables are names that are bound to data values (in the case of primitive types) or the location of data values (in the case of reference types). Variables are declared by specifying a type, a name, and optionally, an initial value. With the exception of the string type, once declared, new values can be computed and assigned to variables as needed. Strings are immutable and variable assignment causes a new string value to be created and bound to the string variable.

Variable declarations

Before a variable can be referenced in a program, it must be declared. The declaration gives the variable a unique name, a type and, optionally, an initial value. See also Assignments.

A variable declaration statement can appear anywhere in a block. Variables declared in a block are in scope in that block and can be used in statements that follow the declaration.

Example:

location rect := location(1.0, 1.0, 5.0, 5.0);
integer i;
boolean c := true, d := false;
sequence <integer> s := [1, 3, 5, 7, 11, 13, 17];
string s1 := "abcdefghijklmnopqrstuvwxyz";

Variable scope

The parts of a program in which a particular variable can be referenced (that is, its value used or a new value assigned) is called the scope of the variable. In EPL, variables can have scopes that include:

  • All monitors. These are global variables that are part of EPL, also called predefined variables.
  • The monitor within which they are declared.
  • The action within which they are declared.
  • The block within which they are declared.
  • The event within which they are declared.
  • The custom aggregate function in which they are declared.
  • The stream query within which they are identified.

Regardless of the scope of a variable, it cannot be referenced in statements or expressions until after it has been declared or specified as an item identifier in a stream query. Further, variables scoped to actions or blocks cannot be referenced until a value has been assigned.

Within a scope at a particular level, variables declared at that level must have unique names. They can, however, have names that are the same as variables defined at an outer scope and in that case the variables declared at the inner level hide or mask the ones defined at the outer level(s) until the end of their scope.

Predefined variable scope

Predefined variables are defined by the correlator and are accessible in all monitors. See Provided variables.

Monitor scope

A variable that is defined in a monitor is visible and can be referenced in all parts of the monitor. Such variables are also called global variables.

Action scope

A variable that is declared in an action (also called a local variable) can only be referenced within the action. A variable that is a formal parameter of an action can only be referenced within the action. If a local variable declared in an action has the same name as a global variable declared at the monitor level, the local variable hides the global variable until the end of the action.

Block scope

A variable that is declared within a block can only be referenced within the block. A block is one or more statements enclosed within curly braces (the characters { and }). If a local variable declared in a block has the same name as a global variable declared at the monitor level, or a local variable declared at the action level, the block’s local variable hides the global variable or the action’s variable, or both if all three have the same name, until the end of the block (the closing }).

Event action scope

The fields of an event are part of the event declaration. An event field’s scope depends on where it is declared. When an event also includes action definitions, the statements in the action can reference the event’s fields as simple identifiers. From the point of view of an event’s action, the fields can be said to be scoped to the event.

Custom aggregate function scope

A variable that is declared in a custom aggregate function (also called a local variable) can only be referenced within the custom aggregate function. If a local variable declared in a custom aggregate function has the same name as a global variable declared at the monitor level, the local variable hides the global variable until the end of the custom aggregate function.

Provided variables

The EPL execution environment provides several variables. You can use these variables in the same way as variables you declare yourself, except that you cannot assign values to them. Instead, the correlator automatically assigns values to these variables.

currentTime

The currentTime variable is a read-only float global variable that contains a timestamp value with the current time and date as read from the correlator’s clock. Timestamps are encoded as the number of seconds and fractional seconds elapsed since midnight, January 1, 1970 UTC and do not have a time zone associated with them.

The current time is the time indicated by the most recent clock tick. Use the currentTime variable to obtain the current time. The value of the currentTime variable is always changing to reflect the correlator’s current time.

If you have multiple contexts, it is possible for the current time to be different in different contexts. A particular context might be doing so much processing that it cannot keep up with the time ticks on its queue. In other words, if contexts are mostly idle, then they would all have the same current time.

In a context, the current time is never the same as the current system time. In most circumstances it is a few milliseconds behind the system time. This difference increases when the context’s input queue grows.

When a listener executes an action, it executes the entire action before the correlator starts to process another event. Consequently, while the listener is executing an action, time and the value of the currentTime variable do not change. Consider the following code snippet,

float a;
action checkTime() {
   a := currentTime;
}
//... Lots of additional code
// A listener calls the following action some time later
action logTime() {
   log a.toString(); // The time when checkTime was called
   log currentTime.toString(); // The time now
}

In this code, an event listener sets float variable a to the value of currentTime, which is the time indicated by the most recent clock tick. Some time later, a different event listener logs the value of a and the value of currentTime. The values logged might not be the same. This is because the first use of currentTime might return a value that is different from the second use of currentTime. If the two event listeners have processed the same event, the logged values are the same. If the two event listeners have processed different events, the logged values are different.

The correlator maintains a clock that advances at a fixed interval (default) of 0.1 seconds. The clock does not advance while an event is being processed.

Event timestamps

The correlator defines an arrival timestamp for every event it receives. The arrival time value is set from the main context’s clock when an event is received by the correlator, just before it is placed on the input queue of each public context.

You can access the arrival timestamp by calling the event’s inbuilt getTime() method (see the description of event in the API reference for EPL (ApamaDoc). After the correlator creates an event or after you coassign an event, the getTime() method returns the time in the context when the event was created or coassigned. An event’s arrival timestamp has the same scope as the event itself.

self

The predefined variable self is an event reference that can be used to refer to an event instance within the event’s definition.

Within an event action body, you can use the self variable to refer an event instance of that event type. In other words, the scope of self is each action body in the event definition. For example:

event Circle
{
   float radius;

   action circumference() returns float
   {
      return (2.0 * float.PI * self.radius);
   }

   action area() returns float
   {
      // Note the use of "radius" is equivalent to
      // "self.radius" in the statement below.
      return (float.PI * radius * self.radius);
   }
}

Note:

You cannot use the self variable in a static action.

Specifying named constant values

A constant is a named literal and its value cannot be changed during runtime. It resembles a variable declaration with constant before it.

You can declare an identifier for a constant value in an event type definition or in a monitor. A constant appears in memory once. Spawning a monitor that contains a constant does not make copies of the constant.

The type of a constant must be boolean, decimal, float, integer, or string.

The name you assign to a constant must be unique within the event type or monitor that contains the constant definition.

The literal that you assign to the constant must be the specified type.

When you define a constant event field, you can refer to that constant from outside the event. Qualify the name of the constant with the event name, for example, MyEvent.myConstant.

You cannot declare a constant in an action, directly in a package, or in a custom aggregate function.

See also Specifying named constant values.