Chapter 7

Executing a Simple Script

This book--until now--has shown you snippets of sample code, but no full scripts. This chapter takes the plunge: it shows you how to write a simple executable script. Along the way, you'll be introduced to the Telescript language's logical flow controls, to its mechanism for reporting execution errors, and to a debugging operation that prints text to your screen so you can see how your program is executing.

Using a Do Statement

You've already been introduced to the concept of a block--a group of statements and variable declarataions enclosed by curly brackets--in previous chapters. You know that a block defines a set of statements for execution, and that blocks are used to create an object's methods; each method is a block of code that executes when the method's corresponding operation is called.

If you want to create a simple script of Telescript code that stands on its own and allows you to declare variables that are restricted to the scope of the code, you can use a do statement. A do statement is simply a block--a group of statements enclosed in curly brackets ({})--preceded by the keyword do. For example, the following is a very short do statement:

do {
	mangos, papayas, fruits: Integer;
	mangos = 25;
	papayas = 47;
	fruits = mangos + papayas;
}
When you compile and execute a script that is a do statement, the Telescript engine executes each of the block's statements in logical order. Executing the example statement you just saw performs some declarations, assignments, and calculation, but has no observable end effect. We'll show you how to see some results later in the chapter.

When you create a do statement, you may have blocks nested within it. For example, you may want to use nested blocks for if/else statements in the do statement.

Monitoring Script Execution

The Telescript language is specialized for network communication between computers. It leaves most non-communication tasks--such as displaying graphics or printing text on a computer monitor--to non-Telescript external code. A pure Telescript script can't, for example, show anything on your computer monitor to prove that it's been working. It can send agents around the globe, retrieve and transfer large amounts of data, all without any outward sign that anything has happened. To display the data that it's retrieved, it must hand off the data to external code.

It's useful to give Telescript code an external voice that can report on activities and help debugging. That voice is provided by the debugging operation dump. dump is implemented on development Telescript engines as an extra operation on the class Object. (dump has no effect when used on production engines.) As you'll recall, every object on a Telescript engine is a member of class Object, so every type of object on an engine has Object operations. This means that you can call dump on any object.

dump takes no arguments. When it's called on an object, it prints the name of the object's class on the engine's monitor. If the class is a predefined Telescript class (one of the classes defined in the Telescript Language Reference), dump also prints the object's value and the value of each of the object's properties. For example, consider this dump statement:

25.dump();
When executed, it creates an integer object of value 25. It then calls dump on the object, which prints this on your monitor:

Integer: <25>
You can use dump with strings to print out text that can inform you of a state or execution location within a script. For example, this dump statement:

"The first arithmetic expression has just been evaluated.".dump();
creates a string that is dumped on your monitor like this:

String: <The first arithmetic expression has just been evaluated.>
We'll use dump throughout this book to show you--on the printed page--the results of executing code.

Controlling the Flow of Execution

Execution flow statements are statements that make execution jump to a new location in your code and that may provide conditional tests to determine where to jump. These statements add a spark of intelligence to code in any language. The Telescript language provides syntax for a full set of execution flow mechanisms.

If/Else Statments

if/else statements allow provisional execution branching. An if/else statement tests a boolean expression and then, if the expression is true, executes a following block or, if the expression is false, skips the block. The statement can include optional following blocks, each with its own boolean test. Any of these blocks can execute if their boolean expression is true and no previous blocks in the statement have executed.

A Simple If Statement

The simplest form of the if/else statement is this:

if <boolean expression> {<statement(s)>};
The boolean expression is the test for execution forking. The block of code following executes or doesn't execute depending on the boolean expression. The semicolon at the end of the statement is optional only if the statement occurs at the end of an enclosing block.

When this simple form of an if/else statement executes, the boolean expression determines where execution continues. If it's true, the block following executes. If it's false, the block following is skipped and execution moves to the next statement following the if/else statement. For example, this do statement

do{
	azure: = 35;
	if azure>20 {"azure is greater than 20.".dump();};
	"This program is finished.".dump();
}
has these results on execution:

String: <azure is greater than 20.>
String: <This program is finished.>
If you edit the second line to set the value of azure to 5, you see these results:

String: <This program is finished.>

The Optional Else

You may, if you wish, create an either/or choice with a two-block if/else statement that uses this syntax:

if <boolean expression> {<statement(s)>} else {<statement(s)>};
The keyword else in the statement precedes a second block of statements. If the boolean expression is true, the first block executes and execution skips the second block. If the boolean expression is false, execution skips the first block and the second block executes. Execution continues with the next statement following the if/else statement in either case. The following do statement is an example:

do{
	azure: = 15;
	if azure>20 {"azure is greater than 20.".dump();}
		else {"azure is 20 or less.".dump();};
	"This program is finished.".dump();
}
When executed, it yields these results:

String: <azure is 20 or less.>
String: <This program is finished.>
If you change the code so that azure is equal to 25, execution yields these results:

String: <azure is greater than 20.>
String: <This program is finished.>

The Optional Else If

In the syntax you just saw for a two-block if/else statement, one of the blocks always executes. If you'd like to have the possibility that neither block executes, you can use the keywords else if in place of the else keyword as shown in the following syntax:

if <boolean expression> {<statement(s)>} else if <boolean expression> {<statement(s)>};
The second boolean expression matches the second block. If the first boolean expression is true, the first block executes. The second boolean expression isn't evaluated and execution skips the second block. If the first boolean is false, execution skips the first block and the second boolean expression is evaluated. If the second expression is true, the second block executes. If the second boolean is false, the second block is skipped.

Consider the following do statement as an example:

do{
	azure: = 20;
	if azure>20 {"azure is greater than 20.".dump();}
		else if azure<20 {"azure is less than 20.".dump();};
	"This program is finished.".dump();
}
When executed, you see these results:

String: <This program is finished.>
If you change the code so that azure equals 30, you see these results:

String: <azure is greater than 20.>
String: <This program is finished.>
And if you change the code so that azure is equal to 15, you see these results:

String: <azure is less than 20.>
String: <This program is finished.>

Multiple Else Blocks

If you'd like to test for more than two conditions in an if/else statement, you can add as many else if clauses as you'd like following the if clause. You can end the else if clauses with an optional else clause if you'd like, as in the following syntax:

if <boolean expression> {<statement(s)>}
	else if <boolean expression> {<statement(s)>}
	<more optional else-if expressions and blocks>
	else if <boolean expression> {<statement(s)>}
	else {<statement(s)>};
In this case, each boolean expression in the statement is evaluated in turn. If the expression is true, its associated block is executed and execution skips the rest of the statement--no more of that statement's expressions are evaluated, and none of its following blocks is executed. If none of the expressions evaluates to true, the last block is executed (the block following the else keyword).

If you want to leave an opportunity open for none of the blocks in the statement to execute, you can end the statement with an else if clause as shown in the following syntax:

if <boolean expression> {<statement(s)>}
	else if <boolean expression> {<statement(s)>}
	<more optional else-if expressions and blocks>
	else if <boolean expression> {<statement(s)>}
	else if <boolean expression> {<statement(s)>};
This form of if/else statement is evaluated as before with this difference: If none of the boolean expressions is true, then none of the blocks in the statement is executed (instead of executing the last block if none is true).

Consider this do statement as an example:

do{
	azure: = 2;
	if azure==1 {"azure equals one.".dump();}
		else if azure==2 {"azure equals two.".dump();}
		else if azure==3 {"azure equals three.".dump();}
		else {"azure is not an integer equal to 1, 2, or 3.".dump();};
	"This program is finished.".dump();
}
When executed, you see these results:

String: <azure equals two.>
String: <This program is finished.>
If you change the code so that azure equals 5, you see these results:

String: <azure is not an integer equal to 1, 2, or 3.>
String: <This program is finished.>
If you set up a multiple else clause statement like this one, note that the statement stops evaluating booleans as soon as it finds a true boolean. If you put expressions that are most often likely to be true before expressions that are less often likely to be true, you'll make execution of your code more efficient. That's because execution won't often have to step through all or most of the expression evaluations.

Loop Statements

loop statements allow a single block to repeat execution continuously. The syntax for a loop statement is simple:

loop {<statement(s)>};
When a loop statement executes, the block in the statement executes from beginning to end, starts execution from the beginning of the block again, and continuously loops execution through the block until a statement within the block stops execution or jumps execution to some point outside the loop block.

A loop statement is often used to enclose a block containing an if/else statement that tests a condition. When the condition is right, a break statement (explained a little later in this chapter) executes and the loop block stops execution. Execution then jumps to the next statement following the loop statement.

If a statement in the loop block throws an exception, this also stops execution of the block and--if the exception is uncaught--execution of the statements surrounding the loop block. (You'll read about exceptions--Telescript's mechanism for reporting errors or exceptional conditions--later in this chapter.)

Please note that a loop block executing for long periods of time is an excellent way to chew up processor resources with no useful results. A process that indiscriminately uses a loop statement may find itself killed by the service provider whose resources it's wasting. If you use a loop block for busy waiting (that is, testing constantly for a condition to change), you should consider using the getEvent operation instead to wait for an event. (You'll learn about events--an advanced Telescript programming mechanism--in a future chapter.)

Break Statements

break statements can only be used within iterative statements such as a loop, while, or for statement. Their very simple syntax is:

break;
When a break statement executes within an iterative block, it halts execution and skips execution to the next statement following the iterative statement. No statements following the break statement within the block are executed.

Consider the following do statement as an example:

do{
	azure: = 0;
	loop {
		azure = azure+1;
		if azure>20 {break;};
	};
	"azure is legal now.".dump();
}
The loop block executes 21 times. The 21st time it breaks with this result:

String: <azure is legal now.>

Continue Statements

continue statements can only be used within iterative statements such as a loop, while, or for statement. Their syntax is as simple as that of the break statement:

continue;
When a continue statement executes within an iterative block, it halts execution and moves execution once again to the beginning of the iterative block, where the next iteration begins. You can use a continue statement to skip unnecessary steps in a loop block. Consider this example:

do{
	azure: = 0;
	loop {
		azure = azure+1;
		if azure<19 {continue;};
		"azure is approaching legal age.".dump();
		if azure == 21 {break;};
	};
	"azure is legal now.".dump();
}
When this statement executes, the loop block loops. On the 19th and 20th loops, the second block of the if/else statement executes, printing an "approaching age" message. On the 21st loop, the else block executes, halting loop block execution so the last statement of the program executes. The results look like this:

String: <azure is approaching legal age.>
String: <azure is approaching legal age.>
String: <azure is legal now.>

While Statements

If you want to loop a block but test for stopping the loop outside the block, you can use a while statement. Its syntax is this:

while <boolean expression> {<statement(s)>};
When a while statement executes, it evaluates the boolean expression. If it's true, the while block executes and the expression is evaluated once again. As long as the expression is true, the while block continues to execute. If the boolean expression is false, execution skips the while block and continues with the next statement following the while statement.

The following do statement shows a while statement at work:

do{
	azure: = 0;
	while azure<5 {
		azure = azure+1;
		"azure is still less than five.".dump();
	};
	"azure has reached five.".dump();
}
When executed, you see these results:

String: <azure is still less than five.>
String: <azure is still less than five.>
String: <azure is still less than five.>
String: <azure is still less than five.>
String: <azure is still less than five.>
String: <azure has reached five.>

Repeat Statements

If you want to loop through a block a set number of times, you can use a repeat statement. The syntax is this:

repeat <integer> {<statement(s)>};
When a repeat statement executes, it executes its block the number of times specified by the integer following the repeat keyword. Although the integer is often a literal, it can be any expression that returns an integer.

The following do statement shows a repeat statement at work:

do{
	repeat 4 {"Interation utterance".dump();};
	"Iteration is finished.".dump();
}
When executed, it produces the following results:

String: <Iteration utterance.>
String: <Iteration utterance.>
String: <Iteration utterance.>
String: <Iteration utterance.>
String: <Iteration is finished.>

For/to Statements

Use a for/to statement if you want to loop through a block a set number of times and make the loop count available within the block. The for/to statement uses the following syntax:

for <integer variable/property> to <integer> {<statement(s)>};
The counter here can be either an integer variable or an integer property. If it's an integer variable (the most common case), it can be a variable that was declared previously to class Integer, or variable may be declared between the for and to keywords, in which case you use the following syntax:

for <integer variable>: Integer to <integer> {<statement(s)>};
If the variable is declared using the second syntax, the variable is restricted in scope to the for/to block that follows. If the variable is declared outside the for/to statement, as in the first syntax, its scope is determined by where it's declared. In any case, its scope includes--but isn't restricted to--the for/to block that follows.

The integer value after the to keyword is the number of times you want to execute the for/to block. If the value is zero or a negative number, it specifies that the for/to block won't execute at all.

When a for/to statement is executed, the integer variable is assigned a value of 1, then the for/to block is executed. The statements in the block can read the value of the integer variable. When the block is finished executing the first time, the integer variable is assigned a value of 2 and then the block executes a second time. After that the integer is assigned a value of 3 for the third execution, 4 for the fourth execution, and so on until the variable is larger than the integer value after the to keyword. When that happens, execution jumps to the next statement following the for/to statement.

It's important to note that an independent Telescript mechanism keeps track of the number of block iterations and assigns that number to the integer variable each time before the block executes. This means that if you change the value of the integer within the block (a bad programming practice in most cases), it doesn't affect the iteration count. To see how this works, look at the following do block:

do{
	counter: Integer;
	for counter to 4 {
		"New iteration.".dump();
		counter.dump();
		counter = counter+5;
		counter.dump();
	};
	"The for/to loop is finished.".dump();
	counter.dump();
}
Notice that the integer variable counter is initialized before the for/to statement. Here are the results when the do block is executed:

String: <New iteration.>
Integer: <1>
Integer: <6>
String: <New iteration.>
Integer: <2>
Integer: <7>
String: <New iteration.>
Integer: <3>
Integer: <8>
String: <New iteration.>
Integer: <4>
Integer: <9>
String: <The for/to loop is finished.>
Integer: <9>
If counter had been initialized within the for/to statement like this

