Diamond Lite v1.1

(c) June 2002 by Michael A. Nelson

MichaelANelson@worldnet.att.net

 

TABLE OF CONTENTS

 

WHAT IS DIAMOND LITE LITE?

Diamond Lite is a simplified version of the Diamond Object Oriented Programmming Library for Euphoria. 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. Diamond Lite removes considerable complexity from Diamond a the cost of power. Diamond Lite is intended for the beginning/intermediate OOP programmer.

 

FEATURES OF DIAMOND LITE LITE

 

INTRODUCTION TO OBJECT ORIENTED PROGRAMMIMG IN DIAMOND LITE

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, a character attacks a monster. One common way of expressing this it an object consists of its state (properties) and its behavior (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 Lite, 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 and methods 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 and methods of Car and adding new properties and methods to represent attributes and actions of police cars which do not apply to normal cars.

Inherited properties 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 Lite 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 Lite defines four program contexts--main program, class definition, instance method, and class method. The program context indicates what type of method (if any) is currently executing. Main program indicates that no method is currently executing and no class definition is in progress. Program context is important for determining access rights. Many Diamond Lite routines can only be used in certain program contexts. Some Diamond Lite routines are also 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 Lite 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.

 

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 Lite. 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 Lite 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 Lite defines two types of classes: normal classes and exceptions. Exceptions are special classes described below.

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

Diamond Lite provides a null class named Null_Class for use in error reporting. Null_Class is a subclass of every class, but has no properties or methods. New instances cannot be created, but a single pre-created instance named Null_Instance is provided.

  

PROPERTIES

Properties represent the state of an entity. Properties are inherited from superclasses, but overriding is not allowed. Properties may only be read or written in a method of the class which defines the property, or a method of a superclass of that class. See property(), get_property(), and set_property().

 

METHODS

Methods represent the behavior of an entity. Methods are inherited from superclasses and can be overridden. A method may be called from any method of any class or from the main program. The universal base class Entity provides some special methods. See method() and call_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.

 

METHOD OVERRIDDING

Method inherited from a superclass can be overridden. To override a method, define a method with the same signature (see Method Overloading) in the subclass. 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 named new, which takes no parameters. This method creates a new instance entity of the calling class. Directly calling the new method of an abstract class will cause program termination.
  2. An instance method named clone, which takes no parameters. This method created 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.
  3. An instance method named delete, which takes no parameters. 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.

 

EXCEPTIONS AND EXCEPTION HANDLING

Exceptions are provided for the handling of recoverable errors and other exceptional conditions. The procedure fatal_error() can 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 Lite and has no superclass. Every other exception must be defined using exception() and must specify an exception as its 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 Lite routines generate fatal errors if an exception is pending. Most importantly, while you can leave a method which threw an exception, you may not enter a new method with call_method().

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. Therefor

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 generates a fatal error if there is none.

 

CLASS DESIGN IN DIAMOND LITE

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 Lite's stack trace facilities.

Consider the properties and methods your class needs. Determine if an existing class can be used as a superclass and provide some or most of the properties and methods by inheritance.

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.

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.

Register each property by using property().

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 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.

The predefined method NULL_METHOD can be used. NULL_METHOD simply returns NIL. This might be useful if you want to override an inherited method so that it does nothing.

Register each method using method().

Code the constructor(s) 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()).

If copying of instances is to be done, nothing needs to be done if a shallow copy (if the value of a property is an instance, only the handle is copied) is acceptable. 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 the copy constructors(s) 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()).

Destructors are often not necessary. 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 destructor(s) 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()).

End the class definition with end_class().

 

DEMO PROGRAM

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

 

COMPATIBILITY

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

 

END USER LICENSE AGREEMENT

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

  1. All distributions of Diamond Lite, modifications of Diamond Lite, or programs incorporating Diamond Lite shall include this End User License Agreement and the Disclaimer.
  2. You may freely copy and distribute Diamond Lite provided that you give due credit to me as author.
  3. You may modify Diamond Lite, and may freely distribute modifications if you give notice of the fact that you have made modifications and the general nature of these modifications.
  4. You may incorporate Diamond Lite, either as-is or modified, into a larger program. You may freely distribute such program subject to conditions 1, 2, and 3 if you distribute your program without charge.
  5. If you wish to sell a program which incorporates Diamond Lite, you may do so provided that your program has a purpose distinct from Diamond Lite's own purpose (the provision of object-oriented programming for Euphoria) and that you comply with conditions 1, 2, and 3.
  6. You have unlimited rights to create new classes for use with Diamond Lite and to copy, distribute and sell such classes, subject to the requirement that you do not use any combination of words indicating my endorsement of your classes anywhere in your code or documentation.

 

DISCLAIMER

Diamond Lite 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.



ALPHABETICAL LISTING OF GLOBAL ROUTINES, VARIABLES, AND CONSTANTS

 

The syntax convention for routines is to show the return value (for functions and types) and the parameters as type names with digits to distinguish them: object1, integer2, entity3, etc. All errors are listed except type clashes and illegal program contexts. Context indicates the legal program contexts for the routine.

 

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

 

call_method

