Diamond 4.0.0

(c) March 2004 by Michael A. Nelson

MichaelANelson@worldnet.att.net

 

 

TABLE OF CONTENTS

 

WHAT IS DIAMOND?

Diamond is a collection of routines written in the Euphoria programming language. It is intended to allow programmers to use object-oriented programming in Euphoria, by allowing the definition of classes, and the creation and use of objects based on these classes.

Diamond was designed to be powerful and secure, even at the cost of complexity. Diamond is intended for the advanced OOP programmer.

 

FEATURES OF DIAMOND

 

INTRODUCTION TO OBJECT ORIENTED PROGRAMMING IN DIAMOND

The fundamental concept of object-oriented programming (OOP) is the object. An object may be thought of as a semi-independent program containing data (properties) and routines (methods). An object represents an entity: a truck, a checking account, a character in a role-playing game, etc. Properties represent attributes of these entities: a truck's weight limit, a checking account's balance, a character's experience points. Methods represent actions performed by or on the entity: a truck turns, a check is debited to a checking account, and a character attacks a monster. One common way of expressing this it an object consists of its state (properties) and its behavior (methods).

Diamond also supports events. Events may be regarded as a specialized form of methods.

Because "object" is a Euphoria data type, from here on an object in the OOP sense above will be called an "entity".

Classes are types of entities: trucks, checking accounts, characters. Classes are blueprints for the creation of entities. Classes may also have properties and methods: attributes and actions pertaining to the whole class rather than to a particular entity. The simplest example would be a class property used as a counter to determine the number of entities of that class which have been created.

In Diamond, classes are also entities. When the distinction is important, an entity which is not a class will be called an "instance entity" or just an "instance".

A class may be derived from another class and inherit properties, methods, and events from that class. The class derived from is called a superclass; the derived class is called a subclass. For example, if there is a class Car, you could define Police_Car as a subclass of Car, inheriting all the properties, methods, and events of Car and adding new properties, methods, and events to represent attributes and actions of police cars which do not apply to normal cars.

Inherited properties and events may not be redefined by a subclass. Inherited methods may be redefined by a subclass with certain restrictions.

In OOP terminology, the kind of redefinition above is called "overriding". Diamond also supports method "overloading", which refers to defining more than one method with the same name in a class, but with different parameters.

 

PROGRAM CONTEXT

Diamond defines four program contexts--main program, class definition, method, and event. Your Diamond program begins in main program context, and returns to main program context when a class definition ends or a method called or an event raised in main program context returns. Class definition context means a class definition is in progress. Method context means a method is currently executing, event context means that an event handler is currently executing.

Program context is important for determining access rights. Many Diamond routines can only be used in certain program contexts. Also, some Diamond routines are not allowed if an exception is pending. For information on specific routines, see the alphabetical listing.

 

POLYMORPHISM

There are various definitions of polymorphism. The definition used in Diamond is as follows: Assume Alpha is a class and Beta is a subclass of Alpha. Whenever an Alpha instance or the Alpha class may be used, a Beta instance or the Beta class may be used in its place. The definition is not reversible: it may be possible to use an Alpha instance or the Alpha class in place of a Beta instance or the Beta class, but this is not required.

Certain rules follow logically from the definition:

1.      If Alpha is a normal class, Beta cannot be an abstract class.

2.      If an Alpha method is a normal method, Beta may not override the method as an abstract method.

3.      If Beta overrides an Alpha method, the Beta method must not have more restrictive access than the overridden Alpha method.

 

ENTITIES

An entity consists of two parts--a handle and a value. The handle is a reference with which the value may be manipulated by Diamond. Internally, a handle is a three-integer sequence. The first element indicates the class, the second indicates the location in the local sequence in which Diamond maintains the values of all instance entities (or 0 if the entity is a class), the third is Euphoria's largest negative integer. The chance of normal data reproducing this by chance is virtually zero, so if entity(x) returns TRUE, x is an entity. However, sequence(x) will of course also return TRUE.

Because an entity is a reference, x=y where x and y are entities results in only the handle being copied, x and y share the same internal data and a change in one will result in a change in the other. To make an actual copy of an entity, use the entity's clone method.

 

CLASSES

Diamond defines six types of classes: normal classes, final classes, abstract classes, interfaces, exceptions, and null class. Interfaces and exceptions are special classes described below.

Diamond provides a universal base class named Entity with special methods inherited by every normal, final, or abstract class. Entity has no superclass; all other normal, final, and abstract classes must have exactly one superclass.

 

