If you know Java or Eiffel, you know what an object reference means. It is an pointer to a piece of object storage; so that the state of the object can be accessed through the pointer. Object storage are allocated and deleted dynamically. Both Java and Eiffel provide garbage collection to prevent memory leak. Programmers feel free to ask more and more object storage and never worry about releasing it. Dangling objects are deleted and the freed storage is collected automatically by the system.
Sounds a good idea, but not good enough.
The first problem is that the smart object reference supported by the language is very limited. It works only on the declared reference variables. Object references can be something else, for example, a handle to a system resource (either hardware or software) or a name to an object in a persistent object storage. If the language does not support smart references to these objects, programmers still have to worry about cleaning things up. An oversight may exhaust the system resource. You might already have the experience in Windows programming.
The second problem is that the "stupid" object reference is still required, for either the efficiency reason, or low-level system programming nature. Stupid object references may be static. They are not necessarily as dangerous as C/C++ pointers. They can be pointers to be statically allocated objects at compile time, link time, load time, or at the time their living environment is created; and they are deleted when the whole system, or their living environment dies. Java preserves this nature only for primitive objects, which is not enough for many application that care about the memory efficiency.
Transframe provides a generic object reference framework, and from which different object reference protocols can be derived as subclasses.
By default, references to primitive objects are static ones and they are assigned with values by direct copy; references to composite objects are smart ones unless you decide that they must be statically allocated.
Transframe enables user to define their own object references to deal with issues like system resource or persistent objects. Here is an example.
class Handle is Refential #(ObjectType: type of OSResource)
{
function operator.(): ObjectType;
// get the object referred by the handle
function operator share (Handle);
// operator used by share reference assignmnet
enter() // constructor
{ // create the resource and return the handle
};
exit() // destructor
{ // collect the resource (may use the similar GC techinique
};
};
class PaintWindow is Window
{ private:
my_brush: Handle of Brush; // or Handle#(Brush)
my_canvas: Handle of Canvas;
public:
function paint ()
{
with (my_brush)
{ setStyle (Crayon);
setColor (NavyBlue);
}
// paint something with the brush on the canvas
};
enter () : Window() // constructor
{
my_brush := (Handle of Brush) (); // create a brush
my_canvas := (Handle of Canvas) (); // create a canvas
}
};
Note that setStyle and setColor are member functions (classes) defined in the class Brush. Using "." operator, we get the object pointed by the reference, and then select the member of the object:
my_brush.setStyle(Crayon)In Transframe, operators like &, *, -> are not required. There is no tricky C++ expressions like "&(**x)->foo()". There is no confusion between expressions "new C()" and "C()". There is no need to "delete". There is even no need to "finalize" for high-level users. Object references of all types have a simple and uniform interface for usage; in general, only ":=" for assignment, and "." for member selection.
More examples: