Frag Object System
This section gives an overview of the Frag object system. For details of the
predefined methods for all objects, please refer to reference of Object
presented below (in Section Object: Method Reference).
Frag is an object-oriented language, but in contrast to many other
object-oriented languages, in Frag every entity is represented by an object.
An object can play the role of a class or a superclass as well, when this is required.
The class concept of the language is not fixed but can be tailored to the current situation.
In Frag all relationships of an object, including class and superclass
relationships, might possibly be changed at any time. When an invocation takes
place, the invocation is dispatched within the current context of the object.
The standard dispatch algorithm of Frag first looks up the classes and superclasses
of the object, calculates the dispatch order, and then dispatches the invocation
in this context.
Note that this dynamic lookup does not mean a problematic performance penalty
in most cases because Frag optimizes the dispatch performance by caching
the lookup order. More important, Frag is not intended to host the
performance-intensive parts of the application - this is the role of the (e.g. compiled)
host language (in case of Frag this is typically Java). Frag is used solely for
composition and configuration, and other high-level tasks, such as building DSLs.
Each object can have one or more classes, but each object in Frag has at least
one class. An object always has at least the class Object, the most generic
class in the Frag object system. Each other class is a subclass of Object. This way
it is ensured that every object in Frag can use the features defined by the class Object.
An object is created by invoking the method create of its class.
For instance, we can create an object Connection1 from the most general class
Object:
Object create Connection1
This invocation means that a new object with the object ID Connection1 is created.
This new object has the class Object.
Alternatively, we can create objects which are unnamed by omitting the object ID
in the create invocation:
set connection1 [Object create]
An unnamed object is immediately garbage collected, once there are no more
references to it. That's the reason, why we stored the object ID in the
variable connection1, directly after it was created. If we don't do this,
the object is lost. For instance, the object created in the following invocation
is directly removed from the interpreter by the garbage collector:
Object create
Unnamed objects have an automatically assigned ID, of the form: %%number,
such as %%12. Named objects have an initial reference, their name. Only if
this name is forgotten, e.g., using the method unname, they can automatically
be garbage collected.
It is advisable to use named objects for instances that should survive, even
if no one references them. Typical examples are objects that are used as classes: They are
typically realized as named objects. Unnamed objects are used for short-living
instances, or for instances that occur in great numbers or consume a lot of
memory, and hence they should get garbage collected, once they are not in use anymore.
We have already seen that the method create can be used to derive an object
from a class. Consider we want to create a class SocketConnection, and derive an
object Connection2 from this class:
Object create SocketConnection
SocketConnection create Connection2
In the context of Connection2, the object SocketConnection acts as a class.
Note that there is no difference in how we have created SocketConnection and
Connection1; at this point both are ordinary objects. The subsequent
creation of Connection2 is what makes SocketConnection (also) a class.
SocketConnection acts as a
class only in the context of Connection2.
In this example it makes not much sense to derive objects from Connection2;
thus it will likely not act as a class. But note that this two-level class concept
is not always applying. For instance, we might want to constrain or extend the
features of SocketConnection. Consider Frag does not implement the SocketConnection
itself, but it is a wrapper for a Java class. That means somewhere we need to define
how to access the Java counterpart of SocketConnection, and this implementation
should be reusable for all Java classes. This can be done by giving the SocketConnection
itself a class JavaClass which can be used for providing wrappers to
other Java classes as well:
Object create JavaClass
JavaClass create SocketConnection
SocketConnection create Connection3
This feature is actually quite important when using Frag for model-driven software
development, and other use cases where models, meta-models, meta-meta-models, etc. must
be represented in Frag: For all meta-levels the same base language syntax, as well
as all the predefined features of Frag like inheritance, can be used and
the number of meta-levels is not restricted
in any sense.
In Frag, each object can have multiple classes. Consider a simple example:
we want to log the invocations of Connection3 using the class ConnectionLogger.
This class can be added to Connection3 by adding it to the existing class
SocketConnection using the method classes. classes can be used to
dynamically change the classes of an object at any time:
Connection3 classes ConnectionLogger SocketConnection
Now Connection3 has two classes, ConnectionLogger and SocketConnection. Later
on you can drop the ConnectionLogger class again:
Connection3 classes SocketConnection
In Frag each class can also have one or more superclasses. Superclasses are
defined for a class using the method superclasses. The superclass relationship
is also dynamic, and can be changed at any time. Per default, each class has the
superclass Object. This class does not have to be explicitly provided as a superclass,
but it is automatically assigned.
For instance, if we want to provide a class for logged connections, we can provide the
two classes ConnectionLogger and SocketConnection as superclasses:
Object create LoggedSocketConnection -superclasses ConnectionLogger SocketConnection
Multiple superclasses can be used to implement the concept of multiple
inheritance in a dynamic fashion.
Each Frag object can have any other object as its class by providing it in
its classes relationship. Among these classes the object itself can be listed.
That simply means that the object (and its superclasses) are also searched during
the search for methods. This is for instance useful when only one instance of the
class is existing (a "Singleton") or when we need to have access to the class before an
instance is created (this is similar to accessing a static method in Java). A prominent example of such a
class is Object that has only the class Object. Object itself defines the
method create, for instance. Create would not be resolved on Object, if Object
would not be on its own class hierarchy.
As another example, consider a Factory object. We want to be able to derive objects with a
method new directly from it, but we do not want to instantiate the Factory,
as it is needed only once in the system. Hence, we add it to its own class list:
Object create ConnectionFactory
ConnectionFactory method new {name} {...}
ConnectionFactory classes ConnectionFactory
...
# "new" is resolved via the self object used as a class
ConnectionFactory new a
ConnectionFactory new b
Because Frag is designed for runtime composition, an important goal is to be
able to find out about the current composition and state of the objects at any time.
Therefore Frag is designed as a fully reflective language, offering
introspection options for each language element and feature it introduces.
Introspection of objects is realized via ordinary, predefined instance methods,
especially of Object (introspection of features of an object) and interp
(introspection of features defined for the whole interpreter, such as all objects).
Introspection options have - as a convention - a name starting with "get" like "getClasses"
or are worded as a question like "isType".
Examples for introspection options follow in the next section.
For all predefined introspection options, see Sections Object: Method Reference and
Accessing the Interpreter.
There are rich introspection
options, defined for the object and class relationships, introduced before
(see the instance methods of Object defined in Section Object: Method Reference).
For example, we can ask an object for its current classes using getClasses.
In the example above:
Connection3 getClasses
would return:
ConnectionLogger SocketConnection
A sometimes handy short-cut is getClass, which returns the first class in
an object's class list. Typically the first class is the one that is used during create
to derive the object.
Consider you want to add a ConnectionLogger to an object using classes.
Hard-coding class names might overwrite other extensions and thus this is not a
good solution. With the introspection option classes, we can add the
ConnectionLogger by appending it and the current classes (without
knowledge of their current value):
Connection3 classes ConnectionLogger [* Connection3 getClasses]
Please note that the "[* ...]" substitution uses the expand syntax explained
in Section Expand Syntax.
In the same way as above, we can ask a class for its superclasses using getSuperclasses.
In the example above:
LoggedSocketConnection getSuperclasses
would return:
ConnectionLogger SocketConnection
In Frag, in addition to the classes and superclasses relationships,
there is an additional relationship of objects that provides a type for an object:
mixins. Each class can have one or more mixins. Mixins are
defined for a class using the method mixins. The mixin relationship
is dynamic and can be changed at any time. Per default, a class has no mixins.
For instance, if we want to log a connection class, we can provide a class
ConnectionLogger as a mixin:
Object create SocketConnection \
-superclasses Connection -mixins ConnectionLogger
The mixin relationship is almost identical to the superclasses relationship,
except that all mixins are invoked before the class itself and its superclasses
are invoked. That is,
when a method invocation is dispatched,
ConnectionLogger is searched before SocketConnection and Connection.
As a consequence, the mixin's methods overshadow
all methods of the class and the superclasses. Hence, the mixin can be used to
intercept method invocations
of the class that it is mixed on. This is especially useful in combination with the
command next (see Section The "next" Command), which allows
you to implement around, before, and after interception of messages, as it can
for instance also be found in AOP languages and frameworks.
For more on the dynamic mixin concept in general see the Document
Object-based and class-based composition of transitive mixins.
More details of mixins in Frag are provided in Section Class Hierarchy and Class Path Linearizing.
<objID> append <variableName> ?new elements ...?
append appends an arbitrary number of new elements to a given list stored in
the object's variable variableName.
The following code returns the list a b c 0 2:
Object create o
o set a {a b c}
o append a 0 2
o get a
<objID> classes <class1> ?... classN?
classes defines a number of classes for objID. Existing
classes are overwritten. Hence classes dynamically changes
the classes of a class. <class1> ?... classN? must be existing classes; if one
of those classes does not exist, an error is raised.
An object must have at least one class. The class an object is created
from is given to it upon creation. That is, each object has after creation exactly
one class. You can use classes to add more classes or change the classes.
In the following code, Q is created from Object and directly afterwards,
two classes are assigned to Q. Then the class list is printed.
Afterwards, the classes are removed, by re-classing to Object.
Object create O
Object create P
Object create Q -classes O P
puts "classes of Q: [Q getClasses]"
Q classes Object
puts "classes of Q: [Q getClasses]"
<objectID> configure <configure args> ?more configure args ...?
configure is internally used by create
(see Section create) to invoke the
configure arguments (see Section Configure Arguments).
configure can be used to access this configuration mechanism on
an existing object (without creating a new object).
The following code performs a configuration, which calls set two times
as a configure argument on an object. The values of the
variables that have been set are then read using get:
Object create x
# do something else and then late configuration
# ...
x configure -set r 15 -set x 13
puts "var values: r=[x get r], x=[x get x]"
<objID> create ?objectName? ?additional args ...?
create creates a new instance of the class objID. If objectName
is given a named object is created. If objectName is omitted, an unnamed
object is created. For details about object creation see Section
Object and Class Concept.
create can take an arbitrary number of additional args, which are
treated as configure arguments, starting with -. See Section
Configure Arguments for more details on configure
arguments.
The following code creates an instance x of the class Object, and
invokes set two times as a configure argument. The values of the
variables that have been set are then read using get:
Object create x -set r 15 -set x 13
puts "var values: r=[x get r], x=[x get x]"
<objID> defaults <defaultList>
defaults defines - on a class - default values for variables for the class'
instances. The variable slots are created during object creation of the instance.
If a class needs to predefine variables to be set for all of its instances, we can use
the defaults method, as in the following example:
Object create D -defaults {
aScalar 1
aList {}
}
The above defaults statement specifies that whenever an instance of D is created,
this instance gets a scalar variable aScalar with the default value 1, as well as an
empty list variable aList.
<objID> deleteMethod <methodName>
deleteMethod deletes a method dynamically from an object.
methodName must be an existing method
of the class objID.
The following code creates a trace method for creation of objects on Object.
As this method might be called rather often, it is advisable to remove it
once the debugging output is not needed anymore.
Object method init args {
puts "[callstack class] [callstack method]"
next
}
# ...
# when not needed anymore: discard the method
Object deleteMethod init
<objID> get <var>
get reads an object variable var and returns
its value. If the variable does not exist, get throws an error.
The following code sets a variable on object o and then reads it using
get:
Object create o
o set r 1
puts "value of r: [o get r]"
<objID> getArgs <methodName>
getArgs returns the list of arguments of the method methodName.
The following example returns the list of arguments of a method (i.e., the
list a b c):
Object create O
O method m1 {a b c} {puts "$a $b $c"}
puts "args of m1: [O getArgs m1]"
<objID> getBody <methodName>
getBody returns the body (i.e., the code) of the method methodName.
The following example returns the body of a method (i.e., the
puts statement in the body of m1):
Object create O
O method m1 {a b c} {puts "$a $b $c"}
puts "body of m1: [O getBody m1]"
<objID> getClass
getClass is a short form of getClasses, returning just the first
class of an object (typically the one used to create an object).
The following code just prints X1, the first class in the class list of O.
Object create X1
Object create X2
Object create Y1
Object create O -classes X1 X2 Y1
puts "[O getClass]"
<objID> getClasses ?-options ...? ?pattern?
Options: -all or -direct
getClasses returns the list of all classes defined for the object
objID. It
takes an optional pattern argument, which performs a pattern matching on the
list of classes before returning it, as its last argument (for details on pattern matching see Section
Pattern Matching). Per default, or when the option -direct is
chosen, only the direct classes are returned. -all returns the list of all direct and indirect classes
defined for the object objID (computed recursively).
The following code creates three objects and makes them classes of object O.
Then O is queried for its classes, which returns: X1 X2 Y, and all
classes starting with X, which returns X1 X2.
Object create X1
Object create X2
Object create Y
Object create O -classes X1 X2 Y
puts "[O getClasses], [O getClasses X*]"
The following code creates three objects and makes them classes of object O. One
of those objects has a superclass S1.
Then O is queried for all its direct and indirect classes, which returns: X1 S1 X2 Y1 Object,
including all superclasses (S1 and Object). The query for all
classes starting with X, returns X1 X2.
Object create S1
Object create X1 -superclasses S1
Object create X2
Object create Y1
Object create O -classes X1 X2 Y1
puts "[O getClasses -all], [O getClasses -all X*]"
<objID> getConfigureArg <variableName> <configureArg> ?cutTheArg?
getConfigureArg is a helper method that reads configure argument
syntax elements from a variable variableName. Optionally, the configure argument can
be cut from the variable variableName.
In the following example, configure is overloaded and an additional
configure argument -debug is introduced. A debugger is informed
if a widget has this option. However, as there is no method debug on
Widget defined, to avoid an error we must cut the configure arg from the args variable
before passing its content on using next.
Object create debugger -set widgetList {}
Object create Widget
Widget method configure args {
if {[catch {self getConfigureArg args "-debug" 1}] == ""} {
debugger append widgetList [self]
}
next
}
Widget create w
w configure -set color blue -set backgroundColor black -debug 1
Widget create v
v configure -set color blue -set backgroundColor black
<objID> getDefaults
getDefaults returns the default values that a class defines for its instances, see
Section defaults.
The following code prints the list of defaults defined for D as a list. The result
is a 1 {a b } 2 {a b c} {1 2 3}.
Object create D -defaults {
a 1
"a b " 2
"a b c" {1 2 3}
}
puts "[D getDefaults]"
<objID> getInstances ?-options ...? ?pattern?
Options: -all or -direct
getInstances returns the list of all instances defined for the object
objID. It
takes an optional pattern argument, which performs a pattern matching on the
list of instances before returning it (for details on pattern matching see Section
Pattern Matching). Per default, or when the option -direct is
chosen, only the direct instances are returned. -all returns the
list of all direct and indirect instances
defined for the object objID (computed recursively).
The following example shows an object O which has three instances: two created
by O and one acquired by re-classing. The list of instances is x1 x2 y1. All
instances starting with x are x1 x2:
Object create O
O create x1
O create x2
Object create y1
y1 classes O
puts "[O getInstances], [O getInstances x*]"
The following code creates a number of instances from S1. All except for
O are included in the allInstances list, because O is reclassed to Y1
and hence not an instance of S1 anymore. The two instances created from X1
are also included because X1 is subclass of S1 and hence c1 and c2 are
indirect instances of S1. The result of all instances is X1 X2 Y1 c1 c2.
X1 X2 is the sub-list that starts with X.
Object create S1
S1 create X1 -superclasses S1
S1 create X2
S1 create Y1
S1 create O -classes Y1
X1 create c1
X1 create c2
puts "[S1 getInstances -all], [S1 getInstances -all X*]"
<objID> getMethods ?pattern?
getMethods prints the list of all methods defined for an object. It
takes an optional pattern argument, which performs a pattern matching on the
list of methods before returning it (for details on pattern matching see Section
Pattern Matching).
The following code defines an object with 3 methods. Next it prints
the list of all methods and then all methods starting with x. The result is:
{x2 x1 y1} {x2 x1}.
Object create O
O method x1 {} {;}
O method x2 {} {;}
O method y1 {} {;}
puts "[O getMethods] [O getMethods x*]"
<objID> getMethodType <methodName>
Each method has a method type, which indicates how the method is internally
implemented (using which Java class). All user-defined methods have the type FragMethod.
The Java-defined methods are of the type JavaMethod.
getMethods allows you to query the method type information.
The following code returns FragMethod JavaMethod because x1 is a
user-defined method, and Object's
set is implemented in Java.
Object create O
O method x1 {} {;}
puts [O getMethodType x1]
puts [Object getMethodType set]
<objID> getMixinOf ?-options ...? ?pattern?
Options: -all or -direct
getMixinOf returns the list of all classes which have
objID defined as a mixin. It
takes an optional pattern argument, which performs a pattern matching on the
list of subclasses before returning it (for details on pattern matching see Section
Pattern Matching). Per default, or when the option -direct is
chosen, only the classes who have objID as direct mixin are returned. -all
returns the list of all direct and indirect classes who have objID as mixin
(computed recursively).
The following code creates a mixin hierarchy and first prints all classes S1 is direct mixin of,
which are X1 X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -mixins S1
Object create X2 -mixins S1
Object create Y1 -mixins S1
Object create O -mixins X1
puts "[S1 getMixinOf], [S1 getMixinOf X*]"
The following code creates a mixin hierarchy and first prints all classes S1 is
direct or indirect
mixin of, which are X1 O X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -mixins S1
Object create X2 -mixins S1
Object create Y1 -mixins S1
Object create O -mixins X1
puts "[S1 getMixinOf -all], [S1 getMixinOf -all X*]"
<objID> getMixins ?-options ...? ?pattern?
Options: -all or -direct
getMixins returns the list of all mixins
defined for the object
objID. It
takes an optional pattern argument, which performs a pattern matching on the
list of superclasses before returning it (for details on pattern matching see Section
Pattern Matching). Per default, or when the option -direct is
chosen, only the direct mixins are returned. -all
returns the list of all direct and indirect mixins
defined for the object objID (computed recursively).
The following code creates a mixins hierarchy and first prints all the direct
mixins of O, which are X1 X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -mixins S1
Object create X2
Object create Y1
Object create O -mixins X1 X2 Y1
puts "[O getMixins], [O getMixins X*]"
The following code creates a mixins hierarchy and first prints all direct and indirect
mixins of O, which are X1 S1 X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -mixins S1
Object create X2
Object create Y1
Object create O -mixins X1 X2 Y1
puts "[O getMixins -all], [O getMixins -all X*]"
<objID> getNextPath ?pattern?
getNextPath calculates the next path of an object following the
class path linearization rules described in Section Class Hierarchy and Class Path Linearizing. It
takes an optional pattern argument, which performs a pattern matching on the
list of classes on the next path before returning it (for details on pattern matching see Section
Pattern Matching).
The following code defines a class hierarchy and first prints the next
path of O, which is very simple - only its class Object. The next
path of o1 is O X1 S1 Object, i.e. the combination of its classes and
all the class' superclasses in the linearized order. The sub-list of this
next path, starting with X, is X1.
Object create S1
Object create X1 -superclasses S1
Object create X2 -superclasses S1
Object create Y1 -superclasses S1
Object create O -superclasses X1
O create o1
puts "[O getNextPath] [o1 getNextPath] [o1 getNextPath X*]"
<objID> getObjectID
getObjectID returns the object ID (i.e., the Dual Value) of the object (see
Section Duals). You can also use getObjectID to
explicitly transform a string into an object reference.
The following code preserves an object before an unname:
Object create A
set r [A getObjectID]
A unname
The following code transforms a given string list into an object list:
set stringList {Student Lecturer}
Object create Student
Object create Lecturer
Object create joe -classes Student Lecturer
set newList ""
foreach str $stringList {
# the references are now preserved in "newList"
append newList [$str getObjectID]
}
Lecturer unname
puts "New List: $newList"
As newList contains references, the result looks like:
New List: Student %%1
<objID> getRefCount
getRefCount is a helper method for debugging and inspecting
garbage collection.
It prints the current reference count of an object. It might get removed
in future versions of Frag.
The following returns the reference count of an object:
Object create o
o getRefCount
<objID> getSubclasses ?-options ...? ?pattern?
Options: -all or -direct
getSubclasses returns the list of all subclasses
defined for the object
objID. It
takes an optional pattern argument, which performs a pattern matching on the
list of subclasses before returning it (for details on pattern matching see Section
Pattern Matching). Per default, or when the option -direct is
chosen, only the direct subclasses are returned. -all
returns the list of all direct and indirect subclasses
defined for the object objID (computed recursively).
The following code creates a superclass hierarchy and first prints all direct
subclasses of S1, which are X1 X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -superclasses S1
Object create X2 -superclasses S1
Object create Y1 -superclasses S1
Object create O -superclasses X1
puts "[S1 getSubclasses], [S1 getSubclasses X*]"
The following code creates a superclass hierarchy and first prints all direct and indirect
subclasses of S1, which are X1 O X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -superclasses S1
Object create X2 -superclasses S1
Object create Y1 -superclasses S1
Object create O -superclasses X1
puts "[S1 getSubclasses -all], [S1 getSubclasses -all X*]"
<objID> getSubtypes ?pattern?
getSubtypes returns the list of all direct and indirect subtypes
of the object objID (computed recursively). This includes the direct and indirect
subclasses, as well as the direct and indirect classes objID is mixin of.
getSubtypes
takes an optional pattern argument, which performs a pattern matching on the
list of subtypes before returning it (for details on pattern matching see Section
Pattern Matching).
The following code creates a superclass and mixin hierarchy and first prints all direct and indirect
subtypes of S1, which are X1 O X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -mixins S1
Object create X2 -superclasses S1
Object create Y1 -superclasses S1
Object create O -superclasses X1
puts "[S1 getSubtypes], [S1 getSubtypes X*]"
<objID> getSuperclasses ?-options ...? ?pattern?
Options: -all or -direct
getSuperclasses returns the list of all superclasses
defined for the object
objID. It
takes an optional pattern argument, which performs a pattern matching on the
list of superclasses before returning it (for details on pattern matching see Section
Pattern Matching). Per default, or when the option -direct is
chosen, only the direct superclasses are returned. -all
returns the list of all direct and indirect superclasses
defined for the object objID (computed recursively).
The following code creates a superclass hierarchy and first prints all the direct
superclasses of O, which are X1 X2 Y1, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -superclasses S1
Object create X2
Object create Y1
Object create O -superclasses X1 X2 Y1
puts "[O getSuperclasses], [O getSuperclasses X*]"
The following code creates a superclass hierarchy and first prints all direct and indirect
superclasses of O, which are X1 S1 X2 Y1 Object, and then
the sub-list starting with X, which is X1 X2.
Object create S1
Object create X1 -superclasses S1
Object create X2
Object create Y1
Object create O -superclasses X1 X2 Y1
puts "[O getSuperclasses -all], [O getSuperclasses -all X*]"
<objID> getSupertypes ?pattern?
getSupertypes returns the list of all direct and indirect superclasses, as well as
all direct and indirect mixins,
of the object objID (computed recursively). The result is identical to the list of
all mixins (as returned by getMixins -all) preprended to the list of all superclasses
(as returned by getSuperclasses -all), if there is no overlap between the two lists.
If a class occurs on both lists, it is only once in the list returned by getSupertypes.
getSupertypes
takes an optional pattern argument, which performs a pattern matching on the
list of superclasses before returning it (for details on pattern matching see Section
Pattern Matching).
The following code creates a superclass and mixins hierarchy and first prints all direct and indirect
superclasses and mixins of O, which are X1 S1 X2 Y1 Object, and then the sub-list starting with X,
which is X1 X2.
Object create S1
Object create X1 -mixins S1
Object create X2
Object create Y1
Object create O -superclasses X1 X2 Y1
puts "[O getSupertypes], [O getSupertypes X*]"
<objID> getVars ?pattern?
getVars prints the list of all instance variables defined
for an object. It
takes an optional pattern argument, which performs a pattern matching on the
list of variables before returning it (for details on pattern matching see Section
Pattern Matching).
The following code defines an object with 3 variables. Then it first prints
the list of all variables and next all variables starting with x. The result is:
{x2 x1 y1} {x2 x1}.
Object create O
O set x1 1
O set x2 2
O set y1 3
puts "[O getVars], [O getVars x*]"
<objID> isType <className>
isType checks whether objID is direct or indirect instance of className.
If this is true, isType returns true, otherwise false.
The following code prints: false true true true true false because O is not of type X1, but of type
Object. o1 is of type O, S1, and X1, but not of type X2.
Object create S1
Object create X1 -superclasses S1
Object create X2 -superclasses S1
Object create Y1 -superclasses S1
Object create O -superclasses X1
O create o1
puts [list build [O isType X1] [O isType Object]
[o1 isType O] [o1 isType S1]
[o1 isType X1] [o1 isType X2]]
<objID> method <methodName> <args> <body code>
method is used for dynamically defining a method. Methods are explained
in Section Methods.
A method is created on a class B and invoked on an instance b of class B:
Object create B
B method m2 {a b c} {
return [list build ($a + 1) $b $c]
}
B create b
puts "Invocation result: [b m2 2 2 2]"
<objID> mixins ?<class1> ... <classN>?
mixins defines a number of classes as mixins for objID. Existing
mixins are overwritten. Hence mixins dynamically changes
the mixins of a class. ?<class1> ... <classN>? must be existing classes; if one
of those classes does not exist, an error is raised.
A class has initially an empty mixin list.
The following code puts two classes as mixins on Q and prints the mixins list.
After this all the mixins are removed, by providing an empty mixins list.
Object create O
Object create P
Object create Q -mixins O P
puts "mixins of Q: [Q getMixins]"
Q mixins
puts "mixins of Q: [Q getMixins]"
<objID> rename <objectName>
rename renames an object by registering it under a new name in the interpreter.
In the following example code, we first create an object o and then rename it
to o1. Hence, o set r 1 does not work anymore after renaming, but o1 set r 1
and o1 getClasses.
Object create C1
C1 create o
o rename o1
set e1 [catch {o set r 1}]
puts "Invocations on o1: [o1 set r 1] [o1 getClasses]"
<objID> renameMethod <methodName> <newMethodName>
renameMethod renames a method dynamically.
methodName must be an existing method
of the class objID. The method is is dynamically renamed to newMethodName.
The following code renames a method to a new name:
Object create ForRename
ForRename method y {} {;}
ForRename renameMethod y a
puts "methods: [ForRename getMethods]"
<objID> set <var> <value>
set writes an object variable var and sets its value to the given
value argument. set returns the value.
The following code sets a variable on object o using set
and then reads it using get:
Object create o
o set r 1
puts "value of r: [o get r]"
<objID> superclasses <class1> ?... classN?
superclasses defines a number of classes as superclasses for objID. Existing
superclasses are overwritten. Hence superclasses dynamically changes
the superclasses of a class. <class1> ?... classN? must be existing classes; if one
of those classes does not exist, an error is raised.
An object must have at least one superclass. If no superclass is given upon creation,
Object is assigned as superclass. Hence, you cannot re-superclass to nothing, but the equivalent
to removing all superclasses from an object is to re-superclass it to Object.
The following code puts two classes as superclasses on Q and prints the superclass list.
Afterwards, the superclasses are removed, by re-superclassing to Object.
This is also the superclass of the "plain" objects, like O or P, which
have no special superclasses assigned.
Object create O
Object create P
Object create Q -superclasses O P
puts "superclasses of Q: [Q getSuperclasses]"
Q superclasses Object
puts "superclasses of Q: [Q getSuperclasses]"
puts "superclasses of O: [O getSuperclasses]"
<objID> unname
unname tells the interpreter to forget the name of an object.
create can create objects with or without name
(see Section create). An object name is like a
reference to the object. If the object has no reference, it gets
garbage collected. Hence, unname can be used to dispose named objects,
once they are no longer needed.
Unnamed objects have an automatically assigned ID, of the form: %%number,
such as %%12. Once unname is called on an object, its name is forgotten,
and it gets an automatically assigned ID, which is returned by unname.
Calling unname on an object without name causes an error.
The code below creates a named object a, which is preserved only because
of its name, but which has no further references. Then unname is called
and hence the object gets garbage collected. The name a does not exist
anymore, and hence the invocation a aMethod 2 causes an error.
Object create a
a unname
set e [catch {a aMethod 2}]
<objID> unset <var1> ?... varN?
unset deletes one or more variables from the object's
variable table. It throws an error, if the variable does not exist
on the object.
The following code first creates four variables on object o.
Then three of these variables get deleted by unset; hence only
the variable x1 remains:
Object create o -set x 3 -set y 4 -set z 5 -set x1 4
puts "Vars on o: [o getVars]"
o unset x y z
puts "Vars on o: [o getVars]"
<objID> varExists <varName>
varExists tests whether a variable varName exists as an instance
variable on object objID and returns true, if it exists, and false
otherwise.
The following example prints true, false because x is an instance variable of O,
but y is not:
Object create O
O set x 1
puts "[O varExists x], [O varExists y]"