NORMAL CLASSES

Normal classes are the most common classes in Diamond. Instances of a normal class can be created. A normal class can be the superclass of a derived class.

 

FINAL CLASSES

Instances of a final class can be created. Final classes cannot be the superclass of a derived class. Final classes are usually used for detailed implementation that is unlikely to need to be subclassed. Using a final class is a good idea if you use code trickery for efficiency.

 

ABSTRACT CLASSES

Instances of an abstract class cannot be created. An abstract class can be the superclass of a derived class. Abstract classes are fairly useless except for use as superclasses. Abstract classes are typically used for generic concepts that will be made specific by subclassing. Example: in a graphics program an abstract Shape class, with subclasses Circle, Square, Triangle, Line, etc.

NULL CLASS

There is only one null class (Null_Class), which has no properties, methods, or events. No instances can be created but a single pre-created instance is provided: Null_Instance. This class is used for error reporting, typically as a return value.

 

INNER CLASSES

A normal, final, or abstract class may be defined within the class definition of another normal, final, or abstract class. The class defined inside the other class is an inner class; the class within which the inner class is defined is an outer class. Inner classes may be nested so that a class may be both an inner class and an outer class.

A normal or abstract inner class may be the superclass of another class, but only if the other class is defined within the same outer class as the superclass.

For the purpose of access rights an outer class can access its inner classes' properties, methods, and events as if the outer class were a superclass of the inner classes; and an inner class can access the properties, methods, and events of its outer class as if it were a subclass of the outer class.

Inner classes replace the Extended_Access interface in Diamond 3.3.0--they accomplish the same goals and more in a safer and cleaner fashion.

 

PACKAGES

It is essential that all classes used in a program must be distinguishable from each other. A class is identified by its handle and by its name. It is no problem if classes from different sources might have the same name for their handle constants: Euphoria namespacing will resolve the issue. But for saving and restoring entities, handles cannot be used as they are dependent on the particular program and often a particular run of that program. For saving and restoring entities, the class name is used. It is entirely likely that class names will be duplicated. In order to resolve these ambiguities, Diamond implements a package concept. Classes are grouped into packages and Diamond will allow two classes with the same name to be used in a program if and only if the two classes belong to different packages. The package() procedure defines a package; any class defined from the point that package() is encountered until another package() procedure are part of that package. If a class is defined before any package procedure is encountered, it will belong to the package "Diamond Default".

 

ACCESS RIGHTS

Access rights control access to the properties, methods, and events of a class. Properties have separate read and write access, methods have a single call access, and events have separate access for linking event handlers (link access) and for raising the event (raise access). In all cases, access rights work in the same fashion, so only reading properties will be explained in detail. The three access types are:

PUBLIC: the property may be read by a method of any class or by the main program

PROTECTED: the property may be read by a method of the class which defines the property or a superclass of that class. A method of a subclass of the defining class may read the property of an entity of the subclass or of one of the subclass's subclasses, but may not read the property otherwise.

PRIVATE: the property may be read by a method of the class which defines the property or a superclass of that class.

Suppose we have four classes A, B, C, and D where B is a subclass of A, C is a subclass of B and D is a subclass of C. Class B defines three instance properties: x with public access, y with protected access, and z with private access. The main program or an unrelated class' method may read only property x. A class A or class B method can read all three properties. A class C method can read x, and can read the y property of an instance of class C or D, but cannot read the y property of an instance of B. A class D method can read x and can read the y property of an instance of D, but cannot read the y property of an instance of B or C.

Inner and outer classes are a bit more complex. Let’s say A, B, C, and D are classes where C is a subclass of A and D is both a subclass of B and an inner class of C.  A class A method or class C method has exactly the same access to a property of a class D entity: it can read any property defined in D, or any public or protected property inherited from B. A class D method (whether defined in D or inherited from B) can read a property of a class C entity exactly as if it were a method of a subclass of C: any public or protected property. A class D method can only read public properties of a class A entity.

Let’s assume that E is a subclass of D, and therefore an inner class of C. A class E method has exactly the same rights to a class A or class C property as a class D method. Let’s assume that F is a subclass of C. A method of class F can read the public and protected properties of a D or E entity.

 

PROPERTIES