for counter: Integer to 4 {
then the scope of the variable would be restricted to the for/to block. The compiler would object to the last statement in the do statement because it tries to dump the variable counter, which no longer exists outside the for/to block.

For/in Statements

for/in statements provide one iteration of a block for each item within a collection. A collection is any object that's a member of Collection, a class you'll be introduced to in Chapter 9. For now, it's enough to know that a collection is a group of objects--a group of integers, for example, or of strings, agents, or even objects of mixed types.

This is the syntax of a for/in statement:

for <variable/property> in <collection> {<statement(s)>};
The variable or property after the for keyword should be one that is declared to be the same class or a superclass of every item in the collection. If the collection is a set of integers, for example, the variable or property should be declared to be class Integer, class Number, or class Object. If you use a variable as the counter, it may be declared before the for/in statement, in which case its scope extends beyond the for/in block. Or the variable may be declared within the for/in statement, just as a variable may be declared in a for/to statement. In that case, it uses the following syntax:

for <variable>: <class ID> in <collection> {<statement(s)>};
The scope of a variable declared this way is restricted to the for/in block.

The number of objects contained in the collection following the in keyword determines the number of iterations of the for/in block. When the for/in statement executes, it assigns an object in the collection to the variable, then executes the for/in block. When the block finishes, a second object in the collection is assigned to the variable, and the for/in block executes a second time. This continues until an iteration of the block has occurred for each object in the collection. When all the objects in the collection have had an interation, the for/in statement passes execution on to the next statement following. Because the for/in variable points to a different item of the collection for each iteration, the block can work on that item during its iteration.

The following do statement shows a for/in statement at work:

do{
	total: Number = 0;
	values: = Collection[Number,Equal](4, 5.2, 3.14159, 10);
	for itemValue: Number in values {
		total = total+itemValue;
		total.dump();
	};
	"The for/in loop is finished.".dump();
	total.dump();
}
In the third line of the program, notice that the expression assigned to the variable values is a collection object containing the numbers within parentheses. When executed, the statement has these results:

Integer: <4>
Real: <9.2>
Real: <12.34159>
Real: <22.34159>
String: <The for/in loop is finished.>
Real: <22.34159>

Understanding Exceptions

When you compile a script and then execute it on a Telescript engine, operations called in the script can signify a problem in execution (an error, for example) by throwing an exception--a mechanism vaguely akin to throwing a fit, but much more polite. To create a safe script, it's important to know what an exception is and how Telescript uses exceptions so you can plan your code accordingly.

Exception Subclasses

An exception is an object that is a member of the class Exception. Because Exception is an abstract class, you can't instantiate it directly. You must instead instantiate one of its subclasses to create an exception.

The Telescript language contains many predefined subclasses of Exception, but you won't find them all listed with individual entries in the Telescript Language Reference for two reasons: They're too numerous to list individually, and many differ only in their class IDs. Some exceptions, such as TripException, have extra features so they are listed under individual entries.

Telescript's predefined Exception subclasses are named to indicate a specific problem in execution. The Telescript language defines a subclass named DivisionByZero, for example, that indicates a problem trying to evaluate a division expression where the divisor has a value of zero. You may, if you wish, define your own Exception subclasses with class IDs that signify special execution problems that may crop up in your custom operations. You can add attributes and operations to those subclasses to help report on the conditions that threw the exceptions.

Throwing an Exception

To throw an exception, use a throw statement. It starts with the keyword throw and is followed by an exception as shown in this syntax:

throw <exception expression>;
For example, this throw statement throws the custom exception NoRainData:

throw NoRainData();
As you'll see in later chapters, a class's methods may often include throw statements to throw an exception because of conditions that exist in that location of the code. For example, the throw statement with NoRainData might sit after a test to see if a variable pointed to rain data, and before statements that would calculate new values using that rain data. If, during execution, the data isn't there, the throw statement executes.

When a throw statement executes, it immediately halts execution of the block where it occurs and throws the exception to an enclosing block if there is one (that is, if the executing block is a nested block within the enclosing block). The enclosing block may then catch the exception using mechanisms described later in this chapter. If the block doesn't catch the exception, then that block stops execution and throws the same exception to its enclosing block if there is one. In this way, an uncaught exception can percolate up through a chain of nested blocks until there are no more blocks to throw the exception.

As you'll remember, an object's methods are blocks of code. This means that methods can and do throw exceptions. If the method of a requester calls the method of a responder, the responder's method may throw an exception. If so, the responder's method halts execution and throws the exception to the requesting method, which may catch it. If it doesn't catch the exception, the requesting method halts execution and throws the same exception.

If one object requests an operation of another object that requests an operation of another object and so on to create a chain of operation calls, an exception thrown by the method of any one of those operations can--if uncaught--percolate all the way up to the original calling method. That method, as you'll learn later, will typically be the live method of a process. If the exception is uncaught there, the engine kills the process.

To see how this works, consider the chain of operations shown in the numbered steps of Figure 7-1. The first object, a process, calls the planWeekend operation on a second object. That operation in turn calls the checkClimate operation on a third object, which calls checkRainfall on a fourth object. checkRainfall's method doesn't have the proper rainfall data, so it stops execution by throwing an exception of the class NoRainData to checkClimate. checkClimate isn't set up to handle the exception, so it immediately stops execution by throwing the exception to planWeekend, which doesn't catch the exception either. It stops execution by throwing the exception to the process, which doesn't handle the exception and is killed.

Figure 7-1 : An uncaught exception (NoRainData) percolates all the way back up a chain of operation calls, killing the process at the beginning of the chain.

The whole succession of percolating exceptions has a clear moral: Uncaught exceptions kill. Catching exceptions is an important part of writing Telescript code that won't crash and die ignominiously. As you may remember from Chapter 4, each operation in the class descriptions of the Telescript Language Reference lists any exceptions that it may throw. You can plan to catch those exceptions using the techniques described later in this chapter.

To see how an uncaught exception kills the execution of a do statement, look at the following sample code with an attempted division by zero.

do{
	"2-25".dump();
	(2-25).dump();
	"2.0-25".dump();
	(2.0-25).dump();
	"25/0".dump();
	(25/0).dump();
	"-4".dump();
	(-4).dump();
	"(4*5)-(2*5)".dump();
	((4*5)-(2*5)).dump();
}
When the code executes, you get the following results:

String: <2-25>
Integer: <-23>
String: <2.0-25>
Real: <-23>
String: <25/0>
<<<The process is killed at this point.>>>
In this case, the divide operation of the class Number (which is called when you used the / operator) threw the exception DivisionByZero. Because it was uncaught, it halted execution of the do block. Notice that execution continued up to the point where the exception was thrown. All statements after the point of exception weren't executed.

Handling Exceptions

Now that you know how exceptions are thrown, you can learn how they're caught: by using a try statement that's quite similar in syntax to an if/else statement.

A Simple Try Statement

A simple try statement uses this syntax:

try {<statement(s)>} catch <exception class ID> {<statement(s)>};
The statement has two blocks. The first is the try block--the block of statements in which you expect an exception to be thrown. The second is the catch block--the block you want to execute if an exception is thrown in the try block. The exception class ID between the two blocks is the type of the exception you'd like to catch. If the exception thrown in the try block isn't a member of this class, the exception isn't caught, execution stops immediately, and the exception percolates up. If the exception is a member of the class, the exception is caught and the catch block executes.

When a try statement of this form executes, the try block begins execution. If it executes completely without any thrown exceptions, execution skips the catch block and goes to the next statement following the try statement. If the try block throws an exception, the try block stops execution and the exception is checked against the specified exception class ID. If the exception is a member of the specified exception class, the exception is caught; the catch block executes and, when finished, passes execution on to the next statement following the try statement. If the exception is not a member of the specified exception class, the exception isn't caught, execution ceases immediately, and the exception percolates up.

To see how a simple try statement works, consider the following do statement. It puts a previous example--the one that threw a DivisionByZero exception--in a try block. It catches the exception and reports on that fact.

do{
	try {
		"2-25".dump();
		(2-25).dump();
		"2.0-25".dump();
		(2.0-25).dump();
		"25/0".dump();
		(25/0).dump();
		"-4".dump();
		(-4).dump();
		"(4*5)-(2*5)".dump();
		((4*5)-(2*5)).dump()
	}
	catch Exception {"An exception was thrown and I caught it.".dump();};
	"That's all, folks!".dump();
}
Notice that in this try statement, the exception class ID is Exception. That means that the catch block will execute if any exception is thrown--because every exception is a member of the class Exception. When the do statement executes, these are the results.

String: <2-25>
Integer: <-23>
String: <2.0-25>
Real: <-23>
String: <25/0>
String: <An exception was thrown and I caught it.>
String: <That's all, folks!>
The try block executes its statements, dumping to the screen, until it reaches line 8, which tries to divide by zero. It throws DivisionByZero which halts execution of the try block. The exception is checked against the specified exception class, which is Exception. Because DivisionByZero is a subclass of Exception, the exception is caught and the catch block executes, reporting on a thrown exception. When it finishes, execution moves to the next statement, which reports the end of the program.

If lines 7 and 8 of the program were changed to divide by 5 instead of 0, you'd see these results:

String: <2-25>
Integer: <-23>
String: <2.0-25>
Real: <-23.0>
String: <25/5>
Integer: <5>
String: <-4>
Integer: <-4>
String: <(4*5)-(2*5)>
Integer: <10>
String: <That's all, folks!>
That's because the try block executed without exceptions, so the catch block was skipped.

Using an Internal Catch-Block Variable

One problem with the last example program is that the catch block doesn't know what kind of exception was thrown, and can't take action accordingly. If you'd like to pass the exception into the catch block so statements there can work on it, you can add an internal catch-block variable to the try statement. The syntax is this:

try {<statement(s)>} catch <exception variable declaration> {<statement(s)>};
This statement works just like the simple try statement discussed before with one difference: the exception class ID is replaced with an exception variable declaration. This declaration creates a variable that is declared to be a type of exception. For example, the declaration might be caughtEx: DivisionByZero. The exception class ID specified for the variable is also the type of exception that is specified to be caught. That exception type sets the scope of exceptions that will be caught in the catch block.

Telescript offers a second syntax to declare an internal catch-block variable. It encloses the declaration in parentheses:

try {<statement(s)>} catch (<exception variable declaration>) {<statement(s)>};
Both syntaxes have the same effect.

When a try statement with an internal catch-block variable executes and an exception is thrown and caught, the exception is assigned to the variable and the catch block executes. The variable is restricted in scope to the catch block, so when the catch block is finished executing and execution passes to the next statement following the try statement, the variable is dropped.

The following do statement alters the first try block example to use an internal catch-block variable:

do{
	try {
		"2-25".dump();
		(2-25).dump();
		"2.0-25".dump();
		(2.0-25).dump();
		"25/0".dump();
		(25/0).dump();
		"-4".dump();
		(-4).dump();
		"(4*5)-(2*5)".dump();
		((4*5)-(2*5)).dump()
	}
	catch caughtIt: Exception {
	"An exception was thrown and I caught it.  It's this:".dump();
	caughtIt.dump();
	};
	"That's all, folks!".dump();
}
The try statement now declares a variable of class Exception, a broad enough class type to catch any kind of exception. When it runs, it has these results.

String: <2-25>
Integer: <-23>
String: <2.0-25>
Real: <-23>
String: <25/0>
String: <An exception was thrown and I caught it.  It's this:>
DivisionByZero
String: <That's all, folks!>
This time through the try statement, the thrown DivisionByZero exception is caught and assigned to the variable caughtIt. The last statement dumps caughtIt so you can see what type of exception was caught.

Using Multiple Catch Blocks

There may be times when you want to catch any one of a variety of exceptions, and then take different actions depending on the type of the exception. For those times, you can use multiple catch blocks, which use the following syntax:

try {<statement(s)>}
catch <exception type/exception variable declaration> {<statement(s)>}
<more optional catch blocks>
catch <exception type/exception variable declaration> {<statement(s)>};
The exception type following the keyword catch in each catch line can be either the class ID of an exception (as you saw in the simple try statement example), or an exception variable (as you saw in the last try statement example) if you want to work with the caught exception within the catch block.

When a statement with multiple catch blocks executes, it works very much like an if/else statement with multiple else blocks. If the try block executes without any exceptions, none of the catch blocks is executed. If the block throws an exception, however, it's checked against each catch type in order. If it matches the catch type, the catch block associated with it is executed and the other catch types aren't checked.

* * *

You can use the syntax you've learned in this chapter to write your own Telescript programs. In the next chapter, you'll find out how to initialize objects to use in those programs.

7 - Executing a Simple Script
Using a Do Statement
Monitoring Script Execution
Controlling the Flow of Execution
If/Else Statments
A Simple If Statement
The Optional Else
The Optional Else If
Multiple Else Blocks
Loop Statements
Break Statements
Continue Statements
While Statements
Repeat Statements
For/to Statements
For/in Statements
Understanding Exceptions
Exception Subclasses
Throwing an Exception
Handling Exceptions
A Simple Try Statement
Using an Internal Catch-Block Variable
Using Multiple Catch Blocks

TS Ref - 26 JUN 1996

Generated with Harlequin WebMaker