Attributes and Interfaces
One advantage of object oriented programming is information hiding. Part of this concept is the ability to restrict the access to members of a class. The next example defines four methods with different access rules, but the first two that are identical, because a nonqualified class member is implicitly
Public.
The first two methods may be accessed directly, the next two not. The last method calls a private method within the same class, which is allowed. This example is not useful with respect to encapsulation, but it shows the effect of a
Private and a
Protected member access.
| Out[4]= |  |
| Out[5]= |  |
| Out[6]= |  |
| Out[7]= |  |
| Out[8]= |  |
Any attempt to access a private member from outside the class is rejected.
| Out[9]= |  |
If an object tries to access a private member, the access violation is detected during the usage of the class. This cannot be done during the definition of a class, because a symbol in
Mathematica may hold any contents. Thefore, it would be necessary to process the logic inside the class methods during the definition of the class in order to discover all kinds of accesses to class members.
| Out[11]= |  |
A child class may use the
Protected member. The next example effectively evaluates the private method
g in the
base class.
| Out[14]= |  |
A member of the class may also be bound to the class rather than to an object generated with the class. The modifier
Static designates such a binding. We take the examples from above, but add this modifier.
There is no need to generate an object, because the class contains only static members. Again, nonpublic members may not be accessed.
| Out[16]= |  |
| Out[17]= |  |
| Out[18]= |  |
| Out[19]= |  |
| Out[20]= |  |
As expected, the
Private member of the base class is not accessible.
| Out[21]= |  |
Nondirect accesses afford checks during runtime.
| Out[23]= |  |
Protected members may be used in a derived class.
| Out[25]= |  |
The concept of an interface can be achieved for example by means of the
Abstract modifier. The next example shows that even globally defined functions may check the correct types of their arguments by means of
InstanceOf. We qualify the method with
Override in order to show that we are aware of redefining functionality of a parent class. This avoids a warning message.
| Out[29]= |  |
If all methods within a class are abstract, it is better to create an
Interface instead, because a class may inherit only from a single class, but from many interfaces. Additionally, the separation from a class is somehow "cleaner" with respect to design. Usually, interface members need not to be qualified, they are implicitly abstract. The next example shows that an object is an instance of all classes and interfaces declared during the definition of the class the object is generated from. Accordingly, the object has access to all non-restricted definitions made in these classes and interfaces. The message is generated during the automatic regeneration of
child during the definition of
base. Since
child is redefined in the line directly below, it does not have an effect here.
| Out[35]= |  |
| Out[36]= |  |
The chain of inheritance can be "terminated" by means of the modifier
Final. Any class member that is qualified with this modifier cannot be changed by a subclass. The next example shows such a case. We must clear
base before, because, during the definition of
base, all subclasses of
base are regenerated in order to keep them up to date. This regeneration would fail, because the member
f is final.
| Out[39]= |  |
If a complete class is qualified with
Final, no other class may inherit anything from it.
| Out[42]= |  |
If you need a method that is not allowed to change an object use
Constant and, if appropriate,
Mutable.
Polymorphism is achieved by means of the
Virtual modifier and can be discontinued with
Real. The next two classes define a field and a method bound to an object as well as to the class in non-polymorphic and polymorphic flavors.
An object's class controls what polymorphic member to use, while other members are controlled by the point in code they are accessed from. A "v" in a member`s name below tells that the member is virtual, while an "s" stands for a static binding. The results show that the concept of polymorphism is also applied to class bound members.
Out[45]//TableForm= |
| |  |
Out[46]//TableForm= |
| |  |
Comfortable handling of fields can be achieved by means of the
Property qualifier. A field
prop marked with
Property automatically uses
getProp[] to read the property and
setProp[value] to evaluate the assignment
prop=value. This allows for example to control the allowed values for
prop without coding the check at every place where
prop gets a new value. In the next class, a property shows an incremented value when read out and a warning when set. We use
Static members to avoid the generation of an object.
Every time the property is used, a new value is generated. An assignment is not possible.
| Out[48]= |  |
| Out[49]= |  |
A few other modifiers are also allowed.
| Out[50]= |  |
Here is a simple class that make use of
HoldAll. We must clear
base, because the automatic regeneration of
child would otherwise cause complaints about
Override qualifiers.
Because of the
Static attribute, the methods are accessed through the class name.
| Out[53]= |  |
| Out[54]= |  |
Finally, the modifier
Transient controls what is exposed during an
Export of objects and classes.