Properties represent the state of an entity. In Diamond, properties have read access and write access specified separately. Properties are inherited from superclasses, but overriding is not allowed. Properties are defined as persistent or transient indicating whether of not the property can be saved and restored. See property(), get_property(), set_property(), and Saving and Restoring Entities.

 

PROPERTY ACCESSORS

The normal way of using properties in OOP languages is to make the properties private and provide public methods to access the property. Normally, there are two accessor methods per property, a getter to read the property and a setter to write it. This works well in Diamond and is essential if you will need to override the accessor in subclasses. For cases where overriding is not desired or required, Diamond also allows you to code getter and setter functions that are called automatically by get_property() and set_property() respectively.

A getter is coded as a one-parameter function: get_property() will pass the current property value to the function and return the function's return value.

A setter is coded as a two-parameter function: set_property() will pass the current property value and the new property value; the property will be set to the function's return value.

See property() for the syntax to declare accessors.

 

 

METHODS

Methods represent the behavior of an entity. There are three types of methods, normal, final, and abstract. Methods are inherited from superclasses and can be overridden. The universal base class Entity provides some special methods. See method() and call_method().

 

NORMAL METHODS

Normal methods may be defined in normal and abstract classes but not in final classes. Normal methods may be overridden in subclasses. A normal method may be overridden by another normal method or by a final method but not by an abstract method.

 

FINAL METHODS

Final methods may be defined in normal , abstract and final classes. Final methods may not be overridden in subclasses.

 

ABSTRACT METHODS

Abstract methods may be defined in abstract classes but not in normal or final classes. Abstract methods may be overridden in subclasses, and must be overridden in normal or final subclasses. An abstract method may be overridden by a normal method, a final method, or another abstract method.

 

METHOD OVERLOADING

A class may define more than one method with the same name. What must be unique in a class is a method's signature, which is composed of three parts:

1.      The method's name.

2.      The number of parameters the method takes. (Parameter types are not considered, unlike C++ or Java.)

3.      Whether the method is an instance method or a class method.

This ability to uses methods of the same name is called overloading. Overloaded methods are different methods with no connection between them. This facility is for the programmer's benefit so similar-functioning methods can have the same name.

Because a method's name is insufficient to identify it, we often use the notation "instance method Print#2" to mean "the version of the Print instance method that takes two parameters". This is always used in Diamond error messages.

 

METHOD OVERRIDING

Method inherited from a superclass can be overridden (unless the inherited method is a final method). To override a method, define a method with the same signature (see Method Overloading) in the subclass. The overriding method must have the same access rights or less restrictive access rights than the overridden method. Thus a private method may be overridden by a public method, but a public method may not be overridden by a private method. Sometimes the whole purpose of overriding is to use less restrictive access. An overridden method can be called by using the second syntax for call_method().

Overriding is the mechanism which makes polymorphism work. For example: A is a class and B is a subclass of A. A defines an instance method X#1 and B overrides X#1 with its own method. Then call_method(z,"X",{15}) will call A's method X#1 if z is an instance of A, but will call B's method X#1 is z is an instance of B.

 

SPECIAL METHODS

The universal base class Entity provides three special methods which are inherited by every normal, final, or abstract class.

1.      A class method new#0. This method creates a new instance entity of the calling class. Directly calling the new method of an abstract class will return Null_Instance and not create an instance of the class.

2.      An instance method clone#0. This method creates a shallow copy of its target instance. In a shallow copy, if a property of the instance is also an instance, only the reference is copied. If a deep copy (properties which are instances are cloned) is needed for instances of a given class, that class can override the clone method. If the target's class implements the Do_Not_Clone interface, returns Null_Instance and does not copy its target.

3.      An instance method delete#0. This method destroys the entity it is invoked on. The delete method reclaims memory used by an instance which is no longer needed. A class may override the delete method to release resources such as file or window handles used by the instance, or to delete instances which are contained in the instance.

These methods are protected in Entity. Usually you will want to override new and delete in your class to make them public. If you want to be able to copy instances of your class, override clone to make it public. If you do make clone public, it is advisable to implement the Clonable interface so that other classes can determine that your class's instances can be copied.

There are cases where you may want to leave these methods protected to control the creation, destruction, or copying of your class's instances.

 

AUTOMATIC METHOD CALLS

Diamond calls certain methods automatically without the use of call_method(). An automatic call to a non-existent or abstract method does not cause an error, it simply results in nothing being done. Automatic calls ignore access rights. These provisions only apply to the direct call--any method calls by the called method work normally. Diamond makes the following automatic method calls:

1.      end_class() calls the class method Initialize#0 for the class.

2.      save_entity() calls the instance or class methods (as appropriate) Before_Save#0 and After_Save#0 for each saved entity.

3.      restore_entity() calls the instance method After_Restore#0 for each restored instance, and calls the class methods Before_Restore#0 and After_Restore#0 for each restored class.

4.      raise_event() calls instance or class methods (as appropriate). For an instance event XXX#0, raise_event() will call the instance methods Before_XXX#0, On_XXX#0 (if appropriate) and After_XXX#0.

 

EVENTS

Events represent specialized behavior of an entity. Events can be overloaded in exactly the same way as methods, but cannot be overridden. (Event names are expressed in the same "Event_Name#0" fashion as method names.) Each event may have one or more handlers assigned by link_handler() during the run of the program. (If an event is raised before any handlers have been linked, the default handler will be used.)

Each event may have a prehandler, a default handler, and a posthandler. These are implemented as methods which are called automatically.

The handlers for an instance event XXX#2 are called as follows, with each handler being passed the parameters specified by raise_event():

The prehandler instance method Before_XXX#2 is called automatically.

The handlers are called in the order they were declared in link_handler(). If one of the handlers is DEFAULT_HANDLER, then the default handler instance method On_XXX#2 is called automatically.

The posthandler instance method After_XXX#2 is called automatically.

If any of these calls results in cancel_event() being executed, an exception being thrown, or the target being deleted (in the case of an instance target), the subsequent calls are skipped.

Handlers are treated as if they were methods of an unrelated class: the handler can only access public properties, methods, and events of the defining class. The prehandler, default handler, and posthandler methods are treated the same as any other methods.

The routine id's of handlers for each event are stored in the entity's value. These will be treated as transient properties when saving and restoring entities: an instance handler will be reset to the default handler; a class handler will retain its current value. See event(), link_handler(), and raise_event().

 

 

EVENT ACCESSORS

Events may have accessors in a similar fashion to properties. The two accessor functions are a linker to be called from link_handler(), and a raiser to be called from raise_event().

A linker is coded as a one-parameter function: link_handler() will pass the list of handler ID's to the function. If the linker returns FALSE, the handlers will be linked to the target event, otherwise they will not be linked.

A raiser is coded as a one-parameter function: raise_event() will pass the event parameters to the function. If the function returns FALSE, the event handlers will be executed, otherwise the event will be cancelled.

See event() for the syntax to declare accessors.

 

INTERFACES

Interfaces are special classes containing lists of instance and class methods. A normal, final, or abstract class which defines each instance and class method of an interface (directly or by inheritance) as a public method is said to implement that interface. (Diamond does not recognize this automatically, it must be declared in the class() function defining the class.) Interfaces express relationships not based on inheritance. For example, trucks, checking accounts, and characters really have nothing in common, but might all implement the Clonable interface which lists the method needed to copy entities. It is possible to define an interface with no methods to act as a tag. Do_Not_Clone is a tag interface.

Interfaces are defined using interface(). An interface does not need to have a superclass, but may have one or more superclasses which must be interfaces. Diamond predefines the Clonable and Do_Not_Clone interfaces.

 

EXCEPTIONS AND EXCEPTION HANDLING

Exceptions are provided for the handling of recoverable errors and other exceptional conditions. The procedure fatal_error() should be used to display error messages for non-recoverable errors.

Exceptions are special classes which form a class hierarchy. The class Exception is predefined in Diamond and has no superclass. Diamond also predefines the exception Type_Check_Failure as a subclass of Exception. Every other exception must be defined using exception() and must specify an exception as its superclass. Like interfaces, exceptions may have multiple superclasses. If no superclass is specified, then Exception will be the superclass.

When your program encounters an error, use throw() to signal an exception. This is allowable anywhere except within a class definition. The exception your program throws becomes the pending exception if no other exceptions are pending. If another exception is pending, the program terminates: only one exception may be pending at a time. Many Diamond routines generate fatal errors if an exception is pending. Most importantly, while you can leave a method or an event handler which threw an exception, you may not call a new method with call_method(), nor may you raise a new event with raise_event().

The function success() may be used to determine if an exception is pending without processing the exception: it returns TRUE if no exception is pending, FALSE if an exception is pending.

