Getting Started
In order to make the functionality of the package available, we first load it with
Needs. The package may also be loaded with
Get (
<<filename,
Get[filename], or
Get[context]). All created objects and classes can be saved with
Export that automatically bundles a runtime version with saved class definitions.
| Out[1]= |  |
The main function of the package is called
Class. It generates all classes, the interfaces are generated by
Interface. The next example shows a simple class that contains one field to store state information and two methods. The output is formatted specially and shows that a parameterless constructor
base[] was automatically added, because there is no user defined constructor. All object constructors are used to initialize objects generated with this class. There is also an optional class constructor
Static[]. A special treatment of members not found within the class is also appended to the class. Members are formatted with
Short.
Out[2]//TableForm= |
| |  |
The state
st is redirected automatically to another data structure in order to be able to bind it to an object rather than to the class itself. The reference to the state is automatically qualified with
This. Additionally, some parameters were renamed without affecting the behavior of the class. We are now ready to create a first object by means of
New. The name of the newly created symbol always adds to
$ObjectPrefix a number
$ObjectNumber and is formatted specially. Please observe the
Dot operator after
New.
| Out[3]= |  |
The value created by
New can be considered as a pointer to an object. It is created in the current context. Members of the class are also accessed by means of the
Dot operator. There is a mechanism to find class members analogous to the menu command . If you type
baseObj.f and then hit
Ctrl+K (twice for plain text cells), you get all members listed that start with
f. For details see
ClassTemplates.
| Out[4]= |  |
Because the state field
st is zero, no special effect is observed. This changes after another state has been assigned and the method is called again with the same parameter.
| Out[6]= |  |
A newly generated object would start with zero for the field
st, which can be checked by means of the list
ObjectInitializations[class]. During object creation,
This is replaced automatically with the current object.
| Out[7]= |  |
Let us continue with inheritance. Implicitely we already used it, because any class that is not derived from a user-defined class inherits from the class
Object that has neither fields nor methods defined. We create a class that derives from the
base already defined. The specially formatted output shows automatic constructor chaining, a
child calls the initialization of its parent. The search for nonfound class members now takes place in the parent
base.
Out[8]//TableForm= |
| |  |
The warning messages show that the package detected a replacement of functionality of a parent class. It does not affect the functionality.
| Out[9]= |  |
Nevertheless, it is "cleaner" to qualify such replacements with
Override followed by a
Dot operator.
Out[10]//TableForm= |
| |  |
The object generation and usage is the almost same as above, but the constructor is called
child.
| Out[11]= |  |
| Out[12]= |  |
In the
base class, we defined
f[x_?Positive]:=x^2, while the
child specifies
f[x_?Positive]:=x. The object automatically selects the correct method.
| Out[13]= |  |
When we try the method for negative parameters, we could be dissapointed. The definition
f[x_?Negative]:=x^3+st accesses the state
st, which is defined in the
child as
st=20. This would yield
-105. Let us try.
| Out[14]= |  |
Without specification, class members are searched for only in the class and its parents. The method for negative parameters is located in the
base class and consequently the
child class is not scanned for the state
st. If we want to get always the state that matches the object, we force polymorphism by means of
Virtual. We must apply
ClearAll either to
base or to
child in order to avoid complaints due to automatic regeneration of
child during the definition of
base.
Out[16]//TableForm= |
| |  |
Out[17]//TableForm= |
| |  |
The redefinition of the classes does not reinitialize objects already created. Therefore, if we defined a new field, we would have to regenerate an object in order to get all fields properly initialized. Here, we simply use the already created object. Polymorphism now assures that the state is used that is closest to the class that generated the object.
| Out[18]= |  |
The polymorphism also works for methods. We start with the definition of a new
base class.
Out[19]//TableForm= |
| |  |
The message is generated, because every redefinition of a class automatically regenerates all classes derived from it. In case of a failure, the class definition is cleared. Here, the
child class cannot be redefined, because of the new
Virtual qualifier of the method within
base. If we try to use a
child's object, we run into trouble, because there is no more a class definition. We wrap the call into a
Catch clause in order to avoid a
Throw::nocatch message.
| Out[20]= |  |
The
base class itself is not affected.
| Out[21]= |  |
In order to correct it, we redefine the
child class.
Out[22]//TableForm= |
| |  |
We can now use the method. The next examples use the function
f that matches the object,
f[x_?Positive]:=x^2 for
base and
f[x_?Positive]:=x for
child.
| Out[23]= |  |
| Out[24]= |  |
In the examples above, there was no way to influence the initial settings of an object. Let us now redefine the
base class such that the state field can get an initial value through a constructor. Analogous to the constructor, there is the possibility to define a cleanup routine by means of
Destructor.
Out[25]//TableForm= |
| |  |
The message is generated, because the
base class now has no parameterless constructor and the automatically generated constructor of
child during automatic regeneration of derived classes tries to use such a constructor. Because we do not need
child anymore in this section, we do not redefine it here. An object can now be generated with specific settings for the state.
| Out[26]= |  |
| Out[27]= |  |
The different settings are reflected in the method's return value.
| Out[28]= |  |
| Out[29]= |  |
A parameterless constructor no longer exists and an exception is thrown for a trial to generate an object without providing parameters to the constructor.
| Out[30]= |  |
Because all exceptions of this package use
Class as label, they can be filtered out easily, while exceptions from other code will not get filtered out.
Once in a while, the overhead of a class definition is rather big, if only a single object of a class is needed. In such cases anonymous classes may extend any other class. We use it here to add the case when the argument to
f is zero. The first line below fails, because there is no such method, while the second has the necessary pattern added. Because there is no parameterless constructor in
base, we must provide one within the extension. It has the name of the class being derived. Internally, a class is generated with a new unique name, see
ClassNumber and
$ClassNumber.
| Out[31]= |  |
| Out[32]= |  |
In bigger projects, each member should be documented directly in the class. This is achieved by means of a "string modifier" for a member.
This description is accessed by means of the menu command
(
Shift+Ctrl+K).Every class is by default formatted as button that prints a description if pressed that shows the previously defined "string modifiers". It contains also pattern information. For further examples see
ClassInformation and
ClassTemplates. Hovering over the class members shows tooltips with more information on them.
| Out[34]= |  |