Variety: function
Syntax: object1=call_method (entity1,identifier1,sequence1) OR
object1=call_method(super(),identifier1,sequence1)
Contexts: Main program, instance method, class method; no pending exception.
Description: Calls the appropriate method of entity1 's class with entity1 as its target. If entity1 is an instance, an instance method is called; if a class, class method is called. Identifier1 gives the name of the method and the number of parameters is the length of sequence1. Sequence1 is passed to the method as its parmaters (if any). Returns the return value of the method. See super() for the second syntax.
Note: Be careful of one parameter methods when passing a sequence or entity. For example: call_method(x,"DoThis","ABC") does not pass ABC to x's DoThis#1 method--it passes 'a', 'b', and 'c' to x's DoThis#3 method. The correct syntax is call_method(x,"DoThis",{"ABC"}). Similarly, if y is an entity, then call_method(x,"DoThat",y) will split y into the components of its handle and pass them to x's DoThat#3 method. Correct syntax to pass y to x's DoThat#1 method is call_method(x,"DoThat",{y}).
Errors: Program termination if:
  • Entity1 is a deleted instance or an exception.
  • The method to be called is not defined by entity1's class.

 

catch

Variety: function
Syntax: boolean1=catch(class_entity1)
Contexts: Main program, instance method, class method.
Description: If class_entity1 is the class of the pending exception or of a superclass of the pending exception, returns TRUE and clears the pending exception; otherwise returns FALSE. Returns FALSE if no exception is pending.
Note: Since all exceptions are direct or indirect subclasses of Exception,
catch(Exception) 

will catch any exception.

Errors: Program termination if Class_Entity1 is not an exception.

 

caught

Variety: function
Syntax: class_entity1=caught()
Contexts: Main program, instance method, class method.
Description: Returns the last exception processed by catch().
Errors: Program termination if an uncaught exception is pending or if no exception has been thrown.

 

CLASS

Variety: constant
Description: Used in property() or method() to specify a class property or method.

 

class

Variety: function
Syntax: class_entity1=class(identifier1,class_entity2)
Contexts: Main program, no pending exception.
Description: Begins the definition of a class with the name identifier1. Class_entity2 is the superclass of the new class. Returns the new class' handle.
Note: It is strongly recommended to assign class_entity1 to a global constant.
Errors: Program termination if identifier1 duplicates an existing class or exception name.

 

class_entity

Variety: type
Syntax: boolean1=class_entity(object1)
Contexts: All.
Description: Returns TRUE if object1 is a class entity; returns FALSE if object1 is an instance entity or is not an entity..
Errors: None.

 

class_name

Variety: function
Syntax: string1=class_name(object1)
Contexts: All.
Description: If object1 is an entity, returns object1's class name. If object1 is not an entity, returns NONE.
Errors: None.

 

deleted_instance

Variety: type
Syntax: boolean1=deleted_instance(object1)
Contexts: All.
Description: Returns TRUE if object1 is an instance entity which has been deleted; returns FALSE if object1 is an instance entity which has not been deleted, is a class entity, or is not an entity..
Errors: None.

 

end_class

Variety: procedure
Syntax: end_class()
Contexts: Class definition.
Description: Ends the current class definition.
Errors: None.

 

entity

Variety: type
Syntax: boolean1=entity(object1)
Contexts: All.
Description: Returns TRUE if object1 is an entity, otherwise FALSE.
Errors: None.

 

error_screen_width

Variety: procedure
Syntax: error_screen_width(object1)
Contexts: All.
Description: Sets the width of the error screen for formatting of termination messages issued by fatal_error() to object1. If object1 is not an integer or is less than 20 the setting is unchanged. (The initial width is 80.)
Errors: None.

 

exception

Variety: function
Syntax: class_entity1=exception(identifier1,class_entity2)
Contexts: Main program, no pending exception.
Description: Defines an exception with the name identifier1. Class_entity2 is the superclass. Returns the new exception's handle.
Note: It is strongly recommended to assign class_entity1 to a global constant.
Errors: Program termination if:
  • Identifier1 duplicates an existing class name.
  • Class_entity2 is not an exception.

 

extends

Variety: function
Syntax: boolean1=extends(object1,object2)
Contexts: All.
Description: Returns TRUE object1 and object2 are entities and object1's class is the same as object2's class or a subclass of object2's class; otherwise returns FALSE.
Errors: None.

 

FALSE

Variety: constant
Description: The integer 0, used as a boolean value.

 

fatal_error

Variety: procedure
Syntax: fatal_error(string1)
Contexts: All.
Description: Terminates the program with an error message. Word wraps the error message based on width of the error screen; this defaults to 80, and can be set by error_screen_width(). The error message consists of:
  • The text in string1 prefaced by "FATAL ERROR:".
  • Any currently pending or caught exception.
  • Any currently pending methods.
Errors: None.

 

get_class

Variety: function
Syntax: sequence1=get_class(object1)
Contexts: All.
Description: If object1 is an instance entity, returns the handle of the entity's class. If object1 is a class entity, returns object1. If object1 is not an entity, returns NONE.
Errors: None.

 

get_property