To process an exception use catch(). This function determines whether an exception is pending, if not, it returns FALSE. If an exception is pending, catch() determines if the exception given as its parameter is the same exception as the pending exception or is a superclass of the pending exception. If so catch() returns TRUE and clears the pending exception, otherwise it returns FALSE. Therefore

catch(Exception) 

will catch any exception, as Exception is a superclass of all exceptions.

When you catch an exception and need to know the exact exception, use caught(): this returns the last exception processed by catch(), but returns Null_Class if there is none.

 

TYPE CHECKING

Diamond provides an alternative to standard Euphoria type checking, in which a type check failure can throw an exception rather than abort the program immediately. The Type_Check_Failure exception is special: if Type_Check_Failure is thrown while another Type_Check_Failure exception is pending, the second Type_Check_Failure is ignored--the program does not terminate. This allows multiple type check failures (say in method parameters) to result in only one exception pending.

Typically your method would throw Type_Check_Failure indirectly by the use of wrapper types.

Writing wrappers for types is quite easy. If you have defined a type foo then this is all that is needed:

type is_foo(object x)
        if not foo(x) then
               throw(Type_Check_Failure)
        end if
        return TRUE
end type

So that if we have

foo x
is_foo y

then assigning an invalid value to x will abort, but assigning an invalid value to y will allow the assignment but throw Type_Check_Failure.

Wrappers are already defined for integer, atom, sequence, object, identifier, entity, instance_entity (is_instance), class_entity (is_class), and live_instance.

A wrapper is also defined for every Diamond Standard Class Library class (except Entity and exceptions). For a class X this will be is_X. The wrapper checks whether the parameter is a live instance (an instance which has not been deleted). If X is a normal, final, or abstract class, the wrapper will check if the parameter's class is X or a subclass of X. If X is an interface, the wrapper checks if the parameter's class implements X. These class wrappers are not listed in the alphabetical listings.

 

SPECIAL NOTE FOR USER'S OF THE EUPHORIA TO C TRANSLATOR

Versions of the translator prior to v2.4 omit type checking of assignments and parameter passes--the above technique cannot be used.

 

SAVING AND RESTORING ENTITIES

Entities can be converted into coded byte sequences. These sequences can be stored to a file, or transmitted over a network or the internet. Use save_entity() to create the coded sequence and use restore_entity() to recreate the entity. Entities can be shared by the same program running on different machines or by different programs on the same or different machines if both programs define the entity's class and the classes of any of the entities property values which are entities. The Var_Saver class implements a simple scheme for saving any or all program variables (whether entities or not) to an EDS database and restoring them in the same or a different program. Methods are called automatically during the process of saving and restoring, see save_entity() and  restore_entity() for details.

If you save entities and restore them in the same run of a program, any entities whose classes implement Do_Not_Clone will be restored as Null_Instance or Null_Class. This does not apply to different programs or different runs of the same program.

Diamond 4.0.0 can restore saved entities created by Diamond 1.2.0 or later.

 

 

CLASS DESIGN IN DIAMOND

A class or several related classes can be defined in an include file. It is possible to put class definitions in the same file as your main program, but inadvisable--this would allow a method to be called by a direct function call rather than through call_method(). This defeats Diamond's access control and stack trace facilities.

Consider the properties, methods, and events your class needs. Determine if an existing class can be used as a superclass and provide some or most of the properties, methods, and events by inheritance. Consider what interfaces should be implemented and if necessary, define new ones.

Give careful thought to the creation, copying, and destruction of the class's instances.

Consider error handling and which exceptions will be used, defining new ones if necessary.

Determine what type of class: normal, final, or abstract. Most of the time you will use normal classes. Use final classes for detailed implementation that is unlikely to need to be subclassed--particularly if you use code trickery for efficiency. Abstract classes are good for generic concepts that will be made particular by subclassing. Example: A class "Shape" subclassed by "Circle", "Triangle", "Square", etc.

Open the class definition by using class(). The class handle returned by class() should normally be assigned to a global constant; however a local constant could be used if it is desired to have the class usable only in the file which defines it. The use of a local constant is more common for inner classes.

Register each property by using property(). It is normal to use private access for both reading and writing. Generally, make an instance property persistent, but make a class property transient. See Saving and Restoring Entities.

If a class property is intended as a constant, use public read access and private write access. If the value of the constant will be the same in this class and all of its subclasses, just set the default value to the constant value, or set the value in the class' Initialize#0 class method. If subclasses will have different constant values for this property, use protected write access in the base class and set the subclass's value for the constant in the subclass's Inititialize#0 method.

