OOPLIB v0.01 
HiSoft Basic Object Oriented Programming Library 
1994, Data Uncertain Software - the authors of MODLIB. 
Written by Craig Graham
 
Introduction 
=============
 
OOPLIB provides support for dynamic class & object manipulation from HiSoft Basic2. 
The facility is very limited at the moment, but will improve rapidly.
 
OOPLIB  runs on any atari machine up to and including the Falcon, and has a very 
minimal code overhead (<2Kbytes for the library code).
 
Currently, the features implemented are:
 
o Class declaration 
   - Attributes are specified in the class declaration 
   - Only long int (32bit) attributes are supported at the moment. 
   - Any number of attributes for a given class.
 
o Object instatiation 
   - Create an object of a class
 
o Object deletion 
   - Get rid of an object that you are finished with
 
o Attribute manipulation 
   - You can set the values of an object's attributes. 
   - You can read those values again.
 
o Services 
   - These are still under developement, so at the monoment there aren't any, 
     I have however, included the syntax that I intend to use for them here in 
     readiness.
 
If this seems a little limiting, take a look at some of the example code to see 
the possible applications of OOPLIB as it stands.
 
Classes and objects are declared & created at run time, so a class could be 
created 'on-the-fly' by an application (eg. a database program could create 
a record class with attributes for each record, and the class could be defined 
by the user whilst the program is running depending of what file is loaded).

 
INSTALLING OOPLIB 
==================
 
You need all the library building stuff from the HiSoft Basic distribution 
discs, put it all in a directory along with the file oop.bin, then:
 
   buildlib.ttp gemvdi gemaes gemdos xbios bios menu oop
 
on a command line (I use mupfel from the gemini distribution). 
This will create a new HBASIC.LIB file, which you can copy into your HiSoft 
WORKING directory.....don't overwrite your original HiSoft disc's - that may be 
a bad move :)

 
USING OOPLIB 
==============
 
OOPLIB is used in the same way as the aes,vdi and xbios libraries, ie. you have 
a LIBRARY statement at the start of your program. The name of the library is 
OOP:
 
eg. 
   LIBRARY "OOP"
 
You must also include the OOPLIB header file OOPLIB.BH at the start of your 
program in order to use services. This can be omitted if you are only using 
the data grouping (attributes) and ignoring the service facilities.
 
CREATING CLASSES 
==================
 
Classes are created using the following syntax:
 
   class "<class name>","<attribute list>", "<service list>"
 
Where <class name> is a name for the class :) 
and <attribute list> is a comma seperated list of attribute names for the class.
 
eg. 
   class "person","age,weight,height", ""
 
would declare a class called person, where each person has attributes age,weight 
and height which may have values assigned to them.

 
CREATING OBJECTS 
==================
 
You create an object (an instance of a class) using the following syntax:
 
   p&=object&("<class name>")
 
The function object&() returns a pointer to an object of type <class name>.
 
eg. 
   craig&=object&("person")
 
would create an object of type person. The variable craig& would be a pointer to 
the object.

 
DELETING OBJECTS 
==================
 
An object can be disposed of when you don't need it anymore, returning the 
storage it was using to the system. The syntax for this is:
 
   delete_object <object>&
 
where <object>& is a pointer to the object which you want to delete (as returned 
by the object&() call).
 
eg. 
   craig&=object&("person")      'create an object of class person 
   delete_object craig&          'get rid of the object again.

 
SETTING ATTRIBUTES 
====================
 
Once you have created an object, you can set the values of it's attributes using 
the following syntax:
 
   o_iset <object>&, "<attribute name>", <value>
 
Where <object>& is a pointer to an object (as returned by the object&() call). 
<attribute name> is the name of an attribute (one of the ones you specified when 
you created the class). 
<value> is an integer or long_integer value.
 
eg. 
   craig&=object&("person") 
   o_iset craig&,"age", 22
 
would set the age attribute of the object pointed to by craig& to be 22

 
READING ATTRIBUTES 
====================
 
The value of an objects attributes may be read using the following syntax:
 
   v=o_iget&(<object>&, "<attribute name>")
 
Where <object>& is a pointer to an object (as returned by the object&() call, 
and previously used in o_iset). 
<attribute name> is the name of an attribute (one of the ones you specified when 
you created the class).
 
