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 "","", "" Where is a name for the class :) and 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&("") The function object&() returns a pointer to an object of type . 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 & where & 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 &, "", Where & is a pointer to an object (as returned by the object&() call). is the name of an attribute (one of the ones you specified when you created the class). 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&(&, "") Where & is a pointer to an object (as returned by the object&() call, and previously used in o_iset). 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 "","", "" service "","", 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&, "" 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