Code methods as functions taking the appropriate number of object parameters (which may be none). If the method overrides a superclass method, the superclass method may be called by using super() as the target of call_method() if the superclass method is not private or abstract. If a method is logically a procedure, have the method return NIL and assign the result to VOID when calling the method. If you are using an abstract method (only legal in an abstract class), don't code it, just register it with method(), for example:

method("X",0,INSTANCE,ABSTRACT,PRIVATE,ABSTRACT_METHOD,NONE)

Public or protected access can also be used.

Instead of coding method parameters as objects, you can use wrapper types as detailed in Type Checking. If you do so, check for a pending exception at the beginning of the method.

The predefined methods NULL_METHOD and SUPER_METHOD can be used. NULL_METHOD does nothing and returns the value you specify (see method()). This might be useful if you must have a method to override an abstract superclass method or implement an interface method but don't really need the method. It is also a simple way to define a method which returns a constant. SUPER_METHOD is used to override superclass methods: it simply passes its parameters to the overridden superclass method and returns the superclass method's return value.

Methods in final classes must be declared final. Methods in normal and abstract classes may be declared final: this is useful when you are sure that a subclass won't need to redefine the method or for private methods the class uses internally.

Register each method using method(). Most methods will be public. Methods used for internal use only will be private. Methods not generally available but needed by subclasses will be protected. Default parameters are used to allow the same code to be used for multiple methods. For example, from the Standard Class Library Sorted_Sequence class:

function Sorted_Sequence_new_3(is_boolean ignoreCase,is_boolean descending,is_boolean unique)
-- code omitted
end function
method("new",1,CLASS,NORMAL,PUBLIC,routine_id("Sorted_Sequence_new_3"),{FALSE,FALSE}) 
method("new",2,CLASS,NORMAL,PUBLIC,routine_id("Sorted_Sequence_new_3"),{FALSE}) 
method("new",3,CLASS,NORMAL,PUBLIC,routine_id("Sorted_Sequence_new_3"),NONE)

So

call_method(Sorted_Sequence,"new",{x,y,z}) 

will call Sorted_Sequence_new_3(x,y,z), while

call_method(Sorted_Sequence,"new",{x,y}) 

will call Sorted_Sequence_new_3(x,y,FALSE) and

call_method(Sorted_Sequence,"new",{x}) 

will call Sorted_Sequence_new_3(x,FALSE,FALSE).

Code the constructors as class methods. Conventionally these are named "new" and return a newly-created instance or throw an exception and return Null_Instance in case of failure. A superclass constructor must be called (normally by using super()). Normally, you will specify public access for a constructor but may use protected access to control the creation of instances of the class. If no initialization needs to be done, SUPER_METHOD may be used for the class' new#0 method. Note that if the class is an immediate subclass of Entity, you must override Entity's new#0 class method to provide public access.

If copying of instances is to be done, using SUPER_METHOD for the class' clone#0 instance method will be sufficient if a shallow copy (if the value of a property is an instance, only the handle is copied) is acceptable. Note that if the class is an immediate subclass of Entity, you must override Entity's clone#0 instance method to provide public access. If a deep copy (if the value of a property is an instance, a copy of that instance is made) is needed, or any kind of error checking or conditional copying is to be done, define copy constructors as instance methods. Conventionally these are named "clone" and return a copied instance or throw an exception and return Null_Instance in case of failure. A superclass copy constructor must be called (normally by using super()).

If you want to prevent copying of instances, implement the Do_Not_Clone interface.

Destructors are often not necessary: use SUPER_METHOD for the class' delete#0 instance method. Note that if the class is an immediate subclass of Entity, you must override Entity's delete#0 instance method to provide public access. Destructors are necessary if instances contain system resources such as file or window handles: the destructor must release these. A destructor may be necessary if the instance can contain other instances. It may be desirable to ensure that these are destroyed when the containing instance is destroyed. In general, a reference to an external instance should not be deleted, while an instance created for internal use should be. If destructors are needed, code them as instance methods. Conventionally these are named "delete" and return Null_Instance or throw an exception and return the target instance in case of failure. A superclass destructor must be called (normally by using super()).

If the class requires initialization, code a class method named Initialize taking no parameters. This will be called automatically and the end of the class definition.

Events handlers are coded as procedures taking the appropriate number of parameters, similar to methods. To cancel the calling sequence of event handlers in progress, use cancel_event() if this is normal, or throw an appropriate exception if an error has occurred. If a handler deletes the target instance, the calling sequence will also be stopped.

