General:. Note: When
experimenting with references, use the $V ... $v facility to display
rather than %**. This is because Glee will automatically
dereference references before operating on them. %** is an operator
whereas the $V ... $v is just a signal to the scanner and not an
operator.
Glee references are a powerful programming tool. They allow access
to objects from more than one place in a program simultaneously. They also
allow access to the same object by different names (but I think that is poor
programming style.)
Example: An object could be a string naming a company.
Every place that company name is needed, the programmer could use a reference
to this string object. One reason for doing this is maintainablilty. If the
company changes its name, you just change the base string object. All
references are immediately affected. Further, if you change the name through a
reference, the base object and all other references are affected.
Because references are so powerful, you must exercise
a certain degree of caution in using them. Know what you are doing. Always
consider whether it is best to use a copy of an object or a reference to it.
To best understand references, you should know how
they are implemented. In Glee, when you name an object by
assigning a value to a name (e.g. 10=>i), you create what is called
an association. An association is a pair of objects. The first element
of the pair is a string object. This string names the other element. The
other element is the data object. Namespaces are formed by
collecting in a sequence, pointers to associations. This all happens implicitly
with the assignment operator (=>).
References are pointers to associations. They
are formed by the (@) operator (e.g. 10=>i; i@ =>ri).
In the example, "i" is an association in the local namespace
sequence. "ri" is also an association, but it associates the
symbol "ri" with a pointer to the association named
"i".
Glee can distinguish reference objects
from other associations. In so doing, it can automatically dereference
them. This allows programs to deal with references in exactly the same fashion
as their base association referents. Glee always dereferences
objects before using them in operations. References are also always singletons,
not vectors. If you want a vector of references you need to contain them in a
sequence.
Glee allows the creation of
anonymous references. These are references to unnamed objects (e.g.
10@). They have meaning only in the context in which they are used.
The best example is the result of the niladic referencing operator
(@). Just as (i@ =>ri) creates a reference to the object
"i" named "ri"; (@ =>rns)
creates a reference to the local namespace and stores it as
"rns". Through this reference, objects in the namespace can
be addressed by fields (e.g "@.i" or
"rns.i" yields the same result as just plain
"i").
A simple example: This
is the simplest of examples. An object "i" containing the
number 10 is created. Next, a reference to that object,
"ri" is created. A new value, 30 is assigned to
"ri". And as we expect, the value of "i"
is changed as well. What has really happened is the following: An association
is created in the local namespace. Its name is "i" and its
data object is a pointer to a number object containing 10. Then a
reference "ri" is created using the reference operator
(@) in the expression (i@ =>ri). This creates an
association in the local namespace named "ri". Its data
object is a reference. A reference is a pointer-to a pointer-to an association.
When Glee assigns to a reference, it dereferences the pointers
and makes the assignment to the untimate target object.
Simple reference usage: I
assign numbers to "i" and "j". At the
same time I create references to them as "ri" and
"rj" respectively. I then use "ri" and
"rj" in an expression (ri*rj) just as I would use
"i" and "j". Looking at
"ri" I see it is a reference to "i" (i.e.
i@). To see "i", I reveal
"ri" (i.e. ri ^@ $;) and see its contents
(10).
Next, I assign the string 'abc' to
"ri". Glee recognizes "ri"
as a reference to "i" and changes the data object in that
association. Now I see "ri" still references
"i" but now contains 'abc' as does
"i".
Remember, you can use references just as if they were
their referants. However, to display them, you need to disclose them
explicitly.
References to References:
Glee does not allow you to assign a reference into a reference.
Rather, it replaces the reference with the new reference. This example
illustrates Glee's behavior when you try to assign a reference
into an existing reference.
"i" is created and a reference to
it is assigned to "r". "j" is then
created and a reference to it is assigned to "r". But at
this point "r" already exists as a reference.
Glee sees the reference being assigned into a reference and does
a replacement rather than the assignement into the object referenced.
Anonymous References and
Indirect Assignment: I illustrate here how references can be made to
objects without names. In this example I create two references
("name" and "desc") to unnamed string
objects. I then form a sequence containing these references with (name
desc => rec;). Next, I assign values to
"name" and "desc" and show how those
assignments are reflected in "rec". Next, I make a new
assignment to "desc" and show "rec" again
reflecting the assignment to the reference. Finally I illustrate assignment
into an element of the "rec" variable with
('WithGLEE' => (rec[1]<); rec$;) and show its effect
on "desc". Note: Once an item of a sequence takes on a
reference object, it forever remains a reference object. This is the nature of
reference objects. They don't become values ... they refer to them. If you
assign a reference to a reference object, it replaces it. If you assign a
non-reference object to a reference object, it assigns into the referant. In
both cases, the object is a reference.
Dereferencing references:
As noted earlier, references are implicitly dereferenced when used in an
operation. However, if you just display them, the display shows them to be a
reference. It does not reveal their contents. The monadic dereference
operator (^@) returns a copy of the referent. If the argument is not a
reference, the argument is just passed through. In this example I create a
number object "i" and reference to it, (i@ =>
ri). I then illustrate the various displays in turn.
Note: I currently have no way of determining if an object is a reference. My
normal .field style of returning object information can't be used. This
is because, with references, fields are indexes into the referants. I expect
this will soon become an issue. If it does, I will likely use a double
reference (@@) to return the type of any object or
(*@) for "exists as a reference". Doing this raises
new issues I'd rather not address until I have an obvious need.