2.2. Symbols, Variables, and Evaluation

Complementing their dynamic environment and event-driven behavior, DataHub scripts have a slightly different approach to symbols and variables compared to other programming languages like C or Java.

2.2.1. Symbols and Variables

One of the fundamental units of Gamma, the DataHub scripting language, is a symbol. Symbols are made up of one or more alphanumeric characters, as well as "_". A symbol gets created whenever a unique group of characters appears in a script for the first time; from that point on the symbol is a unique object in Gamma. When first created, symbols are variables. The value of a variable can be assigned and reassigned at any point in the script. Variables that are not assigned a value have a default value of _undefined_.

Variable Scoping and Dynamic Typing

Similar to many programming languages, variables in Gamma can be local or global in scope. At the same time, to provide maximum flexibility, variables in Gamma are dynamically typed. Each time a variable is assigned a value, Gamma assigns or reassigns the type for that variable, based on the new value. This facilitates rapid development and eliminates the need to type or even declare all variables before they are used. Of course, good programming principles must still be observed when writing scripts to ensure that the variables are of the correct type for the circumstances.

2.2.2. The Read/Evaluate Cycle

When a DataHub script is run, Gamma first parses the script, reading and evaluating each statement in turn. For functions or methods, first each argument gets evaluated, and then each statement gets evaluated. Variables get evaluated to their value. Literals like numbers, strings, arrays, and so on get evaluated to themselves. This read/evaluation cycle iterates through the progam on a recursive basis until the entire code gets read and evaluated. When the process is complete, Gamma executes the code.

Preventing Evaluation

Sometimes you might not want Gamma to evaluate a statement or variable when it parses the code. For example, when attaching an event handler to the .OnChange method, you don't want the code of the event handler to run until the event actually occurs. To prevent evaluation of a statement or variable, you can use the # character, a Gamma quote operator. Putting the # quote operator in front of any Gamma expression turns it into a literal, causing it to be evaluated to itself, as if it were a number or a string.

Example 1

This example shows an interactive session with Gamma in the Script Log. The --> symbols indicate where the user has input an expression, and the next line shows what Gamma has returned as the result of evaluation.

  1. First we assign a value of 5 to the variable myvar:
    --> myvar = 5;
    5
    Gamma returns the value of myvar, which is 5.
  2. Then we pass the variable myvar, to Gamma:
    --> myvar;
    5
    Gamma evaluates it and returns the value, 5.
  3. Now we pass the variable myvar, to Gamma, this time quoted using the # symbol.
    --> #myvar;
    myvar
    And now Gamma evaluates myvar as its literal name, myvar, The expression itself has passed through the evaluator intact, without being evaluated.

Partial Evaluation

In some circumstances you might need Gamma to evaluate part of your statement, but not all of it. For this, there are two more quote operators. The ` quote operator indicates that this stament should not be evaluated, except for those places marked by the @ quote operator.

Example 2

In this example, we use the Gamma list function to illustrate how partial evaluation works. The list function creates a space-separated list out of its arguments

  1. First, let's define our variables and demonstrate the list function.
    --> myvar = 5;
    5
    --> yourvar = 9;
    9
    --> list(myvar, yourvar);
    (5 9)
    Gamma first evaluates the arguments of the list function to 5 and 9, then applies the list function and puts them into a list: (5 9).
  2. Now let's use the # quote operator:
    --> list(#myvar, #yourvar);
    (myvar yourvar)
    --> #list(myvar, yourvar);
    (list myvar yourvar)
    First we quoted the individual arguments, then the entire expression. Do you see the difference in the result? The second return value, (list myvar yourvar) illustrates the internal syntax of Gamma, which is Lisp. Lisp functions are always of this syntax: (function_name arg1 arg2 ...).
  3. Now, suppose we want to partially evaluate the expression. First, let's use the ` quote operator alone:
    --> `list(myvar, yourvar);
    (list myvar yourvar)
    This gives the same result as the # operator, above. Now let's use the ` operator with the @ to allow partial evaluation, like this:
    --> `list(@myvar, @yourvar);
    (list 5 9)
    --> `list(myvar, @yourvar);
    (list myvar 9)
    In the first line, we prvented the evaluation of the list function itself, but allowed Gamma to evaluate both of its arguments. In the second line, we allowed the evaluation of only one argument.
  4. Here are a few more examples, incorporating the Gamma string function, which turns an expression into a string:
    --> string(list(myvar, yourvar));
    "(5 9)"
    --> string(#list(myvar, yourvar));
    "(list myvar yourvar)"
    --> string(`list(@myvar, @yourvar));
    "(list 5 9)"
    --> `string(list(@myvar, @yourvar));
    (string (list 5 9))
    --> `string(@(list(myvar, yourvar)));
    (string (5 9))
    In each case, the ` quote operator prevents the evaluation of the overall expression, while the @ operator allows the evaluation of the sub-expression that immediately follows it.
  5. How does this apply to events in a typical DataHub script? Here is an example, using the .OnChange method in a class named Example with a method called MethodA:
    [Note]

    This the most important example, because this syntax is commonly used with the .OnChange method for handling events.

    class Example Application
    {
    ...
    }
    
    method Example.MethodA (x, y)
    {
    ...
    }
    
    method Example.constructor ()
    {
         .OnChange (#V1, `(@self).MethodA (#V1, #V2));
    }
    In this example, we want to apply MethodA of our Example class to the values of variable V1 and V2 at the exact moment when V1 changes its value. To do this we protect V1 and V2 from evaluation, using the # quote operator. We also do not want to evaluate the MethodA method, but we do have to evaluate the key variable indicating the class (self). So we use the ` operator to prevent the evaluation of the method, and the @ operator to allow the key variable self to be evaluated. This way Gamma knows which class the .MethodA belongs to.

Forcing Evaluation

In some cases you might need to force Gamma to evaluate an expression. For this, you can use the Gamma eval function. For example:

--> myvar = 5;
5
--> #myvar;
myvar
--> eval(#myvar);
5