Register the event with event(). Register the handlers for an entity outside the class definition using link_handler().

Events are used primarily in GUI applications to handle operating system events such as mouse clicks, key presses, window closings, etc. However, events are in no way restricted to this usage. Anytime you need different behavior for different instances of the same class or want to be able to change behavior at runtime, an event can be useful.

While events cannot be overridden, the prehandler, default handler, and posthandler methods can be.

See the following information functions for use in specialized design:

·        an_instance() to use a hypothetical instance as the target of can_...().

·        can_get() to determine if get_property() would be successful.

·        can_get_list() to get a list of all properties for which get_property() would be successful.

·        can_set() to determine if set_property() would be sucessful.

·        can_set_list() to get a list of all properties for which set_property() would be successful.

·        can_call() to determine if call_method() would be succesful.

·        can_call_list() to get a list of all methods for which call_method() would be successful.

·        can_link() to determine if link_handler() would be successful.

·        can_link_list() to get a list of all events for which link_handler() would be successful.

·        can_raise() to determine if raise_event() would be successful.

·        can_raise_list() to get a list of all events for which raise_event() would be successful.

·        last() to get the target of the method or event which called or raised the current method or event.

·        last_class() to get the class of the target of the method or event which called or raised the current method or event.

·        this_method() to get the name of the current method.

·        this_event() to get the name of the current event.

·        last_method() to get the name of the method which called the current method or raised the currewnt event.

·        last_event() to get the name of the event which called the current method or raised the current event.

·        program_stack() to get information about all pending methods and events.

·        class_data() to get a list of all available information about a class.

The following functions allow the attempt to read a property, call a method, etc.:

·        try_get() to attempt to read a property.

·        try_set() to attempt to write a property.

·        try_call() to attempt to call a method.

·        try_link() to attempt to link an event handler.

·        try_raise() to attempt to raise an event.

Each of these function returns a two-element sequence: the first element is a boolean indicating whether the attempt succeeded, the second is the return value or NIL as appropriate if the attempt succeeds or an error message if the attempt fails.

End the class definition with end_class().

Interfaces are defined with interface().

 

COMPOSITION

Composition is a very common class design technique. It refers to using one entity inside another (a property value) and using the internal entity to implement some of the functionality of the enclosing entity. The enclosing entity's methods can be defined to call the internal entity’s methods. The use of property and event accessors can be used to achieve similar effects. Normally, only public properties, methods and events of the internal entity are available to the enclosing entity; but inner classes can be used to provide more extensive access. For example, if you want to use a Sorted_Sequence inside your class but you need to access to its protected and private properties and methods, define an inner class within your class which is a subclass of Sorted_Sequence.

 

 

STANDARD CLASS LIBRARY

Diamond has a small but useful class library which is contained in the following include files:

dexcept.e: provides many useful exceptions.

dcontain.e: provides containers such as stacks, queues, and sorted sequences.

dwidget.e: provides Visual Basic style collections and components as a framework for building widgets.

dvsaver.e: automates saving and restoring variables to an EDS database.

dvar.e: provides reference variables and flexible structures.

dsingle.e: provides instance counted classes, including the Singleton class.

ddelegat.e provides C# style delegates capable of wrapping a property, method or event of any entity for indirect access. Delegates can be passed as parameters, used for callbacks, etc.

See alphabetical listing for details.

Version numbering of the Standard Class Library conforms to Diamond. All include files in the Library will have the same version number as the current version of Diamond.

 

DEMO PROGRAMS

Six demo programs are included:

1.      Demo.ex demonstrates some of the containers in the Standard Class Library.

2.      Speedtst.ex provides some benchmarks--adapted from Rod Jackson's speed test for Quartz.

3.      Progstrt.ex is a simple program launcher illustrating the capabilities of the Diamond Text-Based User Interface package. This is intended primarily for DOS in mode 3, but works in Windows and should work in Linux. When first run, it will ask you to set a password, then ask for your choice of screen colors, then display the main menu. On subsequent runs, it will ask for your password and display the main menu. The main menu allows you to change the password or the screen colors and to launch a program either by typing a command line or from a menu. When you launch a program from a command line, you will be given the option to add this program to your program launch menu.

4.      Savetst1.ex demonstrates saving and restoring entities using a text file. This calls savets1x.ex.

