|
|||||
|
|||||
Related Syntax | Related Concepts | ||||
declaration/definition |
save |
Syntax
save shelf-name
You can use save
to create a variable that is local in lifetime but global in visibility. This means you can act on that local variable outside the lexical scope in which it occurs, as long as that scope is still executing. To accomplish this, you must first declare a global variable and then, in the appropriate local scope, save that variable. This creates a local variable with the global variable name attached to it:
global integer row-count process do xml-parse document scan file "myfile.xml" output "%c" done element table save row-count set row-count to 0 output "<table border = %"1%">%c</table>" output "<p>The table above has %d(row-count) rows." element row output "<tr>%c</tr>" increment row-count element cell output "<td>%c</td>"
In the code above, the variable row-count is saved in the "table" element rule. It is then a local variable of the "table" element rule, but it has global visibility. We are therefore able to increment it in the "row" element rule.
The principal advantage of using a saved variable rather than just using a global variable directly comes when we encounter recursive structures. Suppose that in our data we have tables within tables. The code above would work for nested tables without modification. When the table rule was called for the nested table, the variable would be saved again. Since save
creates a new local variable which simply borrows the global name, no data is lost no matter how deep the recursion. As each level of recursion exits, the local variable at the next level, whose value has not changed, regains the use of the global name, and processing continues.
The local variable created by a save is initialized to the current value of the global with the same name. If the global is a multi-item shelf, the local is initialized as a shelf of the same size with the same values.
When save
is applied to a stream shelf, every item on that shelf must be either unattached
or closed and attached to a buffer.
save
is a variable declaration, not an action. It must be placed with variable declarations at the beginning of a local scope. It cannot have a condition applied to it.
You cannot save
a function argument inside a function.
In a program that executes sequentially, the lexical scopes that save a variable always execute in a properly nested way. The state of a saved variable outside the scope and inside the scope are always distinct and cannot be accessed at the same time. If, however, the program executes multiple coroutines that share access to the same global variable, what happens when only one of the coroutines saves the variable?
If the variable is declared as global
, the action save
has global effect equally visible in
all coroutines. All saves must be properly scoped, just as in the case of a sequentially-executing program. If
two coroutines try saving the same global variable in overlapping scopes, OmniMark throws a program error at the end of the first scope, before the variable value gets corrupted.
If the variable is declared as domain-bound global
, the effect of save
is visible only in the
coroutine that saves the variable. For any other coroutine, the variable retains the same items it had outside
the saving scope. A domain-bound global
can be saved in overlapping scopes without any constraints.
The following program demonstrates the difference between a global
and a domain-bound global
variable:
global string s1 initial { "Hello, World!" } domain-bound global string s2 initial { "Hello, World!" } define string source function f as save s1 save s2 set s1 to "Salut, Monde!" set s2 to "Salut, Monde!" output "Ready.%n" output "Within the save scope: " || s1 || " " || s2 || "%n" process using input as f do output #current-input take "Ready.%n" output "Outside the save scope: " || s1 || " " || s2 || "%n" do save s1 save s2 set s1 to "Hola, Mundo!" set s2 to "Hola, Mundo!" output #current-input take (any ** "%n") done done
The output of this example is
Outside the save scope: Salut, Monde! Hello, World! Within the save scope: Hola, Mundo! Salut, Monde!
Also note that, if we were to shorten the last output
line in the program to
output #current-input
, the function would end before the using input as
scope. The program
would then fail with errors.
Variables of record types and opaque data types are references, so when you save
a variable of this type, you are saving the references, not the actual record or opaque variable. This means you have a new local reference to the record or opaque variable, but still only one global copy of the record of variable itself. Therefore any changes you make to the record or variable in the scope of the save is made to the global record or variable, just as if you had not performed a save. On the other hand, any changes you make to the reference itself are local to the scope of the save and the original reference will be restored when the save scope ends.
The following program illustrates the difference:
declare record greeting field stream word global greeting meeting global greeting parting process set meeting:word to "Hello" set parting:word to "Goodbye" output meeting:word || "%n" output parting:word || "%n" do save meeting save parting local greeting meeting-french set meeting-french:word to "Bonjour" set meeting to meeting-french set parting:word to "Au revoir" output meeting:word || "%n" output parting:word || "%n" done output meeting:word || "%n" output parting:word || "%n"
The output of this program is as follows:
Hello Goodbye Bonjour Au revoir Hello Au revoir
Notice that within the save scope the values of the record referenced by the variable parting
are updated directly within the save scope and are therefore permanent and continue after the end of the scope. In the case of the variable meeting
however, meeting
is changed to reference a locally created record referenced by meeting-french
. When the local copy of meeting
is destroyed at the end of the save scope, the original variable is restored and it still references the original record, and thus displays its value in the final output
statement.
Related Syntax |
Related Concepts |
Copyright © Stilo International plc, 1988-2010.