EuCANOOP

Eu[phoria] can [do] OOP

OOP programming in Euphoria is not built into the language. It is, however, quite simple to achieve and easy to apply. The library in EuCANOOP provides a means of carrying out OOP with just nine routines.

"Standard" Euphoria manipulates data structures such as objects, sequences, atoms, integers and any other type the user chooses to adopt or define. It does the manipulation by means of routines, some written in the program, others being in libraries. Authors might be RDS, the user or, perhaps, other users.

EuCANOOP offers an exactly analogous form of processing, but with just one data structure - the Object - and, at this stage anyway, just two pre-written routines. The difference is that the variables and routines are stored within the data structure and manipulation takes place solely within the Object.

You start by defining Classes, as prototypes of Objects. After each definition is complete the details of that Class are stored for future use. Once you have declared a Class you can create Instances of it (Objects), setting values specific to the Instance. Manipulation of an Object is possible because it carries within its values not only its "variables" but also pointers to routines (both procedures and functions) which operate on the Object's variables.

This is all achieved using two standard Euphoria constructs:

  1. the sequence
  2. the function routine_id

The rest is what I once heard called "syntactical sugar" - coding to provide stylistic simplification. This is what the EuCANOOP library provides.

Read on if you wish for more detail now, or jump to the library's specification.

The library described

You define a Class using the procedure Class. It takes one parameter:

Class("Dog")
If you wish the Class to inherit from another pre-defined Class then use the procedure Extends. Multiple inheritance is supported. Extends takes one parameter:
Extends({"Animal"})

If you wish to add property values then you use the procedure Property. It takes three parameters:

My convention is to use upper-case text for property names.

Property("FEET",INTEGER,0)

If you wish to add a method then use the procedure Method. It takes two parameters:

My convention is to use title-case for method names.
Method("Bark",routine_id("Dog_Bark"))
Repeat Property and/or Method calls as required to define all the values you need.

If you wish to assign an inherited Method to a different routine then you use the procedure Override. Just like Method it takes two parameters:

A Class definition is only stored when the procedure EndClass is called. It takes one parameter:

If you fail to include such a call, or key in the wrong name then the Class will not be entered into the database of Classes.
EndClass("Dog")
I find it useful to use an indenting convention for Class declaration. For example:
Class("Dog")
    Extends({"Animal"})
    Property("BREED",SEQUENCE,"")
    Method("Bark",routine_id("Dog_Bark"))
EndClass("Dog")
EuCANOOP's Objects are operational instances of Class paradigms. Objects are created (in the image of their Class definition) using the function New. It takes two parameters: You only need include such an array if you want to change from the default[s].
Fido = New("Dog",{{"BREED","Mongrel"}})
All Objects are created with two standard Methods: Get and Set. These Methods can be used to inspect or change the values of properties.

Methods are called as follows:

If the Method relates to a procedure then you use MethodProc. It takes three parameters:

MethodProc(StdOut,"Puts",{"Hello, World!"})

If the Method relates to a function then you use MethodFunc. It takes three parameters:

if MethodFunc(StdIn,"GetC",{}) then end if
Routines (qua Methods) must be defined as follows:

The routine must have at least one parameter. This is an Instance, which is used to refer to the Object itself. The remaining parameters, if any, are the ones to be called by the Method.

To avoid ambiguity my convention is to name routines in a consistent fashion. For example, if I intend to define a method called "What", for Class "Fred", with two method parameters (excluding "self") then I would name the routine Fred_What_2.

Example:

procedure Output_Puts_1(Instance self,string text)
    puts(self,text)
end procedure

Constructors

In some circumstances calling New is insufficient. Moreover, some users with other OOP language experience actually want to define Constructors. You can easily write conventional constructors by combining a call to New with a relevant creator routine. So, for example:
constant myFile = New("File",{{"NAME","Hello.ex"},{"MODE","r"}})
MethodProc(myFile,"Open",{})
could be replaced by
constant myFile = File("Hello.ex","r")
if the constructor File is defined as follows:
global function File(string name,string mode)
    Instance obj
    integer handle
    obj = New("File",{{"NAME",name},{"MODE",mode}})
    handle = open(name,mode)
    MethodProc(obj,"Set",{"HANDLE",handle})
    return obj
end function
My convention is to use, as the creator function, a function with precisely the same name as the Class.

Destructors

Because Euphoria has built-in garbage collection, there is no real need to define destructor routines. This even applies to operations such as closing an already opened file - Euphoria automatically closes all files when an application terminates.

Types

Objects are all declared to be of type Instance, which enables the programmer to distinguish all his/her Object instances.

This version extends to range of possible types - both for general programming use and in defining EuCANOOP properties. The additional types offered are:

Just like Euphoria's variables, properties of Objects are typed. EuCANOOP, however, uses its own type-checking routines, so property definitions use EuCANOOP's own types. In addition to the base types defined in Version 2 (OBJECT, ATOM, INTEGER and SEQUENCE) this version offers the addditional EuCANOOP types: ARRAY, BOOL, BYTE, CHARACTER, STRING and STRING_ARRAY.

Type-checking in EuCANOOP takes place when a Class Property's default is set, when an Instance is created with a non-default parameter and when the built-in "Set" Method is invoked. Unlike Euphoria, a type error does not result in program termination. Although an error message is issued if an assignment fails, the property's value is set, respectively, to a "null" value for that type, the Class default or is left unchanged.

Just as in standard Euphoria it is easy to define your own EuCANOOP types to add to the list above. To find out how see here.

Library specification

Version: 3.0.0

Date: November 2009
Author: C A Newbould (canewbould@users.sourceforge.net)
Changes:

Interface

Constants:

Routines:

** Routines for type-checking of properties **

Types:

EuCANOOP types:

Routines:

** Routines for Class creation ** ** Routines for Object manipuation ** ** Built-in Methods ** ** Inspection Routines **