Variety: function
Syntax: object1=get_property(entity1,identifier1)
Contexts: Instance method, class method.
Description: If entity1 is an instance, returns the instance property named identifier1 of the instance. If entity1 is a class, returns the class property named identifier1 of the class.
Errors: Program termination if:
  • Entity1 is a deleted instance or an exception.
  • The property to be read is not defined by entity1's class.
  • The method currently executing is not a method of the class which defines the property or of a superclass of that class.

 

identifier

Variety: type
Syntax: boolean1=identifier(object1)
Contexts: All.
Description: Returns TRUE if object1 is a string which is a valid Euphoria identifier: the first character is a letter and all of the other characters are letters, digits, and underscores; otherwise FALSE.
Errors: None.

  

INSTANCE

Variety: constant
Description: Used in property() or method() to indicate an instance property or method.

 

instance_entity

Variety: type
Syntax: boolean1=instance_entity(object1)
Contexts: All.
Description: Returns TRUE if object1 is an instance entity; returns FALSE if object1 is a class entity or is not an entity..
Errors: None.

 

method

Variety: procedure
Syntax: method(identifier1,integer1,integer2, integer3)
Context: Class definition.
Description: Defines a method named identifier1 in the class currently being defined. Integer1 specifies the number of parameters. Integer2 is INSTANCE or CLASS to specify the method's target. Integer3 is the routine id of the method or NULL_METHOD.
Errors: Program termination if:
  • Identifer1 duplicates an instance method name or class method name (as the case may be) of the class and integer1 duplicates the number of parameters of that instance or class method.
  • Integer1 is negative.
  • Integer2 is not INSTANCE or CLASS.
  • Integer3 is not a valid routine id or NULL_METHOD.

 

NIL

Variety: constant
Description: The integer 0 used in the sense of "no meaningful data", typically the return value of a method which is logically a procedure.

 

NONE

Variety: constant
Description: The empty sequence. A notational convenience, particularly when a sequence is intended as a list.

 

NULL_METHOD

Variety: constant
Description: Used in place of a routine id in method() to specify a do-nothing method which returns NIL.

 

property

Variety: procedure
Syntax: property(identifier1,integer1,object1)
Contexts: Class definition.
Description: Defines a property named identifier1 in the class currently being defined.. Integer1 is INSTANCE or CLASS to specify the type of property. Object1 is the initial value of the class property of the class and of its subclasses, or the initial value of the instance property for each newly-created instance of the class and of its subclasses, as the case may be.
Errors: Program termination if:
  • Identifier1 duplicates an instance property name or class property name (as the case may be) of the class or of any of its superclasses.
  • Integer1 is not INSTANCE or CLASS.

 

same_class

Variety: function
Syntax: boolean1=same_class(object1,object2)
Contexts: All.
Description: Returns TRUE if object1 and object2 are entities and both belong to the same class; otherwise returns FALSE.
Errors: None.

  

set_property

Variety: procedure
Syntax: set_property(entity1,identifier1,object1)
Contexts: Instance method, class method.
Description: If entity1 is an instance, sets the instance property named identifier1 of the instance. If entity1 is a class, sets the class property named identifier1 of the class. Object1 is the value to which the property is set.
Errors: Program termination if:
  • Entity1 is a deleted instance or an exception.
  • The property to be written is not defined by entity1's class.
  • The method currently executing is not a method of the class which defines the property or of a supercalss of that class.

 

success

Variety: function
Syntax: boolean1=success()
Contexts: Main program, instance method, class method.
Description: Returns TRUE if no exception is currently pending, otherwise FALSE.
Errors: None.

 

super

Variety: function
Syntax: integer1=super()
Contexts: Instance method, class method.
Description: Returns an integer constant. When used as the target of call_method(), calls an instance method or class method with this() as its target. The method will be an instance or class method of the immediate superclass of the class which defines the method currently executing. This allows an overridden method to be called by the overriding method (or any other method of the class which overrides the method).
Note: Do not use super() for any other purpose; while it is not an error to use super() in any other way in a method, only call_method() will interpret it correctly.
Errors: None.

 

this

Variety: function
Syntax: entity1=this()
Contexts: Instance method, class method.
Description: Returns the target of the method currently executing.
Errors: None.

 

this_class

Variety: function
Syntax: class_entity1=this_class()
Contexts: Instance method, class method.
Description: Returns the class of the target of the method currently executing.
Note: Faster-executing syntactic sugar for get_class(this()). Intended for instance methods; in class methods, this_class() is legal but redundant, having the same value as this().
Errors: None.

 

throw

Variety: procedure
Syntax: throw(class_entity1)
Contexts: Main program, instance method, class method.
Description: Sets the pending exception to class_entity1, which must be an exception.
Errors: Program termination if:
  • Class_entity1 is not an exception.
  • An exception is already pending.

  

TRUE

Variety: constant
Description: The integer 1 used as a boolean.

 

VOID

Variety: variable
Description: Used to discard unwanted return values, particularly the return values of a method which is logically a procedure and has no meaningful return value. Do not use VOID for any other purpose.
Note: If your program attempts to read VOID, it will always have a value of 0.