eg. 
   craigs_age=o_iget&(craig&,"age")
 
would read the age attribute of the object pointed to by craig& (following on 
from the previous example, this would return the value 22).

 
ASSIGMENTS 
============
 
It is important to note that the assignment '=' in HBASIC does not have the same 
meaning when dealing with objects.
 
eg. 
   a$="person" 
   b$=a$
 
Both a$ and b$ are strings with the value of "person". Changing one string will 
not affect the other at all, as the assignment operation made a copy of the 
string. This is not what happens with objects.
 
   a&=object("person") 
   b&=a&
 
Now a& and b& both refer to an object of class person, but in this case, they 
both refer to the SAME object. So changing a attribute of b& will change the 
same attribute of a&. Deleting one of them will dispose of the object, and leave 
them both as invalid pointers, so care must be taken when performing this type 
of manipulation.
 
Also, note that
 
   a&=object("person")        'create one object, pointed to by a& 
   a&=object("person")        'create another object, and use a& to point to 
                              'this one instead.
 
will create two objects, and the first one will continue to exist, even though 
you can no longer access it via a basic variable. This fact is useful for 
creating linked lists, where you only need to have a pointer to the start of the 
list, and each element has a 'nextitem' attribute which points to the next 
element of the list.
 
Objects with common attributes can be processed by the same routine 
eg. two different types of linked list, both of which have a 'nextitem' attribute 
which points to the next element in the list. The same routine could be used to 
add a new element to the start of the list.
 
   LIBRARY "OOP"
 
   class "list1","value1,age,nextitem" ,"" 
   class "list2","zap,pow,kerblam,nextitem,spam" ,""
 
   list1_start&=object&("list1") 
   list2_start&=object&("list2")
 
   e1&=object&("list1") 
   add_element e1&,list1_start& 
   e2&=object&("list2") 
   add_element e1&,list2_start&     'notice that the same routine is called to 
                                    'add an element to a different class.
 
   END
 
   SUB add_element(element&, list_start&) 
      o_iset element&, "nextitem", list_start& 
      list_start&=element& 
   END SUB
 
The above example would work for any class which has a nextitem attribute (in 
fact you could have mixed class linked lists as well!!!).

 
SERVICES 
==========
 
1) SPECIFYING SERVICES 
----------------------- 
Services are operations associated with an object - conceptually a service is 
part of an object, and is stored together with it.
 
Services for a type are specified as follows:
 
   class "<classname>","<attrib list>", "<service list>" 
   service "<classname>","<service name>", service_address&
 
Note that a service line is required for each service in a class.
 
EG.
 
   class "list1","value1,age,nextitem" ,"addnew" 
   service "add", VARPTRS(add_element)
 
This example makes adding a new element to the list class from the previous 
example, into a service.
 
2) CALLING SERVICES 
-------------------- 
A service of a specific object is called using the syntax:
 
   use object&, "<service name>"
 
EG. 
   a&=object("list1") 
   use a&,"addnew"
 
3) WRITING SERVICES 
-------------------- 
Inside a service routine, you have access to one object by default. The name of 
this object is this&. this& is an alias for whichever object the service routine 
is working for. For example, in the above example, inside the "addnew" service 
call, this& would be an alias for a&, and would be of class "list1".
 
EG. 
  LIBRARY "OOP"                                    'use the OOP library 
  REM $include OOPLIB.BH                           'include the OOPLIB services 
                                                   ' header
 
   class "list","value1,age,nextitem" ,"addnew"    'define the list class 
   service "list","addnew", VARPTRS(add_element)   'specify the service
 
   mylist&=object&("list")                         'create a list object
 
   use mylist&,"addnew"                            'use the addnew service to 
                                                    add another element onto the 
                                                    list
 
   END
 
   SUB add_element                                 'The addnew service routine. 
   STATIC n& 
      n&=object("list")                               'create a new list object
 
      o_iset n&,"nextitem",o_iget&(this&,"nextitem")  'tack the old list onto 
                                                       the new list -notice the 
                                                       use of this& to 
                                                       refferance the current 
                                                       object. 
      o_iset this&, "nextitem", n&                    'stick the new list onto 
                                                       the head of the old list. 
   END SUB
 
A good example of the use of this would be storing vector graphic objects. 
You could have services which performed display, rotation, moving, warping, etc.

 
FUTURES & TECHNICAL 
=====================
 
