Hi,
welcome to a small new project of mine: "Object Oriented Programming for All".
Every none oop language which offers support for Amiga Shared Libraries, is now able to use objects and can
be used to produce new classes.
Every programmer has surely heared about Java and that it will be very slow on an normal amiga. If you wanne code oop you are forced to use one of the C++ compilers or one the eiffel ports. What if you don`t need to because someone has build an open class system and a compiler which offers nearly the same functionality as the JAVA language does ?
Well I did this and because I wanted to use my own compiler language as a basis , I coded a precompiler which does the whole oop releated things and a oop library which does the runtime jobs. This system is open to every programming language which can make use of libraries. If you wanne use your own programming language, you will find a precompiler sourcecode which you can adapt , which is a very easy thing to do.
The results for Preass can be found here:
Heart of the system is the "oop.library", which offers 3 functions:
new() generates new objects, del() destroys them and domethode() calls methods of the generated objects.
Objects are defined in Classes, which can be found in classfiles, postfix .class. These classes will be precompiled with the precompiler preassxx , compiled with preass and assembled with ASM-One. If you wanne use another programming language then look here. The compiled files are real nativ Amiga Shared Libraries.
Classes will only be generated once. Any number of objects can created from these classes. A class is definied as followed:
class classname { variables and objectes methods() {} }Eine Klasse kann eine andere Klasse erweitern und dadurch die Methoden und Variablen der Superklasse erben. A class can extend another class and inherits her methods and variables of the so called superclass.
class b extends a { ... }
Classextentions can be done until you hit the root of the object tree, this means class z can extend y, y can extend x, x can extend w etc. etc..
The name of the extended class can be a fully qualified name or the name without ".class". A packagename (s.b.) can be used also.
Variables are preset from the compiler to long and pointer to long. Preass is used as Compiler, as Assembler ASM-One is used. The praeprozessor Preassxx knows also objects as variables. This is important for constructs like X=objektname.methodenname(arg1,arg2...).methodeY().... Variables can be private ( default state ) or public. This makes only sense for instance variables. You can give this state to any variable used in the methodebody, but there it does not have ANY effect or sense because, these are stackvariables , which can not be accessed from outside. BTW: You can`t access public instance variables too, this is more an indicator for other programmer that these Variables have get and set routines which have to be use instead. This is a strong behaviour compared against other oop systems, i.e. JAVA offers a way to access public variables. If I would do the same, the data inside an object would no longer encapsulated.
Methods can have four different states:
Only public-methods can be access from outside. Abstract methods are methods without methodebodies, without sourcecode after the methodeheader, and can not be compiled!.
class Test { long A B C public setA(long value) { a==value } public setB(long value) { B==value } private setC(long value) { C==value*-1 } public calc() { long returnvalue returnvalue==A*B setC(returnvalue) return returnvalue } } * Test.class is just an example! *if a class wants to use another object it has to instanciate the object with new():
A program which could use the above class
Start: test=new("test",0) domethode(test,"setA",>settag1:10) domethode(test,"setB",>settag2:20) ret=domethode(test,"calc",0) printf("10 * 20 = %ld\n",*ret) test=del(test) {* return *}
class a { long testobject public methode() { testobject=new("test",0) ... del(testobject) } } or class a { long testobject public methode() { testobject new Test ... del(testobject) } }If you use the new New-Syntax you can initialize more than one object at the same time. Just add more variablenames.
class a { public methode() { test1 test2 test3 new Test ... del(test1) del(test2) del(test3) } }As a bonus you can directly initialize an object via it`s Constructor.
class a { public methode() { test1 new Test("Hallo",1492) ... del(test1) } }Because we won`t make use of normal programs any more, there is a program called oopa which can start classes by calling the Main methode of a class. If the class does not have a Main it won`t run this class. oopa parses the commandline arguments to Main.
class a { ... public Main() { Object testobject testobject=new("test",0) Result=testobject.Test() if Result#0 { printf("Result != null\n") } testobject=del(testobject) } }WARNING: There is no GarbageCollector which destroys unused objects. This has to be done by the owner of the object for each himself.It`s save to destroy an objects more than once if you use this construct Object=del(Object). With it the reference to the object will be removed and every further call will be alerted to the user by the oop.library.
If you wanne compile a new version of a class you have to remove the old library from the system. The amigaoslibraryloader normally does not check if a newer version of a library is available after loading one from disk. This spares some time if you have a floppy system, but makes problems if develop with oop4a or other library building tools. For this case we have small tool, which removes the unneeded libs from ram like a GarbageCollector should do. It`s called "flushlibs" and together with the flush tool in okd:bin, you can remove old libs from ram in a given time intervall. Its more or less a small garbage collector and maybe in the future the way to find unused objects. Maybe! You can find flushlibs at aminet or in the odk.
For every object exists a Constructor and a Deconstructor paire. You don`t have to use the "object=del(object)" rule in the deconstructor because there are no more calls in this object :-) .
class a { long testobject public methode() { testobject=new("test.class",0) ... testobject=del(testobject) } public DeConstructor() { del(testobject) } }Im Konstruktor werden Routinen abgearbeitet die bei jedem Erstellen eines Objektes dieser Klasse durchlaufen werden sollen. Dies passiert exakt einmal im Leben eines Ojektes, es sei denn der Konstruktor wird expliziert aufgerufen. Der Dekonstruktor wird auch nur einmal aufgerufen, wenn das Objekt zerstört werden soll. At the Constructor you will place all routines which have to be called everytime an object is generated. This happens exactly one time in the life of an object. If you call the constructor a second time by hand it we be used a second time but that far beyond any coding style! The Deconstructor will be called only one time too! Don`t call it before you wanne destroy it, not even if theres no Deconstructorbody! The precompiler adds a lot stuff the coder won`t see!
Function | Name |
---|---|
Construktor | Constructor() |
Deconstruktor | DeConstructor() |
Abstract classes are classes which can not be instanciated, because concret methodebodies are missing!
abstract class A { long Zahl abstract public Methode1(long a,long b) public Methode2(long a,long b) { ... concrete code ... } }This classs A can not be instanciated, because Methode1() does not contain a methodebody. A class B must extend this class and has to add the needed methodebody or has to left the methode abstract to be extended by another class!
class b extends a { public Methode1(long a,long b) { long returnvalue returnvalue==a+b return returnvalue } }This happens because objects can be exchanged if they offer the same interface. An example will make it clear.
class a { Object class String Name Object class Integer Zahl Methode() { Name.Set("hallo") } }Daraus wird das folgende De/KonstruktorPaar zusammengebaut, selbst wenn ein De/Konstruktor vorgeben wird. Bitte beachten Sie das! This will produce the following constructor/deconstructor paire, even if a de/constructor paire is given! Please take care of it!
Constructor() { name=new("String",0) Zahl=new("Integer",0) if name&zahl=0 { del(name) del(zahl) {* UnFramereturn -1*} } } DeConstructor() { del(name) del(zahl) }
Please download the PREASS package from the Preass Page
or from the Download Section and install it first.
the actual preass version in odk:bin is the uptodate one!
After this depack the oop4a archive and copy the oop.library to "libs:". Please
make a tree copy of the source tree to libs:classes which contains only the directories!
Make an Assign odk: to the okd directory and add the okd:bin to your path i.e.
"assign c: odk:bin add" . That's it. You need asmone as "ass" in c: . It could be
that you have to adjust the prefs of asmone at first use. A prefs file containing
the working options is placed in odk:misc , copy it to env: and envarc: .
Packages are build like in JAVA. The name must the relative to
Libs:classes. You can use '/' instead of '.' it's equal, but '.' is more common.
If don't own an internet domain, pls build it like this example:
TopLevelDomain of your home country ( i.e. de ) + name of the author + projectname + .. i.e. de.Cyborg.HamsterkäfigPlace your sourcecode in odk:classes with your package structure as directory tree.
You will find a working preprocessor, or precompiler if want, in odk:source. If you understand how it works you just need to change the output to the needed syntax of your favorite compiler and thats it. Most library part is done in includefiles so it's easy to change the precompilerbackend. All lines of code inside a methodebody are untouched if they are have no keywords inside and these keywords are only "return", "Object" , "long" and "new".
The precompiler works in two steps, first step is to sort all variables, methodes,, objects and other informations in chained lists. The second step produces the outputfile. In step one some parts of step two are done for strings and analysing of constructs.
At the end of the process must be the same library structure with the same behaviour as the original one. Important are the structures and arrays which are used by the oop.library to match the methodenames and argumenttypes.
An important information: all classes which are compiled with PreassXX are threadsafe! if you compiler can off this behaviour you have a problem.
Don`t mess this with syncronised methodes!
Have Fun!