This page uses CSS, and renders properly in the latest versions of Microsoft Internet Explorer and Mozilla.
This is Frontier: The Definitive Guide by Matt Neuburg, unabridged and unaltered from the January 1998 printing.
It deals with the freeware Frontier 4.2.3; for commercial Frontier 8, look here, and for the inexpensive Radio UserLand, look here. See my Web site for information.
Those wishing an offline or printed copy may purchase the book, which is still in print.
Copyright 1998 O'Reilly & Associates, Inc. ALL RIGHTS RESERVED. Reprinted with permission.
TOP UP: UserTalk Basics NEXT: Datatypes

9

Special Evaluation

In general, Frontier evaluates names before using them. When you say:

x = y

it is the value of y that is assigned to x ; when you say:

myScript(y)

it is the value of y that is handed as a parameter to myScript(). Under certain circumstances, however, Frontier behaves exceptionally with regard to evaluation. Sometimes it doesn't evaluate a name; sometimes it bypasses the normal evaluation rules. This chapter is about these and related matters.

Non-Evaluation

Four verbs - defined(), parentOf(), sizeOf(), and nameOf() - are special forms : they look like ordinary verbs, but they aren't. When they are used, their parameter is not evaluated. These verbs have in common that their parameter is an object reference - not an address - and it was this object reference itself, not its value, which passed to the verb.

To see why this is a good idea, consider defined(), which returns true or false depending on whether its parameter is the object reference of an existing object. Suppose defined() were not a special form. If we handed defined() an object reference and that reference was evaluated, we wouldn't be talking about the object itself. We could not hand defined() an address, though, because if the object in question didn't exist, it might be illegal to take its address in the first place.

The other special forms are parallel; one can speak to them of nonexistent objects without causing a runtime error.

If what you have is an address or string denoting the object reference, and you wish to hand that object reference as parameter to one of these verbs, you must dereference the address or string. For example:

defined (fakeTable.fakeEntry)
    « false
myString = "fakeTable.fakeEntry"
defined (myString^)
    « false, as expected; if we had said defined(myString)...
    « ...it would have returned true - the string variable myString exists

Because of the non-evaluation, it is permissible to dereference a string denoting an unresolvable reference.1

Pre-Evaluation

Like most computer languages, UserTalk has a number of reserved words . The user is not free to employ such reserved words to designate ordinary objects. For example, the keywords, such as if, with, on, return, and local, are reserved words. If you could call a variable local, then whenever you said local, Frontier would have a hard time deciding whether you were referring to your variable or starting a local declaration.

The way Frontier enforces the special status of its reserved words is by pre-evaluating them. When you use a reserved word, Frontier never even tries to resolve it as a name; it discovers beforehand that the word is reserved. The resolution process is, as it were, short-circuited in order for reserved words to work.

Pre-evaluation is implemented by way of three lists of reserved words, which are maintained inside system.compiler. The keywords are kept at system.com-piler.language.keywords. Certain verbs that need special treatment - including the special forms we have just mentioned - live at system.compiler. language.builtins. In addition, the UserTalk constants - in other words, names whose values are predefined at compiler level - are in system.compiler. language.constants.

It is best not to attempt to give an object a name that is a reserved word. Because of pre-evaluation, which can extend even to individual elements of an object reference, you will not be able to refer normally to such an object. Here are some examples of the kinds of knots you can tie yourself in if you try it:

  • You cannot directly define a local variable called infinity ; infinity is a compiler constant, and pre-evaluation means you are trying to define a local variable called 2147483647. You would have to speak of ["infinity"] instead.
  • You can define a local handler called pack, but you cannot call it. pack() is a built-in verb, and pre-evaluation means that when you say pack() you call the pack() in system.compiler.language.builtins.
  • Similarly, you can define a handler in the workspace table called pack, and you can call it by saying workspace.pack(), but if you say:
with workspace
    pack()
  • it is the built-in pack() that is called, because the pre-evaluation precedes the application of the with.

Also, it is unwise to call a database entry by one of the names constants, keywords, or builtins.

Constants

The built-ins and reserved words are discussed individually later on, under the topic appropriate to the functionality of each. The UserTalk constants are as follows:

  • The no-value constant, nil . This is the value of any variable or database entry that has never been explicitly assigned a value; you may assign it as a value if you wish.
  • The largest positive integer UserTalk can represent, dubbed infinity.
  • The eleven "directions," used in describing cursor movement when operating on such objects as wptexts and outlines: the most important are up, down, left, right, flatup, and flatdown.
  • The two booleans, true and false.
  • The datatype names. Their use is discussed in Chapter 10, Datatypes .

evaluate( )

We have seen that you can obtain an extra round of evaluation for an element of an object reference that is a valid UserTalk expression, by enclosing the element in square brackets:

people.[user.initials]

By the same token, you can obtain an extra round of evaluation for any UserTalk expression. The expression must be constructed as a string; that string is then handed to evaluate() and the result of evaluating it is returned.

evaluate() is useful when an expression is unknown until runtime. This situation typically arises when a script, during the course of its execution, turns to the user to obtain a UserTalk expression. The communication takes place by way of a string. For example, suites.samples.basicStuff.runClipboard() is a script that lets the user copy text from another application for Frontier to evaluate in UserTalk; the user can then paste the result into the original application. And use of evaluate() in Frontier's Web site management facilities is what makes it possible to calculate pieces of a Web page at runtime; for instance, if {clock.now()} appears within the text of a Web page, the current time is substituted when the page is actually produced.


1. Certain other verbs, such as delete(), appear to be special forms in other ways, performing evaluation in an unusual fashion, but they are less significant.


TOP UP: UserTalk Basics NEXT: Datatypes

This is Frontier: The Definitive Guide by Matt Neuburg, unabridged and unaltered from the January 1998 printing.
It deals with the freeware Frontier 4.2.3; for commercial Frontier 8, look here, and for the inexpensive Radio UserLand, look here. See my Web site for information.
Those wishing an offline or printed copy may purchase the book, which is still in print.
Copyright 1998 O'Reilly & Associates, Inc. ALL RIGHTS RESERVED. Reprinted with permission.