This  section  lays  out  the  eventual  aims  of OOPLIB, and the direction I am 
currently going in, and how I get there.
 
This is the current state of play: (example code coming up)
 
============================================================================= 
   DEFINT a-z
 
   LIBRARY "OOP"
 
   declare_objects 100           'initial number of objects, grows dynamicly but 
                                 'better to set a bigish number here as each 
                                 'dynamic grow (50 objects) eats into the OS pool.
 
   'Define a linked list class (the simplest dynamic structure you can get). 
   ' each object has a number and a pointer to the next element in the list. 
   class "linked_list", "next, number", ""
 
   a&=object("linked_list")      'instance of the linked list object 
   o_iset a&,"number",20          'Set the value of an object attribute. 
                                 'o_vset = object value set
 
   b&=object("linked_list")      'another instance of a linked list element 
   o_iset b&,"number",30
 
   o_iset a&,"next",b&           'link object a to object b
 
   value_b=o_iget(o_vget(a&,"next"),"value") 
   print value_b
 
===============================================================================
 
Ok, not a particularly thrilling example, but you get the idea. At the moment 
all that I really have is a dynamic implementation of pointers to records (PASCAL) or 
pointers to structures (C). This is more reminiscent of the classes in smalltalk 
which are dynamic as well.
 
This does allow a greater degree of expression than HB does normally, but I'd 
like to add methods to the objects as well - but haven't got a clue how to call 
a HB function from assembly. I could use the syntax:
 
service "class name", "service name", varptrs(sub name), "parameters list"
 
but this presents some problems with parameter passing. For the service to 
address the object is fairly straight forward (set a global 'this&' with the 
current object like in c++), but passing parameters to perform the equivalent of 
a c++
 
   object.service(parameter);
 
is giving me a headache......what do you think ?
 
INTERNALS 
=========== 
All the OOP library code is in assembler, and doesn't do auto garbage collect to 
speed things up. When an object is disposed of (delete_object a&) it leaves a 
hole in the object store - a count of store usage & remaining is kept & the 
garbage is taken out when storage runs out, or is forced explicitly using 
'flush_objects'.
 
The objects are accessed via an indirection table:
 
 BASIC            OBJECT      OBJECT 
 VARIABLE         TABLE       STORE 
+--------+     +----------+  +-------+ 
|        |     |          |  |       | 
|  a&    |---->| object1& |->|  O1   | 
|        | +-->|          |  |       | 
+--------+ |   +----------+  +-------+ 
|        | |   |          |  |       | 
|  b&    |-+   | object2& |->|  O2   | 
|        |  +->|          |  |       | 
+--------+  |  +----------+  +-------+ 
|        |  |  |          |  |       | 
|  c&    |-++  | object3& |  |  O3   | 
|        |     |          |  |       | 
+--------+     +----------+  +-------+ etc
 
In the example above, a& and b& both reffer to the same object. The indirection 
table allows objects to move in memory transparently to the HB program using 
them as the OBJECT TABLE will handle all that.
 
IDEALS 
=======
 
Ideally, the eventual aim would be to provide windows style complex objects as 
well by identifying the object type with an application or accessory which can 
provide the services for them.
 
eg. Metafile object display
 
   class "metafile", "x,y,w,h,image", "display" 
   service "metafile","display:external[kadinsky.app]","x,y,w,h"
 
would associate the display service for an object class "metafile" with 
the program kandinsky.app so if you wanted to display a metafile at a location, 
(quick switch to c++ syntax)
 
   // mymeta is a metafile object. 
   mymeta.display(10,10,200,200);
 
This would call kandinsky, passing it either the metafile object or a pointer to 
it, and requesting that it displayed it at (10,10) with a size of (200,200).
 
I am about to field a proposal on the NET & the GEM Interface mailing list about 
agreeing a standard for this type of request (either derived from gemini av, or 
the more advanced Xacc2 standard). Anyway, that's outside of what I originally 
began talking about....views on the HB OOP library first, specificly a syntax 
for specifying services (of course, a better idea would be for HiSoft to include 
composite types, pointers & objects as part of the main HB language).

 
Regards. 
Craig Graham 
(still using HB 2.0)
 
craig.graham@newcastle.ac.uk

