When you create an object through an operator expression, or through other means such as a literal expression or a constructor expression, you lose access to that object for the rest of your program unless you use it as an operation argument, assign it to an attribute, or assign it to a variable. You've already learned about operations and attributes, so this chapter goes on to show you how to work with variables. You'll find detailed information about the syntax of declaration and assignment. You'll also get a close look at specifying a variable's type and determining the scope of a variable.
Operator | Description |
- | Unary minus operator. Use it before a value to negate that value. |
+ | Addition operator. Use it between two values to add them together. |
- | Subtraction operator. Use it between two values to subtract the second value from the first. |
* | Multiplication operator. Use it between two values to multiply them together. |
/ | Division operator. Use it between two values to divide the first value by the second value. |
Some examples of operator expressions using arithmetic operators:
-872 6.43 + 9 92 - 3 25 * 4 7 / 3.5These expressions respectively evaluate to these single values:
-872 15.43 89 100 2.0.Note that the type of result you get using an arithmetic operator depends on the types of the number you use. If you use two real numbers, the result is a real number. If you use a real number and an integer, the result is a real number. And if you use two integers, the result is an integer--unless the operator is the division operator, which always results in a real number, even if it operates on two integers.
Ordered
(described in the last chapter). Remember that one ordered object is before, equal to, or after another object--or the two objects are unordered if they can't be compared.
Comparison operator expressions evaluate to a boolean, so they are either true
or false
.
Operator | Description |
< | Less-than operator. Use it between two values to compare the first value to the second value. If the first value is before (less than) the second value, the expression evaluates to true. If the first value is equal to, after (greater than), or unordered with respect to to the second value, the expression evaluates to false. |
> | Greater-than operator. Use it between two values to compare the first value to the second value. If the first value is after (greater than the second value, the expression evaluates to true. If the first value is equal to, before, or unordered with respect to the second value, the expression evaluates to false. |
<= | Less-than-or-equal-to operator. Use it between two values to compare the first value to the second value. If the first value is before, equal to, or unordered with respect to the second value, the expression evaluates to true. If the first value is after the second value, the expression evaluates to false. |
>= | Greater-than-or-equal-to operator. Use it between two values to compare the first value to the second value. If the first value is after, equal to, or unordered with respect to the second value, the expression evaluates to true. If the first value is before the second value, the expression evaluates to false. |
== | Equal-to operator. Use it between two values to compare the first value to the second value. If the two values are equal, the expression evaluates to true. If the two values aren't equal, the expression evaluates to false. This operator isn't limited to ordered objects; it can check equality (as defined by the operation isEqual) between unordered objects. (Note that Telescript reserves a single equal sign (=) for assignments; you must use double equal signs as the equal-to operator.) |
!= | Does-not-equal operator. Use it between two values to compare the first value to the second value. If the two values are not equal, the expression evaluates to true. If the two values are equal, the expression evaluates to false. This operator, like the equal-to operator, isn't limited to ordered objects. |
Some examples of operator expressions using comparison operators:
3 < 8 3 > 8 3.14 <= 3.14 9 >= -5 9 == -5 9 != -5These examples respectively evaluate to these single values:
true false true true false true
Operator | Description |
is | Type operator. Use it between an object and a type (typically the name of a class) to see if the object is a member of the class. The expression evaluates to true if the object is a member of the class (that is, an instance of the class or any of its subclasses), or to false if the object is not a member of the class. If you follow the class name with an exclamation point (!), this operator returns true if the object is an instance of the class and false if the object isn't an instance of the class. |
An example of an operator expression using the is operator:
9 is NumberThis expression checks to see if 9 is a member of
Number
. It is, so it returns true
.Another example:
9 is Number!This expression checks to see if 9 is an instance of
Number
. It's not (it's an instance of Integer
), so the expression returns false
.true
or false
). They evaluate to a boolean object.
Operator | Description |
! | Not operator. Use it before a boolean value to perform the logical operation "not" on the value. !true evaluates to false; !false evaluates to true. |
&& | And operator. Use it between two boolean values to perform the logical operation "and" on the values. true && true evaluates to true; if either or both of the values are false, the expression evaluates to false. |
|| | Or operator. Use it between two boolean values to perform the logical operation "or" on the values. false || false evaluates to false; if either or both of the values are true, the expression evaluates to true. |
Some examples of operator expressions using Boolean operators:
!(5 == 5) 4 < 5 && 5 < 2 4 < 5 || 5 < 2The first expression evaluates to
false
because the expression 5 == 5
evaluates to true
, which is negated.
The second expression evaluates to false
because the expression on the left side of the operator evaluates to true
, but the expression on the right side evaluates to false
.
The third expression evaluates to true
because the expression on the left side of the operator evaluates to true
, and only one expression needs to be true
for a true evaluation.
The expressions on the right side of the logical operator &&
or ||
are not evaluated if the expression on the left side is all that's needed to determine the result. In other words, if the left expression of &&
is false
, the full expression must be false
so the right expression isn't evaluated. And if the left expression of ||
is true
, the full expression must be true
so the right expression isn't evaluated. This is important to remember if you've called an operation in the right expression; it won't be called in some cases.
Priority | Operations |
1 | ! - (prefix) |
2 | * / |
3 | + - (infix) |
4 | is |
5 | < > <= >= |
6 | == != |
7 | && || |
Operators with the highest priority within an expression are applied before operators with lower priorities. Once these operators are applied, operators of the next highest priority are applied. This continues until all the operators are applied.
To see how this works, consider the following expression:
6 + -8 * 2 == 12 / 2 - 10This expression evaluates to
false
. To see why, look at the order in which the operators are evaluated. The highest priority operator is the unary minus before the eight which makes the eight a negative eight. The operators next in priority are the multiplication and division operators. Once they're resolved, the expression yields:
6 + -16 == 6 - 10The next highest priority operators are the addition and subtraction operators which, when resolved, yield:
-10 == -4The lowest priority operator is the equal-to operator. Negative 10 does not equal negative 4, so the expression's final value is
false
.To see how this works, consider the following expression:
-((2+6)/2)It evaluates to negative 4 because the addition operator is applied first, followed by the division operator, followed by the unary minus operator. Without the parentheses,
-2+6/2the expression evaluates to 1: the unary-minus operator is applied first followed by the division operator followed by the plus operator.
An important note: Telescript doesn't specify the application order of equal-priority operators within parentheses. This means that you can't safely assume that one operator expression will be evaluated before another operator expression of equal priority--unless you enclose one of those operator expressions in parentheses.
A variable is, simply put, an identifier that refers to an object. It's supported by Telescript's variable mechanism, which allows you--within a block of code--to first declare a variable and then assign a value to the variable. When you declare a variable, you create a unique identifier and specify the type of the objects to which the identifier can refer. You may then assign a value (an object) to the variable--as long as the value is a member of the specified type. Once assigned, you can reassign a new value to the variable any time, replacing the old value. You can use the variable within an expression; the expression is evaluated using the variable's current value.
Let's take a closer look at the mechanism that supports variables.
C variables are declared to be one type or another because--among other things--the amount of memory allocated for the variable is important. If you declare a variable to be a type that requires only a single byte of memory (a character, for example) and then write a value that requires four bytes (a long integer, for example), only a single byte will be stored (if the compiler lets it pass). Chances are good that the value of the variable won't be at all what you intended it to be.
In Telescript, a variable does not have an address of a specific piece of memory; it has a reference to a value, which is an object that may be located anywhere in memory. The value object's location is of no concern to the programmer. You declare a type for a variable not to allocate memory, but to assure that you know what type of object you're working with when you use the object in later statements. If you assign a new value to the variable, the Telescript engine simply changes the variable's reference from the old value to the new value.
The power of the Telescript variable is that it can handle simple values in assignments such as cost = 3.45
and sum = cost + tax
, and it can also handle more complex objects such as keeping track of and working with members of the classes Place
, Agent
, and other similar objects. In these cases a single variable refers to a complex value that contains many objects within.
<<<Note: The current version of the Telescript engine ignores type in variable assignment. If the compiler misses a conflict of type on variable assignment, the engine will let the assignment pass. So--for example--an Integer variable may refer to a real number without any squawks.>>>
sahara
and assign to it an object of the custom class RainRecord
(an example custom class that tallies rainfall):
sahara = RainRecord();The right side of this statement creates a new instance of the class
RainRecord
for assignment to the variable. Statements following the assignment can then use the variable to work on the new object. For example, you may want to call the addTally
operation on the object to add the day's rainfall totals. You do so by using the identifier, which refers to the RainRecord
object and so designates the operation's responder:
sahara.addTally(.01);You can assign a new value to a variable at any point within a block. Any statements that use the variable after reassignment work with the variable's new value. For example, if you assign a new RainRecord object to the variable
sahara
, all subsequent operation calls on sahara
are called on the new object, not on the previously assigned object.(When an object is "dropped"--that is, it's no longer referred to--it eventually disappears. The Telescript engine's garbage-collection mechanism automatically deletes any unreferred-to objects from memory--a topic discussed in more advanced chapters of this book.)
Consider the sahara
variable created in the previous example. When the variable is declared within a block, it's stored with that block as long as the block executes. Any statements that follow the declaration can use the variable. When the block finishes execution, the identifier sahara
is dropped, as is the RainRecord object to which the variable refers. Because the identifier and the RainRecord object aren't processes, and because they aren't referred to by anything outside of the block, these two objects are deleted by the Telescript engine's garbage-collection mechanism, and can't be used outside of the block.
Remember that the scope of a variable is the block within which it's declared. If you try to declare the same variable a second time within that block, the compiler will object.
Telescript declarations come in two varieties: explicit and implicit.
temperature
, and specifies a type of Real. (This limits it to real-number values.)
temperature: Real;The declaration starts with an identifier and is followed by a colon. The text of the identifier must follow all the rules set forth in the last chapter for instances of the Identifier class. On the right side of the colon is the name of a single type. The declaration ends in a semicolon.
temperature, speed, volume: Real;creates three variables all declared as type
Real
: temperature
, speed
, and volume
.
temperature: Real = 102 - 3.4;It creates the variable
temperature
, restricts its value to Real objects, and assigns it a value of 98.6
. 98.6
is a real-number value that is the result of the operator expression 102-3.4
. The variable temperature
now refers to the object 98.6
.You may only assign a single object in a declaration. You may, however, assign that single object to more than one variable if you use more than one identifier in the declaration as shown here:
temperature, speed, volume: Real = 98.6;All three declared variables are assigned the value of
98.6
. Note that all three variables refer to the same object--the real number 98.6
.
temperature: = 98.6;looks like a simple assignment statement with one small difference--the colon (
:
) before the equal sign (=
) means that it's really a declaration with an assignment. That is, it declares the variable temperature
, limits it to Real objects (the type of the value 98.6
), and then assigns it a value of 98.6
.In a declaration with implicit type, you use identifiers and objects just as you do in the declarations with explicit type. That is, you can use multiple identifiers if you wish such as
temperature, speed, volume: = 98.6;and you're limited to a single object for assignment. In this example,
98.6
is assigned to all three variables.
A declaration with implicit type is a convenient form of declaration that allows you to declare a variable without knowing exactly what type you need to specify. For example, this declaration of the variable price
price: = estimateassigns the object of the variable
estimate
to the variable price
. That is, it refers price
to the same object that estimate
refers to. If estimate
was declared earlier to be a real number, price
is declared as a Real variable. If estimate
was declared as an integer, price
is declared as an Integer variable.Explicit type declarations, on the other hand, allow you to specify a superclass of the value you assign, something you can't do with implicit type. For example, in this declaration
price: Number = 98.6;
price
is restricted to the class Number
, which is a superclass of both Integer
and Real
. You can assign 98.6
to the variable because the real number 98.6
is an object that is a member of the Number class--that is, it's an instance of Real
, and Real
is a subclass of Number
.
Note that one drawback to using implicit type in an assignment is that it makes your code a little harder to read--you can't easily tell what type is specified for each variable. A second drawback is that if you get in the habit of using ": =
" in declaration assignment, you may accidentally use it for a simple assignment and declare a new variable when you meant to use an existing variable.
When you explicitly specify a type, you use a class expression--a text string that gives the class name. If the class you specify is defined by a class family (such as List
, for example), you must supply actuals in square braces ([]
) following the class family name: List[Integer, Equal]
, for example. (Don't worry about class families for now; you'll read more details about families, formals, and actuals in Chapter 9.) The class you specify can be any of the built-in Telescript classes listed at the back of this book, or any custom classes that are in use when you declare the variable.
Because a variable's type may allow reference to objects of the type's subclasses, it's important to consider inheritance when you specify type. A good place to start is the beginning of Part Four of the Telescript Language Reference, which shows a class tree of built-in Telescript classes. Notice that if you specify the type Object, the variable you declare can refer to any object because Object is the root class of all other classes (except mix-ins, of course, which can't be instantiated anyway).
Once a variable is declared, you must be careful that you only assign it values that satisfy its type. If you try to assign a value that doesn't satisfy the type, the compiler won't accept the assignment.
!
). Consider these two variable declarations for example:
route: Map; locations: Map!The first declaration specifies the class
Map
as its type. An instance of Map
will satisfy this type, as will instances of LocalMap
or WorldMap
(assuming LocalMap
and WorldMap
are subclasses of Map
). The second declaration specifies Map!
as its type. Only an instance of Map
will satisfy this type. Instances of LocalMap
or WorldMap
won't satisfy the type.|Nil
after the class expression. This specification says that you can assign a nil to the variable and the variable can be used to express a nil value. For example,
cobalt: Real|Nildeclares a variable to which you may assign a real number or a nil. If you do assign a nil, you can use the variable as a nil value in other expressions. If you hadn't declared the variable using the
|Nil
option, the compiler would object anytime you tried to assign a nil to the variable or anytime you tried to use the variable in an expression where the compiler knows the variable must have a value of nil.One reason that a nil option is useful in declaration is that it allows you to check the value of a variable before it has been assigned. When the Telescript engine first creates a declared variable, it assigns the variable a nil value until you assign a value later. If you haven't declared the variable with a nil option, and then try to read the variable's pre-assignment value, the compiler will object so you won't be able to read its nil value.
Assignment has a simple syntax: you give the variable's identifier, follow it with an equal sign, follow that with a value for assignment, and end with a semicolon. For example, this assignment statement sets the variable spot
to refer to the character "Z":
spot = 'Z';You may also, if you wish, use multiple variables in an assignment statement such as
spot = point = location = 'Z';in which case you must separate the variable identifiers with equal signs. All variables in a multiple assignment are assigned the same object. In this example, the three variables
spot
, point
, and location
are all assigned the value "Z"--that is, they all refer to the same character object.It's important to make sure that the variables in an assignment are all declared somewhere in the code block before the assignment statement. It's also important to make sure that the object you assign to a variable satisfies the variable's type. If you forget either of these rules, the compiler will return errors when you try to compile your code.
When you use an assignment to assign an object to a variable, you can create a new object for the assignment, or you can use an existing object.
A constructor expression is simply a class name followed by a set of zero or more values within parentheses. A constructor expression asks the engine to create an instance of the class; the values in parentheses, called initialization values, are used to define the attributes of the newly initialized object. Initialization is a topic discussed in more detail in Chapter 8. For now, it's enough to know that the class descriptions in the Telescript Language Reference describe just what initialization values are necessary for instantiating each class. You'll find that many classes require no initialization values, in which case the parentheses are empty as in this assignment example:
sahara = RainRecord();Other classes do require initialization values, in which case the values are separated by commas and placed within the parentheses as follows:
heartwood = RingCount(35, nil, 'A');One important consideration for constructor expressions: You can't use a constructor expression to construct a primitive object. Primitives are created exclusively through literal expressions.
tab = 3; count = tab;In this case, the variable
count
now refers to the same object (3
) as the variable tab
. You could use this statement to get the same results:
count = tab = 3;You can also use an assignment to calculate a new value for a variable based on the variable itself. For example
count = count + 3;uses the operator expression
count + 3
to increment the value of count
by three and assign the resulting value as count
's new referred object.There are a few wrinkles in the fabric of scope, however, caused by the fact that a block of code can contain nested blocks of code within it. If you declare a variable at the beginning of such a block, what happens to that variable within the nested blocks of code? The answer is that the variable persists within the nested blocks. This means that you can use the variable in expressions, assign it new objects, and treat it as you would in any block--all without redeclaring it. Any new assignments you make to the variable remain in effect when the execution of the nested block is finished. Consider, for example, the following code snippet:
{ counter: Integer = 0; <a statement to make the following block loop 5 times> { <statements> counter = counter + 1; <statements> } executionTimes: = counter; }The variable
counter
is declared and assigned 0 before the nested block that follows. When the nested block executes five times, counter
is incremented by one each time. When the nested block is finished looping and counter
is used in a statement outside the nested block, its value is 5, the last value it was assigned in the nested loop.You can, if you wish, redeclare a variable within a nested block--that is, you declare a variable with the same identifier as a variable in the outer block. You can give the redeclared variable a new type and object assignment, and work with it as you wish. When the nested block finishes execution, the redeclared variable is dropped, and the original variable is restored for use in the outer block. To see how this works, consider the following example.
{ counter: Integer = 73; <a statement to make the following block loop 5 times> { <statements> counter: Integer = 0; <statements> } howMany: = counter; }The first declaration in the outer block declares
counter
to be an integer and sets an initial value of 73
. Inside the looping nested block, counter
is redeclared and assigned 0
. When the nested block finishes execution, counter
is restored to its condition as it was before the nested block started execution; the loop value is removed and its original value of 73
is re-exposed. 73
is assigned to the variable howMany
.Because variable declarations may be interleaved throughout a block, it's important to realize that the scope of a declared variable does not include any statements that precede the declaration in the block. If, for example, you declare a variable after five statements in the block, that variable is not available to the preceding five statements.
Now that you understand operators and variables, it's time to move on to the next chapter, where you'll use them to write some real Telescript code.
Generated with Harlequin WebMaker