5.      Savetst2.ex demonstrates saving and restoring entities using the Var_Saver class to create an EDS database. This calls savets2x.ex.

6.      Event.ex illustrates some abstract event handling.

 

COMPATIBILITY

Diamond 4.0.0 is fully compatible with all standard include files with these exceptions: file.e, get.e, and graphics.e have name clashes if diamond.e is included first. Including these files (or any files including them) before including diamond.e prevents this problem. In Euphoria 2.3 or later, namespacing may also be used.

Diamond 4.0.0 is backward compatible with Diamond 3.3.0 with the exception of the Extended_Access interface: this no longer exists. Diamond 4.0.0 is backward compatible with Diamond 3.2.0 with one exception: the return value of class_data() has changed--this will be relevant only if your code is examining data for events. Diamond 4.0.0 is backward compatible with Diamond 3.0.0, Diamond 3.1.0, and Diamond 3.1.1 with one additional exception: some named constants have changed value, which will break code that uses these constants by value rather than by name.

Diamond 4.0.0 and the Diamond Standard Class Library are not guaranteed backward compatible with versions prior to 3.0.0, but backward compatibility is very high except in the following areas:

·        Entities saved by Diamond versions prior to 1.2 cannot be restored.

·        Exception-throwing type checking.

·        Events.

Diamond 4.0.0 is compatible with the Euphoria to C Translator, but exception throwing type checks as used in the Standard Class Library will not work with versions of the Translator prior to v2.4.

 

NOTE CONCERNING COMPATIBILITY

I believe that the event system introduced in Diamond 2.0.0 was flawed and needed to be redesigned, so it became necessary to break backward compatibility. The automatic method call approach for prehandlers, default handlers, and post handlers used in Diamond 3 is much cleaner than the Diamond 2 approach. I also now have separate access for linking handlers and raising events.

Having already broken backward compatibility, I decided to clean up the exception-throwing type checks and move them from the Standard Class Library into Diamond itself.

I believe that by breaking compatibility, I have created a better version of Diamond than I could produce if I had maintained compatibility.

If you have any Diamond code from a previous version that breaks under Diamond 3, email me and I will personally assist you in converting it.

The backward compatibility break in Diamond 4.0.0 is not so radical. If you are not using Extended_Access features, no code will break. If you are, it’s easy to change your code to use inner classes. The offer of personal assistance above also applies to this issue.

 

END USER LICENSE AGREEMENT

Diamond consists of all files contained in diamond.zip. Diamond is freeware. Diamond is released for private, public, and commercial use subject to these conditions:

1.      All distributions of Diamond, modifications of Diamond, or programs incorporating Diamond shall include this End User License Agreement, the Disclaimer, and proper authorship credit.

2.      All distributions of Diamond, modifications of Diamond, or programs incorporating Diamond shall be free of charge; but you may charge a sufficient sum to recover the cost of the distribution media.

3.      You may freely modify Diamond, but all distributions of modifications of Diamond must contain notice that you have made modifications and the general nature of these modifications.

4.      You may incorporate Diamond, either as-is or modified, into a larger program. You may distribute your program if you comply with conditions 1, 2, and 3 (if applicable).

5.      If you wish to sell a program which incorporates Diamond, whether as-is or modified, you may do so if you comply with conditions 1 and 3 (if applicable). Condition 2 is waived if and only if your program's purpose is clearly distinct from Diamond's own purpose: the provision of Object Oriented Programming services for the Euphoria language. [Examples: A business application or a game incorporating Diamond may be sold. A program which prints "Hello World" incorporating Diamond may not--the program is clearly a ruse to evade condition 2.]

6.      You have unlimited rights to create new classes for use with Diamond and to copy, distribute and sell such classes, subject to the requirement that you do not use a class or package name containing the word "Diamond", including variations in case and/or creative spelling [Example: "Dymond"], and do not use any combination of words indicating my endorsement of your classes anywhere in your code or documentation.

7.      Condition 6 does not apply to classes submitted to me and accepted for inclusion in official Diamond libraries. Any class submitted to me and accepted will be distributed free of charge (with full authorship credit) in future releases of Diamond. If you wish to sell a class, don't submit it for inclusion in an official library.

 

DISCLAIMER

Diamond is released without warranty of any kind whatsoever, whether express or implied. The author is not responsible for any damages arising from the use of this software, whether direct or indirect, incidental or consequential.

USE AT YOUR OWN RISK.

 

NEXT PAGE