Module oop and EnableClass

Share your advanced PureBasic knowledge/code with the community.
GPI
PureBasic Expert
PureBasic Expert
Posts: 1394
Joined: Fri Apr 25, 2003 6:41 pm

Module oop and EnableClass

Post by GPI »

With Interfaces PureBasic supports a very minimalistic version of oop. Unfortunately you must create and handle vTables. When you want to use inheritance, constructors, destructors and copy-constructors this become very unhandy.
I want a possible to:
  • simple way to declare of class (including vTables)
  • Inheritance (including overwrite of methods from parents)
  • Pointer to objects
  • Support of modules (private and public objects and classes)
  • Constructor
  • Destructors
  • Copy-Constructors
  • Memory-handling by PureBaisc and not with AllocateMemory()
  • Debugging-support
Definition of a class
Here is a simple example:

Code: Select all

Class(cName)
  ParentClass(cParent) ;optional
  DeclareMethods
    <list oft he methods, like in Interface-EndInterface >
  Properties
    <attributes oft he class/object, like in Structure-EndStructure >
  Methods
    <definitions of the methods >
EndClass
The Order of the commands is important. Do not connect the Class() and the ParentClass() line with a “:”, the macros will not work. Even when you don’t have any attributes/Properties, you must add the Properties-Line!
Properties are always private! There is no easy way to access them in Purebasic outside the class. Also there is no way to define static properties, use global variables instead.
The definitions of the methods are like the definition of procedures, for example:

Code: Select all

Method(i,Set,Var.x)
  *self\Value=Var
  self\CheckValue()
  MethodeReturn *self\Value
EndMethod
Method (<type>, <method name> [,<parameter list>])
Unfortunately a definition like "Method.i name(" is not possible. The parameter list can be 10 parmaters long (can be extended in the Method-Macro of my code).
The methods must match to the declartion, it is for my code has no possibly to check this.
self
With *self\ a method can access the properties (read and write), with self\ it is possible to call other methods oft he class.
Important: The definition of the class contains program code. That’s why you can’t define classes in procedures.

Special methods Initalize, Dispose and Clone
Initalize()
Also known as constructor. This method is called, when a new object of this class is created. When the class has a parent class, both Initalize() are called. First the parent Inialize(), then the child Inialize().

Dispose()
Also known as destuctor. This method is called, when an object will be destroyed. Like Initalize() all Dispose() of a class were called, but in different order. First the child Dispose() then the parent Dispose().

Clone()
When a clone of an object is created, it is a 1:1 copy of the original object. When the class allocate memory with AllocateMemory() the clone and the original object reference to the same memory. When now the original free the memory the clone doesn’t get any information about this! When now the clone tries to access the memory, the program crash!
The Clone-method exists to solve this problem. The Clone-Method has no parameter!
My code has already copied the complete object (including arrays, lists and maps). You must only handle the pointer, handles and so on by your own.
For example (in the properties are *buffer and bufferlen attributes)

Code: Select all

Method(i,Clone)
  define *save=*self\buffer
  if *self\buffer
    *self\buffer=AllocateMemory(*self\bufferlen)
    if *self\buffer=0
      MethodReturn #false
    endif
    CopyMemory(*save,*self\buffer,*self\bufferlen)
  endif
  MethodReturn #true
EndMethod
Don’t forget the MethodReturn! You should return #true when you succeed or the object will be destroyed immediately!
IMPORTANT! When you return #False the Dispose()-Method is called next. You should set all critical properties to harmless values, which will not destroy the original object.
Example – like above, only with two memory buffers. When the first AllocateMemory() failed, you must set the pointer to the second memory to zero, because it reference to the original object:

Code: Select all

Method(i,Clone)
  define *save=*self\buffer
  if *self\buffer
    *self\buffer=AllocateMemory(*self\bufferlen)
    if *self\buffer=0
      *self\buffer2=0 ; *buffer2 references to the original, set to 0
      MethodReturn #false
    endif
    CopyMemory(*save,*self\buffer,*self\bufferlen)
  endif
  if *self\buffer2
    *save=*self\buffer2
    *self\buffer2=AllocateMemory(*self\bufferlen2)
    if *self\buffer2=0
      MethodReturn #false
    endif
    CopyMemory(*save,*self\buffer2,*self\bufferlen2)
  endif
  MethodReturn #true
EndMethod
Like Initalize() first the Parent Clone() is called, than the Child Clone().

PureBasic hates Dispose
It is easy to detect, when an object is created. But it is impossible to detect, when an object/variable is destroyed.
Local objects exist until “End” or in procedures until “EndProcedure” or “ProcedureReturn”.
Because of this you must replace this commands with _End, _EndProcedure and _ProcedureReturn. When you miss an _EndProcedure my macros detect this and stop the compiler. A missing _End can be easy detect by the missing “[INFO] _end” on the debug-window. A missing _ProcedureReturn is not so easy to detect.
When the Debugger is running, every local created object increase a counter and when the object is destroyed, the counter is decreased. _End check this counter and when it is not 0, there must be a missing _ProcedureReturn and a message is printed to the debugger window ("[WARNING] not disposed objects: ").

How bad is a missing _ProcedureReturn?
Local objects are created in local variables. PureBasic handle this and free the used memory by the objects. But all handles, allocated memory and so on will not be freed, because this should handle the Dispose() method.

_End
_End will not work in procedures. It must be placed in the main code.

_FakeEnd
Same as end, this command Dispose() every local and global object, but the program will not be terminated. Usefull for debugging.

Activate complete object monitoring
When you define a constant before the Include of the Module_oop.pbi, a complete monitoring of all objects will activate.

Code: Select all

#__class_debug_all_objects=#True
XIncludeFile("Module_oop.pbi")
Now “_End” will display all objects which are not correctly Disposed() with full name and the line where the objects are created. For Example: "[WARNING] Missing dispose:clock.cClock E:\purebasic\OOP\main.pb@239".
This monitoring will slow down the creation and destruction of every object. Also it needs more memory. The monitoring-routines are only active when the debugger is on.

Create an object
Define_Object(<object name>,<class name>)
Protected_Object(<object name>,<class name>)
Global_Object(<object name>,<class name>)
Static_Object(<object name>,<class name>)

When you call one of this macros, an object is defined and initialized. Important, these macros contain program code. When you use it like here:

Code: Select all

If #False
  Define_Object(MyObj,cMyClass)
EndIf
This will not work. Because the Define_Object() is never processed the object will only declared, but not initialized! When you use the created object your program will crash!

Pointer

Code: Select all

*<pointer name>.<class name>
Important

Code: Select all

Define_Object(obj1,cMyClass)
Define_Object(obj2,cMyClass)
Define *pObj.cMyClass
obj1=obj2 ;Bad
*pObj=@obj1 ; Won't work
*pObj=obj1 ; Work
With obj1=obj2 you don’t create a copy of obj2. Instead obj1 reference now to obj2!
With *Obj=@obj1 will not work, because obj1 is for PureBasic already a pointer. You create here a pointer of a pointer.

Allocate_Object(<class name>)
Free_Object(<object>)

With these functions you allocate memory for a new object. You must release the object by your own with Free_Object().
Important: _End will not Dispose() allocated objects! It will only warn you, when you forget to Disposed allocated objects ("[WARNING] not disposed allocated objects: ").

Inheritance and method overwrite
For example:

Code: Select all

Class(cVar)
  DeclareMethods
    Set(x)
    Get()
  Properties
    value.i
  Methods
    Method(i,Set,x.i)
      *self\value=x
    EndMethod
    Method(i,Get)
      MethodReturn *self\value
    EndMethod
EndClass

Class(cVar2)
  ParentClass(cVar)
  DeclareMethods
    OldSet(x)
  Properties
  Methods
    AliasMethod(Set,OldSet)
    Method(i,Set,x)
      *self\value=x*2
    EndMethod
EndClass

Define_Object(obj1,cVar2)
Define *obj2.cVar

obj1\Set(20) 
Debug obj1\Get(); Return 40
obj1\OldSet(20)
Debug obj1\Get(); Return 20

*obj2=obj1
*obj2\Set(30)
Debug obj2\Get(30); Return 60!
The class cVar2 is a child of cVar. In cVar2 the method “Set” will be overwritten. Because set is already declared in cVar, it is not allowed to declare it in cVar2.
With AliasMethod you can save a method of the parent class before you overwrite it with a new one. The alias must be declared in the DeclareMethods section.
It is important, that the method type and the parameters aren’t changed. It is not possible to check this by my routines, because PureBasice doesn’t support any type check.
Maybe you are surprised that the pointer *obj2 (type cVar) called the Set method of cVar2. The object decides which version is called and the object is a cVar2 class.
You can set a pointer of a parent class (here cVar) to an object of the child class (cVar2) without any problems, because all methods and properties of the parent are also in the child.

A save way to set an object
PureBasic allows setting a pointer of a class to an object of a complete different class. When you now use the pointer, random methods with random parameters are called and the result will be funny. To find such kind of errors are very difficult.
I create a function to check the class of an object, here is an example.

Code: Select all

*obj2=Object_CheckClass(obj1,cVar)
Object_CheckClass() controls the object (here obj1) it if belongs to the class (cVar) or if the object is a child of the class. When true, it returns the object itself or #Null if false.
When in the above example obj1 is from a diffrent class, the pointer *obj2 will be filled with a „null object“. When now the program tries to use this object, the program will crash “clean”. This is much easier to debug than random events.

There is a special function designed for the procedures, which needed pointers to objects in parameters.
Object_ForceClass(<object>,<class name>)
When the check fails, automatically the debugger is called and the program is terminated.

Special class oop::object
oop::object is a root-class. A pointer to this class can contain any object of any class. This class contains some methods that may be useful:

Method GetClassName()
Return the name of the class of the object. Important, not the class of the pointer!

Method Size()
Return the base-size of an object.

Method CloneFrom(<source-object>)
Destroy the object and create a copy oft he source object. The objects must belong to the exact same class.
Example:

Code: Select all

  Protected_Object(obj1,cVar)
  Protected_Object(obj2,cVar)
  obj2\Set(30)
  obj1\CloneFrom(obj2)
If cloning fail, CloneFrom() return #False otherwise #True.

Method AllocateClone()
Create a clone of the object and return the new allocated object. This object must be destroyed with Free_Object() manually. When cloning fails, it return 0 otherwise the object.

Method Reset()
Dispose() and re-Initalize() the object.

Module
When you want to use classes, you must enable it with this line in DeclareModul:

Code: Select all

UseModule EnableClass
Private and public objects
Simple use for example Define_Object() in the DeclareModul-EndDeclareModule section to create a public object or in the Module-EndModule-Section for privat objects.

Private class
Definite the class in Module-EndModule-section for a private class.

Public class
You must declare the class between DeclareModule-EndDeclareModule and define it in the Module-EndModule.
Here is an example, how to do this:

Code: Select all

DeclareModule TestModul1

  UseModule EnableClass
  
  DeclareClass(cTM1)
    DeclareMethods
      Get()
      Set(v.i)
    Properties
      value.i
  EndDeclareClass

EndDeclareModule

Module TestModul1

  DefineClass(cTM1)
    Method(i,Get)
      MethodReturn *self\value
    EndMethod
    Method(i,Set,v.i)
      *self\value=v
    EndMethod
  EndDefineClass

EndModule
Important: Unlike procedures you can’t use a class after you declare it. You must define it before, or your program will crash. The Problem is, that the vTable is created during the declaration and without it you can’t use objects.

Objects in classes
It is possible to use objects in the properties of a class. You must declare it in the properties-field and then initalize in the Initalize()-Method of the class. My code handles the Clone and Destruct of the Object, but you must Initalize it manually.

Declare_Object(<object-name>,<class>[,<arraysize>)
Only useable in the properties-section. Array size is optional. Array-Size is same as in a structure. When you want to access a object in an array, type something like: *self\<object-name>[1].

Initalize_Object(<object-name>,<class>[,<arraysize>)
Should only used in the Initalize-Method of a class.

Example:

Code: Select all

 Class(cDeep2);- cDeep2
    DeclareMethods
    Properties
      Declare_Object(var,cDeep1,2)
    Methods
      Method(i,Initalize)
        Initalize_Object(var,cDeep1,2)     
        *self\fakemem=fakealloc()
      EndMethod
  EndClass
Other Functions/Macros

SizeOf_Class(<class name>)
Return the size of an object of the class.

DebugCreate_Obj(<obj name>,<message>)
Create a message in the debug-window, which contain the object name, class name and the position in sourcecode which the object was created.

Setup the IDE
I suggest to add this words to the "Costum-Keywords" list in the preferences:

Code: Select all

Class
DeclareClass
DefineClass
ParentClass
DeclareMethods
Properties
Methods
EndDeclareClass
Method
MethodReturn
EndMethod
AliasMethod
EndClass
EndDefineClass
Allocate_Object
Free_Object
Protected_Object
Global_Object
Define_Object
Static_Object
Declare_Object
Initalize_Object
_FakeEnd
_End
_EndProcedure
_ProcedureReturn
self
and under "Indentation"

Code: Select all

_EndProcedure -1 0
Class 0 1
DeclareClass 0 1
DefineClass 0 1
DeclareMethods 0 1
EndClass -2 0
EndDeclareClass -2 0
EndDefineClass -1 0
EndMethod -1 0
Method 0 1
Methods -1 1
Properties -1 1
Last edited by GPI on Sun Sep 20, 2015 9:15 pm, edited 1 time in total.
GPI
PureBasic Expert
PureBasic Expert
Posts: 1394
Joined: Fri Apr 25, 2003 6:41 pm

Re: Module oop and EnableClass

Post by GPI »

Module_oop.pbi

Code: Select all

;*
;* Module oop and EnableClass
;*
;* Version: 1.1
;* Date: 2015-09-20
;*
;* Written by GPI
;*

;* Changelog
;* 1.1
;*    - some code improvments
;*    - ThreadSave - Mutex for global/static objects
;*    - Declare_Object and Initalize_Object for "Properties"
;*    - Self/CloneFrom() - reset object on fail
;*    - Self/Reset() - destroy und reinitalize object with default values

CompilerIf #PB_Compiler_IsMainFile
  #__Class_debug_all_objects=#True
CompilerEndIf



CompilerIf Not Defined(__Class_debug_all_objects,#PB_Constant)
  #__Class_debug_all_objects=#False
  ;when true, monitor all objects and output all object without dispose on "_end"
  ;for example: [WARNING] Missing dispose:clock.cClock E:\purebasic\OOP\main.pb@239
  ;only with debugger
CompilerEndIf

;- ***
;- *** module oop
;- ***


CompilerIf #__Class_debug_all_objects
  DeclareModule oop
    #debug_all_objects=#True
  CompilerElse
    DeclareModule oop
      #debug_all_objects=#False
    CompilerEndIf
   
   
   
    EnableExplicit
   
   
    ;-
    ;-{ Macro Creation
   
    Macro MacroColon
      :
    EndMacro
   
    Macro MacroQuote
      "
    EndMacro
   
    Macro JoinMacroParts (P1, P2=, P3=, P4=, P5=, P6=, P7=, P8=)
      P1#P2#P3#P4#P5#P6#P7#P8
    EndMacro
   
    Macro CreateMacro (name,macroBody=)
      oop::JoinMacroParts (Macro name, oop::MacroColon, macroBody, oop::MacroColon, EndMacro)
    EndMacro
   
    Macro CreateQuote (name)
      oop::JoinMacroParts (oop::MacroQuote, name, oop::MacroQuote)
    EndMacro
    ;}
    ;-
   
    ;-
    ;-{ Basisclasse Object
    Declare AllocateClone (*self)
    Declare CloneFrom (*self,*source)
    Declare __Init (*self)
    Declare __Disp (*self)
    Declare.s GetClassName (*self)
    Declare __CheckClass (*self,*table)
    Declare Size (*self)
    Declare Reset(*self)
   
    CompilerIf #PB_Compiler_Debugger
      Declare __DebugOut (*self,message.s)
    CompilerEndIf
   
    DataSection     
      object__Class__Name:
      Data.s "object"
    EndDataSection
   
    Interface object
      AllocateClone()
      CloneFrom(*obj)
      __init()
      __disp()     
      GetClassName.s()
      __CheckClass(*table)
      Size()
      Reset()
      __Initalize()
      __Dispose()
      __Clone()
      __VTable_parent() ;var
      __CopyStructure(*new)
      __AllocateStructure()
      __ResetStructure()
      __classname();var
      __size()     ;var
      __deep()     ;var
      CompilerIf #PB_Compiler_Debugger
        __DebugOut(test.s)
      CompilerEndIf   
    EndInterface
   
    Structure object__Class__VTable
      *AllocateClone
      *CloneFrom
      *__init
      *__disp
      *GetClassName
      *__CheckClass
      *Size
      *Reset
      *__Initalize
      *__Dispose
      *__Clone
      *__VTable_parent.object__Class__VTable   
      *__CopyStructure
      *__AllocateStructure
      *__ResetStructure
      *__classname
      *__size
      *__deep
      CompilerIf #PB_Compiler_Debugger
        *__DebugOut
      CompilerEndIf   
    EndStructure
   
    Structure object__Class__struc
      *__VTable.object__Class__VTable   
      *__dispose_chain
      *__properties_chain
      CompilerIf #PB_Compiler_Debugger
        __objname.s
        __creationline.l
        __creationfile.s
      CompilerEndIf
    EndStructure
   
    Global object__Class__functions.object__Class__VTable
    object__Class__functions\AllocateClone=@AllocateClone()
    object__Class__functions\CloneFrom=@CloneFrom()   
    object__Class__functions\__init=@__init()
    object__Class__functions\__disp=@__disp()
    object__Class__functions\GetClassName=@GetClassName()
    object__Class__functions\__CheckClass=@__CheckClass()
    object__Class__functions\Size=@Size()
    object__Class__functions\Reset=@Reset()
    object__Class__functions\__classname=?object__Class__Name
    object__Class__functions\__size=SizeOf(object__Class__struc )
    object__Class__functions\__deep=-1
   
    CompilerIf #PB_Compiler_Debugger
      object__Class__functions\__DebugOut=@__DebugOut()
    CompilerEndIf 
    ;}
    ;-
   
    ;-
    ;-{ Debug
    CompilerIf #PB_Compiler_Debugger
      Global counter__object.i
      Global counter__allocate__object.i
    CompilerEndIf
   
    CompilerIf #debug_all_objects And #PB_Compiler_Debugger
      Declare addobj(*obj.object)
      Declare subobj(*obj.object)
      Declare listobj()
    CompilerElse
      Macro addobj(a)
      EndMacro
      Macro subobj(a)
      EndMacro
      Macro listobj()
      EndMacro
    CompilerEndIf
    ;}
    ;-
   
    ;-
    ;-{ Common
    Define Mutex_GlobalChain=CreateMutex()
    Global *__Class__global_dispose_chain
    Define *__Class__define_dispose_chain
   
    CompilerIf #PB_Compiler_Debugger
      Declare Obj_init(*objVTable, size, *obj.object,name$,line,file$ )
    CompilerElse
      Declare Obj_init(*objVTable, size, *obj.object)
    CompilerEndIf
   
    Macro newobj(access,obj,ClassName,lis)
      CompilerIf (Not Defined(*__Class__define_dispose_chain,#PB_Variable) Or #PB_Compiler_Procedure="") And oop::CreateQuote(__Class__endprocedurecheck()) = "fail"
        CompilerError "missing _EndProcedure or _ProcedureReturn above this line!"
      CompilerEndIf 
     
      CompilerIf oop::CreateQuote(lis)="Define" And #PB_Compiler_Procedure<>"" And Not Defined(*__Class__define_dispose_chain,#PB_Variable)
        Define *__Class__define_dispose_chain.oop::object__Class__struc
      CompilerEndIf
     
      access obj#__Class__obj.ClassName#__Class__struc
      access obj.ClassName
     
      If obj=0
        obj=obj#__Class__obj 
        obj#__Class__obj\__VTable=ClassName#__Class__functions
        CompilerIf #PB_Compiler_Debugger
          obj#__Class__obj\__objname=oop::CreateQuote(obj)
          obj#__Class__obj\__creationline=#PB_Compiler_Line
          obj#__Class__obj\__creationfile=#PB_Compiler_File
          oop::addobj(obj)
        CompilerEndIf   
        obj\__init()
       
       
        CompilerIf oop::CreateQuote(lis)="Global" Or #PB_Compiler_Procedure=""
          CompilerIf oop::CreateQuote(lis)="Global" And #PB_Compiler_Thread
            LockMutex(oop::Mutex_GlobalChain)
          CompilerEndIf
          obj#__Class__obj\__dispose_chain=oop::*__Class__#lis#_dispose_chain
          oop::*__Class__#lis#_dispose_chain=obj
          CompilerIf oop::CreateQuote(lis)="Global" And #PB_Compiler_Thread
            UnlockMutex(oop::Mutex_GlobalChain)
          CompilerEndIf
        CompilerElse     
          obj#__Class__obj\__dispose_chain=*__Class__#lis#_dispose_chain
          *__Class__#lis#_dispose_chain=obj
        CompilerEndIf
       
        CompilerIf #PB_Compiler_Debugger
          oop::counter__object+1
        CompilerEndIf
      EndIf
     
      CompilerIf oop::CreateQuote(__Class__endprocedurecheck()) = "__Class__endprocedurecheck()" And #PB_Compiler_Procedure<>"":oop::CreateMacro(__Class__endprocedurecheck(),fail):  CompilerEndIf
    EndMacro
   
    Macro Dispose_local_obj()
      CompilerIf #PB_Compiler_Procedure<>""
        CompilerIf Defined(*__Class__define_dispose_chain,#PB_Variable)
          oop::dispose_chain(*__Class__define_dispose_chain)
          *__Class__define_dispose_chain=0
        CompilerEndIf
      CompilerElse
        oop::dispose_chain(oop::*__Class__define_dispose_chain)
        oop::*__Class__define_dispose_chain=0
      CompilerEndIf
     
    EndMacro
   
    Macro Dispose_global_obj()
      oop::dispose_chain(oop::*__Class__global_dispose_chain)
      oop::*__Class__global_dispose_chain=0
    EndMacro
   
   
    Declare dispose_chain(obj.object)
    ;}
    ;-
   
  EndDeclareModule
 
  Module oop
   
    ;-
    ;-{ common
    CompilerIf #PB_Compiler_Debugger
      Procedure Obj_init(*objVTable,size, *obj.oop::object,name$,line,file$ )  : ;EndIndent
                                                                                 ;}
    CompilerElse
      Procedure Obj_init(*objVTable,size, *obj.oop::object)
      CompilerEndIf
      Protected *obj_struc.object__Class__struc=*obj
      If *obj
        *obj_struc\__VTable=*objVTable
        CompilerIf #PB_Compiler_Debugger
          *obj_struc\__objname=name$
          *obj_struc\__creationline=line 
          *obj_struc\__creationfile=file$
          addobj(*obj)
          oop::counter__allocate__object+1
        CompilerEndIf   
        *obj\__init()
       
      EndIf
      ProcedureReturn *obj
    EndProcedure
    Procedure dispose_chain(obj.object)
      Define *obj.oop::object__Class__struc=obj
      Define *next
      While *obj
        obj=*obj
        *next=*obj\__dispose_chain
        *obj\__dispose_chain=0
        If *obj\__VTable
          obj\__Disp()
          CompilerIf #PB_Compiler_Debugger
            oop::counter__object-1
            oop::subobj(obj)
          CompilerEndIf
        EndIf
        *obj=*next
      Wend
    EndProcedure
    ;}
    ;-
   
    ;-
    ;-{ object methods
   
   
    Procedure reset(*self.object__Class__struc)
      Define save.object__class__struc
      Define *VTable.object__Class__VTable=*self\__vtable
     
      CopyStructure(*self,save,object__Class__struc);backup base settings
     
      CallFunctionFast(*VTable\__disp,*self);destroy
     
      CallFunctionFast(*VTable\__ResetStructure,*self);reset values
     
      CopyStructure(save,*self,object__Class__struc);restore base settings
     
      CallFunctionFast(*vtable\__Init,*self);initalize
    EndProcedure
   
    Procedure CountObjects(*self.object__Class__struc)
      Define *obj.object__Class__struc
      Define count
      *obj=*self\__properties_chain
      While *obj
        If *obj\__properties_chain
          count+CountObjects(*obj)     
        EndIf     
        Count+1     
        *obj=*obj\__dispose_chain
      Wend 
      ProcedureReturn count
    EndProcedure
   
    Structure SavedObject
      *int.long
      *obj.object__Class__struc
      save.object__Class__struc
    EndStructure
   
    Procedure SaveObjects(*self.object__Class__struc,Array saveobj.Savedobject(1),i=0)
      Define *obj.object__Class__struc
      *obj=*self\__properties_chain
      While *obj
        saveobj(i)\int=*self+PeekL(*obj-SizeOf(long))
        saveobj(i)\obj=*obj
       
        CopyStructure(*obj,saveobj(i)\save,object__Class__struc)
        i+1     
        i=SaveObjects(*obj,SaveObj(),i)     
       
        *obj=*obj\__dispose_chain
      Wend 
      ProcedureReturn i
    EndProcedure
   
    Procedure CloneChain(*self.object__Class__struc)
      Define i
      Define ret=#True
      Define *VTable.object__Class__VTable
     
      *VTable=*self\__VTable   
      ;If *VTable\__deep
      Dim *saveClone(*VTable\__deep)
     
      While *VTable
        If *VTable\__Clone
          *saveClone(i)=*VTable\__Clone
          i+1
        EndIf
        *VTable=*VTable\__VTable_parent
      Wend 
     
      While i>0
        i-1
        ret & CallFunctionFast(*saveClone(i),*self)
      Wend
      ;EndIf
      ProcedureReturn ret
    EndProcedure
   
   
    Procedure RecoverObjects(*self.object__Class__struc,*new.object__Class__struc,Array *objlist.object__Class__struc(1),i=0)
      Define *obj.object__Class__struc
      Define *objnew.object__Class__struc
      Define i
      *obj=*self\__properties_chain
      *objnew=*new+(*obj-*self)
      *new\__properties_chain=*objnew
      Repeat     
        PokeI(*new+PeekL(*obj-SizeOf(long)),*objnew)
        *objlist(i)=*objnew       
        i+1
       
        If *obj\__properties_chain
          i=RecoverObjects(*obj,*objnew,*objlist(),i)
        EndIf
       
       
        *obj=*obj\__dispose_chain
        If *obj
          *objnew\__dispose_chain=*new+(*obj-*self)
          *objnew=*objnew\__dispose_chain       
        EndIf     
      Until *obj=0
      ProcedureReturn i
    EndProcedure       
   
    Procedure AllocateClone (*self.object__Class__struc)
      Define ret=#True
      Define *new.object__Class__struc
      Define count
      Define i
      Define *VTable.object__Class__VTable
     
      *VTable=*self\__VTable
      *new=CallFunctionFast(*VTable\__AllocateStructure,*self)
      If *new=0
        ProcedureReturn #False
      EndIf
     
      If *self\__properties_chain
        count=CountObjects(*self)
      EndIf
     
      CallFunctionFast(*VTable\__CopyStructure,*self,*new)
      *new\__dispose_chain=0
      *new\__properties_chain=0
      CompilerIf #PB_Compiler_Debugger
        *new\__objname="*clone:"+*self\__objname
        oop::addobj(*new)
        oop::counter__allocate__object+1
      CompilerEndIf   
     
      If count
        Dim *ObjList.object__Class__struc(count-1)
        RecoverObjects(*self,*new,*ObjList())
        For i=count-1 To 0 Step -1
          ret & CloneChain(*ObjList(i))
          CompilerIf #PB_Compiler_Debugger
            *ObjList(i)\__objname="*clone:"+*ObjList(i)\__objname
            oop::addobj(*ObjList(i))
            counter__object+1
          CompilerEndIf
        Next 
      EndIf
     
     
      ret & CloneChain(*new)
     
      If ret=#False
        CallFunctionFast(*vtable\__disp,*new)
        FreeStructure(*new)
       
        CompilerIf #PB_Compiler_Debugger
          oop::subobj(*new)
          oop::counter__allocate__object-1     
        CompilerEndIf     
        *new=0     
      EndIf   
     
      ProcedureReturn *new 
    EndProcedure
   
    Procedure CloneFrom (*self.object__Class__struc,*source.object__Class__struc)
      Define ret.i=#True
      Define save.object__Class__struc
      Define count
      Define i
      Define *VTable.object__Class__VTable
     
      If *self\__VTable<>*source\__VTable  Or *self=*source
        reset(*self)
        ProcedureReturn #False
      EndIf
     
      ;save before dispose because dispose kills the vtable
      If *self\__properties_chain
        count=CountObjects(*self)
       
        Dim SaveObj.SavedObject(count-1)
        SaveObjects(*self,SaveObj())
      EndIf
     
     
      ;Destroy the original object and copy from source
      *VTable=*self\__VTable
      CopyStructure(*self,save,object__Class__struc)
      CallFunctionFast(*VTable\__disp,*self)
      CallFunctionFast(*VTable\__CopyStructure,*source,*self)
      CopyStructure(save,*self,object__Class__struc)
     
      If count
        CompilerIf #PB_Compiler_Debugger
          ;__disp will destroy the local objects, but we are recreate the objects from the copy
          counter__object+count
        CompilerEndIf
        For i=count-1 To 0 Step -1
          SaveObj(i)\int\l=SaveObj(i)\obj
          CopyStructure(SaveObj(i)\save,SaveObj(i)\obj,object__class__struc)
          ret & CloneChain(SaveObj(i)\obj)
        Next
      EndIf
     
      ret & CloneChain(*self)
     
      If ret=0
        reset(*self)
      EndIf   
     
      ProcedureReturn ret   
    EndProcedure
   
    Procedure __Init (*self.object__Class__struc)
      Define *VTable.object__Class__VTable
      Define i
     
      *VTable=*self\__VTable 
     
      ;If *vtable\__deep
      Dim *saveInitalize(*vtable\__deep)
     
      While *VTable
        If *VTable\__Initalize
          *saveInitalize(i)=*VTable\__Initalize
          i+1
        EndIf
        *VTable=*VTable\__VTable_parent
      Wend 
     
      While i>0
        i-1
        CallFunctionFast(*saveInitalize(i),*self)
      Wend     
      ;EndIf 
    EndProcedure
   
    Procedure __Disp (*self.object__Class__struc)
      Define *VTable.object__Class__VTable
     
      *VTable=*self\__VTable
     
      While *VTable
        If *VTable\__Dispose
          CallFunctionFast(*VTable\__Dispose,*self)
        EndIf
        *VTable=*VTable\__VTable_parent
      Wend 
     
      If *self\__properties_chain
        dispose_chain(*self\__properties_chain)
      EndIf
     
      *self\__VTable=0     
    EndProcedure
   
    Procedure.s GetClassName (*self.object__Class__struc)
      ProcedureReturn PeekS(*self\__VTable\__classname)
    EndProcedure
   
    Procedure __CheckClass (*self.object__Class__struc,*table)
      Define *VTable.object__Class__VTable
      *VTable=*self\__VTable
     
      If *table=object__Class__functions
        ProcedureReturn *self
      EndIf
     
     
      While *VTable
        If *table=*VTable
          ProcedureReturn *self
        EndIf
        *VTable=*VTable\__VTable_parent
      Wend
     
      ProcedureReturn #Null
    EndProcedure
   
    Procedure Size (*self.object__Class__struc)
      ProcedureReturn *self\__vtable\__size
    EndProcedure
   
    CompilerIf #PB_Compiler_Debugger
      Procedure __DebugOut (*self.object__Class__struc,message.s)
        Debug message +": "+*self\__objname+"."+PeekS(*self\__VTable\__ClassName)+" "+*self\__creationfile+"@"+Str(*self\__creationline)
      EndProcedure
    CompilerEndIf
    ;}
    ;-
   
    ;-
    ;-{ Debug all objects
    CompilerIf #debug_all_objects And #PB_Compiler_Debugger
      Structure Class_debug
        *obj
        line.s
      EndStructure
     
      Global NewList allobj.Class_debug()
      Procedure addobj(*obj.object)
        Protected *obj_struc.object__Class__struc=*obj
        AddElement(allobj())
        allobj()\obj=*obj
        allobj()\line=*obj_struc\__objname+"."+PeekS(*obj_struc\__VTable\__ClassName)+" "+*obj_struc\__creationfile+"@"+Str(*obj_struc\__creationline)
       
      EndProcedure
      Procedure subobj(*obj.object)
        ForEach (allobj())
          If allobj()\obj=*obj
            DeleteElement(allobj())
            Break
          EndIf
        Next
      EndProcedure
      Procedure listobj()
        ForEach allobj()
          Debug "[WARNING] Missing dispose: "+allobj()\line
        Next   
      EndProcedure
    CompilerEndIf
    ;}
    ;-
   
   
  EndModule
 
  ;- ***
  ;- *** Module EnableClass
  ;- ***
 
  DeclareModule EnableClass
    EnableExplicit
   
    #PB_Class=#PB_Interface
   
    ;-
    ;-{ Declaration and Definition
   
    Macro Class(ClassName):   ;EndIndent
     
      CompilerIf Not #PB_Compiler_Procedure="" Or Defined(__Class__BeyondEnd,#PB_Constant)   
        CompilerError "Don't define Class after _End or in Procedures"
      CompilerEndIf 
     
      DataSection     
        ClassName#__Class__Name:
        Data.s oop::CreateQuote(ClassName)
      EndDataSection 
     
      oop::CreateMacro(__currentClass(),ClassName)   
    EndMacro
   
    Macro DeclareClass(ClassName):;EndIndent
      Class(ClassName):           ;EndIndent
    EndMacro
   
    Macro DefineClass(ClassName):  ;EndIndent
      CompilerIf Not #PB_Compiler_Procedure="" Or Defined(__Class__BeyondEnd,#PB_Constant)   
        CompilerError "Don't define Class after _End or in Procedures"
      CompilerEndIf
     
      oop::CreateMacro(__currentClass(),ClassName)   
    EndMacro
   
    Macro ParentClass(ClassName)
      oop::CreateMacro(__parentClass(), ClassName)
    EndMacro
   
    Macro DeclareMethods  :    ;EndIndent
      CompilerIf oop::CreateQuote(__parentClass()) = "__parentClass()"
       
        Interface __currentClass() Extends oop::object:      ;EndIndent
       
      CompilerElse
        Interface __currentClass() Extends __parentClass():  ;EndIndent
       
      CompilerEndIf
     
    EndMacro
   
    Macro Properties   
      EndInterface  ;Indent
     
      CompilerIf oop::CreateQuote(__parentClass()) = "__parentClass()"
        Structure __currentClass()__Class__struc Extends oop::object__Class__struc     : ;EndIndent
       
      CompilerElse
        Structure __currentClass()__Class__struc Extends __parentClass()__Class__struc : ;EndIndent
       
      CompilerEndIf
     
    EndMacro
   
    Macro Methods 
      EndStructure: ;Indent
      Structure __currentClass()__Class__substruc
        offset.l
        struc.__currentClass()__Class__struc
      EndStructure
     
      Structure __currentClass()__Class__VTable extends oop::object__Class__VTable
        space.b[SizeOf( __currentClass() )-SizeOf(oop::object__Class__VTable)]
      EndStructure
      Global __currentClass()__Class__functions.__currentClass()__Class__VTable
     
      CompilerIf oop::CreateQuote(__parentClass()) <> "__parentClass()"
        CopyMemory(__parentClass()__Class__functions,__currentClass()__Class__functions,SizeOf( __parentClass() ))
        __currentClass()__Class__functions\__VTable_parent= __parentClass()__Class__functions
        __currentClass()__Class__functions\__Initalize=0
        __currentClass()__Class__functions\__Dispose=0
        __currentClass()__Class__functions\__Clone=0
       
      CompilerElse
        CopyMemory(oop::object__Class__functions,__currentClass()__Class__functions,SizeOf( oop::object ))
       
      CompilerEndIf 
      __currentClass()__Class__functions\__deep+1
      __currentClass()__Class__functions\__classname=?__currentClass()__Class__Name
      __currentClass()__Class__functions\__size=SizeOf(__currentClass()__Class__struc )
    EndMacro
   
    Macro EndDeclareClass    ;Indent 
    Methods                  ;Indent
     
      UndefineMacro __currentClass
      UndefineMacro __parentClass
    EndMacro
   
   
    Macro Method(ret,func,p1=,p2=,p3=,p4=,p5=,p6=,p7=,p8=,p9=,p10=) ;EndIndent
      CompilerIf      oop::CreateQuote(p1)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc) ;EndIndent
      CompilerElseIf oop::CreateQuote(p2)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p3)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p4)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p5)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3,p4)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p6)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3,p4,p5)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p7)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3,p4,p5,p6)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p8)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3,p4,p5,p6,p7)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p9)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3,p4,p5,p6,p7,p8)  ;EndIndent
      CompilerElseIf oop::CreateQuote(p10)=""
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3,p4,p5,p6,p7,p8,p9)  ;EndIndent
      CompilerElse
        Procedure.ret  __currentClass()__Class__#func(*self.__currentClass()__Class__struc,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10)  ;EndIndent
      CompilerEndIf
      Protected self.__currentClass()=*self
     
      oop::CreateMacro(__currentfunc(),func)
    EndMacro
   
    Macro MethodReturn
      _ProcedureReturn
    EndMacro
   
    Macro EndMethod
      ;Indent
      _EndProcedure ;Indent
      CompilerIf oop::CreateQuote(__currentfunc())="Initalize" Or oop::CreateQuote(__currentfunc())="initalize" Or  oop::CreateQuote(__currentfunc())="Dispose" Or oop::CreateQuote(__currentfunc())="dispose" Or oop::CreateQuote(__currentfunc())="Clone" Or oop::CreateQuote(__currentfunc())="clone"
        __currentClass()__Class__functions\__#__currentfunc() =@__currentClass()__Class__#__currentfunc() ()
      CompilerElse
        PokeI(__currentClass()__Class__functions+OffsetOf(__currentClass()\__currentfunc() ()),@__currentClass()__Class__#__currentfunc() ())
      CompilerEndIf 
      UndefineMacro __currentfunc
    EndMacro
   
    Macro AliasMethod(oldfunc,newfunc)
      PokeI(__currentClass()__Class__functions+OffsetOf(__currentClass()\newfunc ()), PeekI(__currentClass()__Class__functions+OffsetOf(__currentClass()\oldfunc ())))
    EndMacro
   
    Macro EndClass  ;Indent
                    ;Indent
      Procedure __currentClass()__Class____CopyStructure(*source,*new)
        ProcedureReturn CopyStructure(*source,*new,__currentClass()__Class__struc)
      EndProcedure
      __currentClass()__Class__functions\__CopyStructure=@__currentClass()__Class____CopyStructure()
      Procedure __currentClass()__Class____AllocateStructure(*self)
        ProcedureReturn AllocateStructure(__currentClass()__Class__struc)
      EndProcedure
      __currentClass()__Class__functions\__AllocateStructure=@__currentClass()__Class____AllocateStructure()
     
      Procedure __currentClass()__Class____ResetStructure(*self)
        ClearStructure(*self,__currentClass()__Class__struc)
        InitializeStructure(*self,__currentClass()__Class__struc)
      EndProcedure
      __currentClass()__Class__functions\__ResetStructure=@__currentClass()__Class____ResetStructure()
     
     
      UndefineMacro __currentClass
      UndefineMacro __parentClass
     
    EndMacro
   
    Macro EndDefineClass
      EndClass ;Indent ;Indent ;Indent
    EndMacro
    ;}
    ;-
   
    ;-
    ;-{ Object Creation and Destruction
   
   
    CompilerIf #PB_Compiler_Debugger 
      Macro Allocate_Object(ClassName)
        oop::Obj_init(ClassName#__Class__functions,SizeOf(ClassName#__Class__struc),AllocateStructure(ClassName#__Class__struc),"*allocate",#PB_Compiler_Line,#PB_Compiler_File)
      EndMacro
    CompilerElse
      Macro Allocate_Object(ClassName)
        oop::Obj_init(ClassName#__Class__functions,SizeOf(ClassName#__Class__struc),AllocateStructure(ClassName#__Class__struc))
      EndMacro
    CompilerEndIf
   
    Declare Free_Object(*obj.oop::object)
   
    Macro Protected_Object(obj,ClassName)
      oop::newobj(Protected,obj,ClassName,Define)
    EndMacro
    Macro Global_Object(obj,ClassName)
      CompilerIf #PB_Compiler_Procedure="" And Not Defined(__Class__BeyondEnd,#PB_Constant)
        oop::newobj(Global,obj,ClassName,Global)
      CompilerElse
        CompilerError "Don't create global obj in procedures or after _END !"
      CompilerEndIf
     
    EndMacro
    Macro Define_Object(obj,ClassName)
      oop::newobj(Define,obj,ClassName,Define)
    EndMacro
   
    Macro Static_Object(obj,ClassName)
      oop::newobj(Static,obj,ClassName,Global)
    EndMacro
   
    Macro Declare_Object(obj,ClassName,size=1);for properties
      obj#__Class__obj.ClassName#__Class__substruc[size]
      obj.ClassName[size]
    EndMacro
   
   
    Macro Initalize_Object(obj,ClassName,size=1);for properties
      Define i__class__position
      For i__class__position=0 To size-1
        If *self\obj[i__class__position]=0
          *self\obj[i__class__position]=*self\obj#__Class__obj[i__class__position]\struc
         
          *self\obj#__Class__obj[i__class__position]\offset=OffsetOf(__currentClass()__Class__struc\obj)+SizeOf(integer)*i__class__position
         
          *self\obj#__Class__obj[i__class__position]\struc\__VTable=ClassName#__Class__functions
          CompilerIf #PB_Compiler_Debugger
            *self\obj#__Class__obj[i__class__position]\struc\__objname=*self\__objname+"."+oop::CreateQuote(__currentClass()\obj)+"["+Str(i__class__position)+"]"
            *self\obj#__Class__obj[i__class__position]\struc\__creationline=#PB_Compiler_Line
            *self\obj#__Class__obj[i__class__position]\struc\__creationfile=#PB_Compiler_File
            oop::addobj(*self\obj[i__class__position])
          CompilerEndIf
          *self\obj[i__class__position]\__init()
         
         
          *self\obj#__Class__obj[i__class__position]\struc\__dispose_chain=*self\__properties_chain
          *self\__properties_chain=*self\obj[i__class__position]
         
          CompilerIf #PB_Compiler_Debugger
            oop::counter__object+1
          CompilerEndIf
        EndIf     
      Next
    EndMacro
   
   
    ;}
    ;-
   
    ;-
    ;-{ Command replace
    Macro _FakeEnd
      CompilerIf oop::CreateQuote(__Class__endprocedurecheck()) = "fail"
        CompilerError "missing _EndProcedure or _ProcedureReturn above this line!"
      CompilerEndIf   
     
      oop::Dispose_global_obj()
      oop::Dispose_local_obj() 
      CompilerIf #PB_Compiler_Debugger
        If oop::counter__object
          Debug "[WARNING] not disposed objects: "+Str(oop::counter__object)
        EndIf
        If oop::counter__allocate__object
          Debug "[WARNING] not disposed allocated objects: "+Str(oop::counter__allocate__object)
        EndIf
        oop::listobj()   
      CompilerEndIf
      Debug "[INFO] _end"
    EndMacro
    Macro _End
      _FakeEnd
      #__Class__BeyondEnd=#True
      End
    EndMacro
   
    Macro _EndProcedure
      oop::Dispose_local_obj()  ;Indent
      UndefineMacro __Class__endprocedurecheck
      EndProcedure  ;Indent
    EndMacro
   
    Macro _ProcedureReturn
      oop::Dispose_local_obj()
    ProcedureReturn ;EndIndent
  EndMacro
  ;}
  ;-
 
  ;-
  ;-{ Class handling
 
  Macro Object_ForceClass(obj,ClassName)
    If obj\__CheckClass(ClassName#__Class__functions) = #False
      CompilerIf #PB_Compiler_Debugger 
        obj\__DebugOut( "[ERROR] Wrong Class, expected" + oop::CreateQuote(ClassName))
        CallDebugger
      CompilerEndIf
      End
    EndIf
  EndMacro
 
 
  Macro Object_CheckClass(obj,ClassName)
    obj\__CheckClass(ClassName#__Class__functions)
  EndMacro
 
 
  Macro SizeOf_Class(ClassName)
    SizeOf(ClassName#__Class__struc)
  EndMacro
 
  Macro DebugCreate_Obj(obj,message)
    CompilerIf #PB_Compiler_Debugger
      obj\__DebugOut(message)
    CompilerEndIf 
  EndMacro
 
 
 
  ;}
  ;-
EndDeclareModule

Module EnableClass
  Procedure Free_Object(*obj.oop::object)
    If *obj
      *obj\__disp()
      CompilerIf #PB_Compiler_Debugger
        oop::counter__allocate__object-1
        oop::subobj(*obj)
      CompilerEndIf
      FreeStructure(*obj)
     
    EndIf
  EndProcedure
EndModule

UseModule EnableClass
Last edited by GPI on Sun Sep 20, 2015 9:16 pm, edited 1 time in total.
GPI
PureBasic Expert
PureBasic Expert
Posts: 1394
Joined: Fri Apr 25, 2003 6:41 pm

Re: Module oop and EnableClass

Post by GPI »

And here is an example (also my test-routines)

Code: Select all

;-***
;-*** TEST
;-***

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
 
  Global NewMap _fakealloc()
 
  Procedure fakealloc()
    Static c.i
    c+1
    _fakealloc(Str(c))=1
    ProcedureReturn c
  EndProcedure
  Procedure fakefree(c)
    If _fakealloc(Str(c))>0
      _fakealloc(Str(c))=0
    Else
      _fakealloc(Str(c))=-1
    EndIf
   
  EndProcedure
  Procedure listfake()
    Define ok=#True
    ForEach _fakealloc()
      If _fakealloc()<>0
        ok=#False
      EndIf
    Next
    ProcedureReturn ok
  EndProcedure
  Procedure falidFake(c)
    ProcedureReturn Bool(_fakealloc(Str(c))>0)
  EndProcedure
 
 
  Global TestResult=#True
 
  Global TestName.s
 
  Macro Test(a,ss,c)
    Define __aa=a,__cc=c
    _Test(#PB_Compiler_Procedure,Bool(__aa ss __cc),oop::CreateQuote(a ss c),Str(__aa),Str(__cc),oop::CreateQuote(ss))
  EndMacro
  Macro TestS(a,ss,c)
    Define __aas.s=a,__ccs.s=c
    _Test(#PB_Compiler_Procedure,Bool(__aas ss __ccs),oop::CreateQuote(a ss )+" "+__ccs,"",""," ")
  EndMacro
 
 
  Procedure _Test(p.s,bool.i,sa.s,a.s,c.s,s.s)
    If s="<>":s="!":EndIf
    Static back,lastp$,lastTestName$
    Define fc,cok,cfail
   
    If lastTestName$<>TestName
      lastTestName$=TestName
      ConsoleColor(8,0)
      PrintN(TestName+":")
      lastp$=""
    EndIf
   
    If lastp$<>p
      lastp$=p
      ConsoleColor(8,0)
      If lastp$<>""
        PrintN("  ("+lastp$+")")
      Else
        PrintN("  (Main)")
      EndIf   
    EndIf
   
    Print ("     ")
    back!1
    If back
      fc=15
      cfail=12
      cok=10
    Else
      fc=7
      cfail=4
      cok=2   
    EndIf
   
    Define state.s
    ConsoleColor(fc,0)
   
    Print(Left(sa+Space(35+24),35+24) )
   
    Print(Left(Right(Space(5)+a,5)+s.s+Left(c+Space(5),5),11))
    If bool
      ConsoleColor(cok,0)
      PrintN("ok  ")
      ConsoleColor(fc,0)
    Else
      ConsoleColor(cfail,0)
      PrintN("FAIL")
      ConsoleColor(fc,0)
      TestResult=#False
    EndIf 
    ConsoleColor(7,0)
  EndProcedure
 
  Global Init_test.i=1
  Global Clone_test.i=1
 
 
  Class(cTestParent);- cTestParent
    DeclareMethods
    Properties
    Methods
      Method(i,Initalize)
        init_test+1
      EndMethod
      Method(i,Dispose)
        init_test-3
      EndMethod
      Method(i,Clone)
        Clone_test+2
        MethodReturn #True
      EndMethod
     
  EndClass
 
  Class(cTestChild);- cTestChild
    ParentClass(cTestParent)
    DeclareMethods
      get()
    Properties
      *fakemem
    Methods
      Method(i,Initalize)
        init_test*2
        *self\fakemem=fakealloc()
      EndMethod
      Method(i,Dispose)
        init_test*4
        fakefree(*self\fakemem)
        *self\fakemem=0
      EndMethod
      Method(i,Clone)
        ;*old=*self\fakmem
        *self\fakemem=fakealloc()
        ;copy *old\fakemem to *self\fakemem
        Clone_Test*3
        MethodReturn #True
      EndMethod       
      Method(i,get)
        MethodReturn *self\fakemem
      EndMethod   
  EndClass
 
  Class(cTestGrandChild);- cTestGrandchild
    ParentClass(cTestChild)
    DeclareMethods
      getvar()
      setvar(v.i)
    Properties
      value.i
    Methods
      Method(i,Initalize)
        init_test+6
      EndMethod
      Method(i,Dispose)
        init_test-2
      EndMethod
      Method(i,Clone)     
        Clone_test+9
        MethodReturn #True
      EndMethod
      Method(i,GetVar)
        MethodReturn *self\value
      EndMethod
      Method(i,SetVar,v.i)
        *self\value=v
      EndMethod
     
  EndClass
 
  Class(cTestChild2);- cTestChild2
    ParentClass(cTestParent)
    DeclareMethods
    Properties
    Methods
      Method(i,Initalize)
        init_test*5
      EndMethod
      Method(i,Dispose)
        init_test*13
      EndMethod
      Method(i,Clone)
        Clone_test*7
        MethodReturn #True
      EndMethod
  EndClass
 
  Class(cTestCloneFail);- cTestCloneFail
    ParentClass(cTestGrandChild)
    DeclareMethods
    Properties
    Methods
      Method(i,Clone)
        MethodReturn #False
      EndMethod
     
  EndClass
 
  Class(cVar);- cVar
    DeclareMethods
      Set(x)
      Get()
    Properties
      value.i
    Methods
      Method(i,Set,x.i)
        *self\value=x
      EndMethod
      Method(i,Get)
        MethodReturn *self\value
      EndMethod
  EndClass
 
  Class(cVar2);- cVar2
    ParentClass(cVar)
    DeclareMethods
      OldSet(x)
    Properties
    Methods
      AliasMethod(Set,OldSet)
      Method(i,Set,x)
        *self\value=x*2
      EndMethod
  EndClass
 
 
  Class(CSubs);- cSubs
    DeclareMethods
      Get(w.i)
      Set(w.i,v.i)
    Properties
      Declare_Object(Var,cVar)
      Declare_Object(Var2,cVar)
    Methods
      Method(i,Initalize);--Initalize
        Initalize_Object(Var,cVar)
        Initalize_Object(Var2,cVar)
      EndMethod
      Method(i,Get,w.i);--Get
        If w=1
          MethodReturn *self\Var\Get()
        EndIf
        MethodReturn *self\Var2\Get()
      EndMethod
      Method(i,Set,w.i,v.i);--Set
        If w=1
          MethodReturn *self\Var\Set(v)
        EndIf
        MethodReturn *self\Var2\Set(v)
      EndMethod
  EndClass
 
  Class(CSubs2);- cSubs2
    DeclareMethods
      Get(w.i)
      Set(w.i,v.i)
    Properties
      Declare_Object(Var,cVar,2)
    Methods
      Method(i,Initalize)
        Initalize_Object(Var,cVar,2)
      EndMethod
      Method(i,Get,w.i)
        MethodReturn *self\Var[w-1]\Get()
      EndMethod
      Method(i,Set,w.i,v.i)
        MethodReturn *self\Var[w-1]\Set(v)
      EndMethod
  EndClass
 
  Class(cDeep1);- cDeep1
    DeclareMethods
      get()
      set(v.i)
      GetFake()
    Properties
      *fakemem
      value.i
    Methods
      Method(i,Initalize)
        *self\fakemem=fakealloc()
      EndMethod
      Method(i,Dispose)
        fakefree(*self\fakemem)
        *self\fakemem=0
      EndMethod
      Method(i,Clone)
        *self\fakemem=fakealloc()
        ;copy *old\fakemem to *self\fakemem
        MethodReturn #True
      EndMethod   
      Method(i,Set,v.i)
        *self\value=v
      EndMethod
      Method(i,Get)
        MethodReturn *self\value
      EndMethod
      Method(i,GetFake)
        MethodReturn *self\fakemem
      EndMethod   
  EndClass
  Class(cDeep2);- cDeep2
    DeclareMethods
      get(p.i)
      set(p.i,v.i)
      GetFake(p.i)
    Properties
      *fakemem
      value.i
      Declare_Object(var,cDeep1,2);we use only the first one, the second is only for "fakemem"-tests
    Methods
      Method(i,Initalize)
        Initalize_Object(var,cDeep1,2)     
        *self\fakemem=fakealloc()
      EndMethod
      Method(i,Dispose)
        fakefree(*self\fakemem)
        *self\fakemem=0
      EndMethod
      Method(i,Clone)
        *self\fakemem=fakealloc()
        ;copy *old\fakemem to *self\fakemem
        MethodReturn #True
      EndMethod   
      Method(i,Set,p.i,v.i)
        If p=1
          *self\var\set(v)
        Else
          *self\value=v
        EndIf     
      EndMethod
      Method(i,Get,p.i)
        If p=1
          MethodReturn *self\var\get()
        Else
          MethodReturn *self\value
        EndIf     
      EndMethod
      Method(i,GetFake,p)
        If p=1
          MethodReturn *self\var\getfake()
        Else
          MethodReturn *self\fakemem
        EndIf
      EndMethod
  EndClass
  Class(cDeep3);- cDeep3
    DeclareMethods
      get(p.i)
      set(p.i,v.i)
      GetFake(p.i)
    Properties
      *fakemem
      value.i
      Declare_Object(var,cDeep2)
    Methods
      Method(i,Initalize)
        Initalize_Object(var,cDeep2)
        *self\fakemem=fakealloc()
      EndMethod
      Method(i,Dispose)
        fakefree(*self\fakemem)
        *self\fakemem=0
      EndMethod
      Method(i,Clone)
        *self\fakemem=fakealloc()
        ;copy *old\fakemem to *self\fakemem
        MethodReturn #True
      EndMethod   
      Method(i,Set,p.i,v.i)
        If p=1 Or p=2
          *self\var\set(p,v)
        Else
          *self\value=v
        EndIf     
      EndMethod
      Method(i,Get,p.i)
        If p=1 Or p=2
          MethodReturn *self\var\get(p)
        Else
          MethodReturn *self\value
        EndIf     
      EndMethod
      Method(i,GetFake,p)
        If p=1 Or p=2
          MethodReturn *self\var\getfake(p)
        Else
          MethodReturn *self\fakemem
        EndIf
      EndMethod
  EndClass
  Class(cDeep4);- cDeep4
    DeclareMethods
      get(p.i)
      set(p.i,v.i)
      GetFake(p.i)
      GetFake2()
    Properties
      *fakemem
      Declare_Object(var,cDeep3)
    Methods
      Method(i,Initalize)
        Initalize_Object(var,cDeep3)
        *self\fakemem=fakealloc()
      EndMethod
      Method(i,Dispose)
        fakefree(*self\fakemem)
        *self\fakemem=0
      EndMethod
      Method(i,Clone)
        *self\fakemem=fakealloc()
        ;copy *old\fakemem to *self\fakemem
        MethodReturn #True
      EndMethod   
      Method(i,Set,p.i,v.i)
        MethodReturn *self\var\set(p,v)
      EndMethod
      Method(i,Get,p.i)
        MethodReturn *self\var\get(p)
      EndMethod
      Method(i,GetFake,p.i)     
        MethodReturn *self\var\getfake(p)
      EndMethod
      Method(i,GetFake2)
        MethodReturn *self\fakemem
      EndMethod   
  EndClass
  Class(cDeep5);- cDeep5
    ParentClass(cDeep4)
    DeclareMethods
      GetFake3()
    Properties
      *fakemem2
      Declare_Object(var2,cDeep3)
    Methods
      Method(i,Initalize)
        Initalize_Object(var2,cDeep3)
        *self\fakemem2=fakealloc()
      EndMethod
      Method(i,Dispose)
        fakefree(*self\fakemem2)
        *self\fakemem2=0
      EndMethod
      Method(i,Clone)
        *self\fakemem2=fakealloc()
        ;copy *old\fakemem to *self\fakemem
        MethodReturn #True
      EndMethod   
      Method(i,Set,p.i,v.i)
        If p<4
          *self\var\set(p,v)
        Else
          *self\var2\set(p-3,v)
        EndIf     
      EndMethod
      Method(i,Get,p.i)
        If p<4
          MethodReturn *self\var\get(p)
        Else
          MethodReturn *self\var2\get(p-3)
        EndIf     
      EndMethod
      Method(i,GetFake3)
        MethodReturn *self\fakemem2
      EndMethod   
  EndClass
 
 
  ;clonefrom überprüfen
 
 
 
 
 
  OpenConsole()
  EnableGraphicalConsole(1)
  ConsoleColor(7,0)
  ClearConsole()
 
  TestName="Initialize Tests";-{ Initalize Tests
  Procedure InitTest1()
    Define_Object(obj1,cTestParent)
    test(Init_Test,=,2)
    Define_Object(obj2,cTestChild)
    test(Init_Test,=,6)
    Define_Object(obj3,cTestGrandChild)
    test(Init_Test,=,20)
    Define_Object(obj5,cTestChild2)
    test(Init_Test,=,105)
  _EndProcedure
  InitTest1()
  ;}
 
  TestName="Disopse Tests";-{ Dispose Tests
  Procedure DisposeTest1()
    Protected_Object(obj1,cTestGrandChild)
    test(Init_Test,=,48)
  _EndProcedure
  Procedure DisposeTest2()
    Protected_Object(obj1,cTestChild2)
    test(Init_Test,=,910)
  _EndProcedure
  Init_test=20
  DisposeTest1()
  Test(Init_Test,=,181)
  DisposeTest2()
  Test(Init_Test,=,11827)
  ;}
 
  TestName="Clone Tests";-{ Clone Tests
  Procedure CloneTest1()
    Protected i
    Protected *mem1,*mem2
    Protected_Object(obj1,cTestGrandChild)
    Protected_Object(obj2,cTestGrandChild)
    Protected_Object(obj3,cTestParent)
    *mem1=obj1\get()
    *mem2=obj2\get()
    Init_Test=54
    Clone_Test=1
    test(obj1\CloneFrom(obj2),=,#True)
    test(Init_test,=,205)
    test(Clone_Test,=,18)
   
    test(obj1\get(),<>,obj2\get())
    test(obj1\get(),<>,*mem1)
    test(obj2\get(),=,*mem2)
    test(falidfake(obj1\get()),=,#True)
    test(falidfake(obj2\get()),=,#True)
   
    obj1\setvar(99)
    test(obj1\CloneFrom(obj3),=,#False)
    test(obj1\getvar(),=,0)
    obj1\setvar(99)
    test(obj1\CloneFrom(obj1),=,#False)
    test(obj1\getvar(),=,0)
  _EndProcedure
  Procedure CloneTest2()
    Protected_Object(obj1,cVar)
    Protected_Object(obj2,cvar)
    obj1\Set(1)
    obj2\Set(2)
    obj1\CloneFrom(obj2)
    Test(obj1\Get(),=,2)
    obj1\Set(3)
    Test(obj2\Get(),=,2)
  _EndProcedure
  Procedure CloneTest3()
    init_test=0
    Protected_Object(obj1,cTestCloneFail)
    Protected_Object(obj2,cTestCloneFail)
   
   
    obj2\setvar(99)
    test(obj2\CloneFrom(obj1),=,#False)
    test(obj2\getvar(),=,0)
    init_Test=1
    test(obj2\AllocateClone(),=,#False)
    test(Init_test,=,-7)
   
  _EndProcedure
 
  test(listfake(),=,#True)
  CloneTest1()
 
  test(listfake(),=,#True)
  CloneTest2()
 
 
  test(listfake(),=,#True)
  CloneTest3()
 
  test(listfake(),=,#True)
 
  ;}
 
  TestName="Global Tests";-{ Global Tests
  Global_Object(gVar,cVar)
  Procedure GlobalTest1()
    gvar\Set(gvar\get()+1)
  _EndProcedure
  gvar\set(20)
  globalTest1()
  test(gvar\get(),=,21)
  ;}
 
  TestName="Bad Obj1=Obj2 Test";-{ Bad Test
  Procedure BadSet()
    Protected_Object(obj1,cVar)
    Protected_Object(obj2,cVar)
    obj1\set(10)
    obj2\set(20)
    obj1=obj2
    test(obj1\Get(),=,obj2\get())
   
  _EndProcedure
  BadSet()
  ;}
 
  TestName="Pointer Tests";-{ Pointer Test
  Procedure pointer(*obj.cVar)
    test(Object_CheckClass(*obj,cVar),<>,#False)
    Object_ForceClass(*obj,cVar)
    If Not Object_CheckClass(*obj,cVar)
      ProcedureReturn
    EndIf
   
    *obj\set(*obj\get()+10)
   
  _EndProcedure
  Define_Object(pointer1,cvar)
  Define_Object(pointer2,cTestParent)
  pointer(pointer1)
  test(pointer1\Get(),=,10)
  pointer(pointer1)
  test(pointer1\Get(),=,20)
  ;}
 
  TestName="Recursive Test";-{ Recursive Test
  Procedure recursive(*obj.cvar)
    Protected_Object(obj2,cvar)
    Protected x
    x=*obj\get()+1
    *obj\set(x)
    obj2\set(x)
    If *obj\get()<5
      recursive(*obj)
    EndIf
    test(obj2\get(),=,x)
  _EndProcedure
  pointer1\set(0)
  recursive(pointer1)
  test(pointer1\get(),=,5)
  ;}
 
  TestName="Loop Test";-{ Loop Test
  Procedure loop()
    Define i
    For i=1 To 10
      Define_Object(obj,cVar)
      obj\Set(obj\Get()+1)
    Next
    test(obj\Get(),=,10)
  _EndProcedure
  loop()
  ;}
 
  TestName="Static Test";-{ Static Test
  Procedure StaticTest(x)
    Static_Object(obj,cvar)
    obj\Set(obj\Get()+1)
    Test(obj\get(),=,x) 
  _EndProcedure
  StaticTest(1)
  StaticTest(2)
  ;}
 
  TestName="Check Class Test";-{ Check Class Test
  Procedure CheckTest()
    Protected_Object(obj1,cTestParent)
    Protected_Object(obj2,cTestChild)
    Protected_Object(obj3,cTestGrandChild)
    Protected_Object(obj4,cVar)
    Protected_Object(obj5,cTestChild2)
    test(Object_CheckClass(obj1,cTestParent),<>,0)
    test(Object_CheckClass(obj2,cTestParent),<>,0)
    test(Object_CheckClass(obj3,cTestParent),<>,0)
    test(Object_CheckClass(obj4,cTestParent),=,0)
    test(Object_CheckClass(obj5,cTestParent),<>,0)
    test(Object_CheckClass(obj1,cTestChild),=,0)
    test(Object_CheckClass(obj2,cTestChild),<>,0)
    test(Object_CheckClass(obj3,cTestChild),<>,0)
    test(Object_CheckClass(obj4,cTestChild),=,0)
    test(Object_CheckClass(obj5,cTestChild),=,0)
    test(Object_CheckClass(obj1,cTestGrandChild),=,0)
    test(Object_CheckClass(obj2,cTestGrandChild),=,0)
    test(Object_CheckClass(obj3,cTestGrandChild),<>,0) 
    test(Object_CheckClass(obj4,cTestGrandChild),=,0)
    test(Object_CheckClass(obj5,cTestGrandChild),=,0)
    test(Object_CheckClass(obj1,cVar),=,0)
    test(Object_CheckClass(obj2,cVar),=,0)
    test(Object_CheckClass(obj3,cVar),=,0)
    test(Object_CheckClass(obj4,cVar),<>,0)
    test(Object_CheckClass(obj5,cVar),=,0)
    test(Object_CheckClass(obj1,cTestChild2),=,0)
    test(Object_CheckClass(obj2,cTestChild2),=,0)
    test(Object_CheckClass(obj3,cTestChild2),=,0)
    test(Object_CheckClass(obj4,cTestChild2),=,0)
    test(Object_CheckClass(obj5,cTestChild2),<>,0)
  _EndProcedure
  CheckTest()
  ;}
 
  TestName="Modul Test";-{ Modul Test
  DeclareModule TestModul1
    UseModule EnableClass
   
    DeclareClass(cTM1)
      DeclareMethods
        Get()
        Set(v.i)
      Properties
        value.i
    EndDeclareClass
  EndDeclareModule
  Module TestModul1
    DefineClass(cTM1)
      Method(i,Get)
        MethodReturn *self\value
      EndMethod
      Method(i,Set,v.i)
        *self\value=v
      EndMethod
    EndDefineClass
  EndModule
  Procedure Test_Modul1()
    Protected_Object(obj1,TestModul1::cTM1)
    obj1\set(10)
    Test(obj1\get(),=,10)
  _EndProcedure
 
  DeclareModule TestModul2
    UseModule EnableClass
    Declare Output()
    Declare Output2()
  EndDeclareModule
  Module TestModul2
    Class(cTM2)
      ParentClass(TestModul1::cTM1)
      DeclareMethods
        Get2()
        Set2(v.i)
      Properties
        Value2.i
      Methods
        Method(i,Get2)
          MethodReturn *self\Value2
        EndMethod
        Method(i,Set2,v.i)
          *self\Value2=v
        EndMethod
    EndClass
   
    Global_Object(obj2,cTM2)
   
    Procedure Output()
      obj2\set(11)
      ProcedureReturn obj2\get()
    EndProcedure
   
    Procedure Output2()
      obj2\set2(22)
      ProcedureReturn obj2\get2()
    EndProcedure
  EndModule
 
  DeclareModule TestModul3
    UseModule EnableClass
    Global_Object(obj1,TestModul1::cTM1)
  EndDeclareModule
  Module TestModul3
    obj1\set(33)
  EndModule
 
  Test_Modul1()
  test(TestModul2::Output(),=,11)
  test(TestModul2::Output2(),=,22)
  test(TestModul2::Output(),=,11)
  test(TestModul2::Output2(),=,22) 
  test(TestModul3::obj1\get(),=,33)       
  ;}
 
  TestName="Allocate Test";-{ Allocate Test
  Procedure Allocate1()
    Define *obj.cVar
    *obj=Allocate_Object(cVar)
    *obj\set(912)
    test(*obj\get(),=,912)
    Free_Object(*obj) 
    *obj=0
  EndProcedure 
  Procedure Allocate2()
    Define *obj.cVar
    Define *obj2.cVar
    *obj=Allocate_Object(cVar)
    *obj\set(193)
    test(*obj\get(),=,193)
    *obj2=*obj\AllocateClone()
    test(*obj2\get(),=,193)
   
    Free_Object(*obj)
    test(*obj2\get(),=,193)
    Free_Object(*obj2)
  EndProcedure
 
  Allocate1()
  Allocate2()
  ;}
 
  TestName="Class Name Test";-{ Class Name Test
  Procedure ClassName()
    Define_Object(obj1,cTestParent)
    Define_Object(obj2,cTestChild)
    Define_Object(obj3,cTestGrandChild)
    Define_Object(obj4,cVar)
    tests(obj1\GetClassName(),=, "cTestParent")
    tests(obj2\GetClassName(),=, "cTestChild")
    tests(obj3\GetClassName(),=, "cTestGrandChild")
    tests(obj4\GetClassName(),=, "cVar")
  _EndProcedure
  ClassName()
  ;}
 
  TestName="Overwrite Method Test";-{ Overwrite Method Test
  Procedure Overwrite()
    Define_Object(obj1,cVar2)
    obj1\Set(30)
    test(obj1\Get(),=,60)
    obj1\OldSet(30)
    test(obj1\Get(),=,30)
    Define *obj.cVar=obj1
    *obj\Set(30)
    test(*obj\Get(),=,60)
   
  _EndProcedure
  Overwrite()
  ;}
 
  TestName="BaseClass Test";-{ BaseClass Test
  Procedure baseclass()
    Define_Object(obj1,cvar)
    obj1\set(30)
   
    Define *obj.oop::object
    Define *obj2.cvar
    Define *new.cVar
    *obj=obj1
   
    *new=*obj\AllocateClone()
    test(*new\get(),=,30)
    *new\set(20)
    test(*new\get(),=,20)
    test(obj1\get(),=,30)
   
   
    *obj=Allocate_Object(cVar)
    *obj\CloneFrom(*new)
   
    *obj2=*obj
    test(*obj2\get(),=,20)
    *obj2\set(10)
    test(*obj2\get(),=,10)
    test(*new\get(),=,20)
   
    tests(*obj\GetClassName(),=,"cVar")
    tests(*obj2\GetClassName(),=,"cVar")
    tests(*new\GetClassName(),=,"cVar")
   
    test(*obj\size(),=,sizeof_class(cVar))
    test(*obj2\size(),=,sizeof_class(cVar))
    test(*new\size(),=,sizeof_class(cVar))
   
    Free_Object(*obj)
    Free_Object(*new)
   
  _EndProcedure
  baseclass()
  ;}
 
  TestName="Objects in Class Test";-{ Objects in Class Test
  Procedure ObjInClass()
    Define_Object(obj,cSubs)
    Define_Object(obj2,cSubs)
    obj\Set(1,33)
    obj\Set(2,55)
    obj2\Set(1,233)
    obj2\Set(2,255)
    test(obj\Get(1),=,33)
    test(obj\Get(2),=,55)
    test(obj2\Get(1),=,233)
    test(obj2\Get(2),=,255)
  _EndProcedure
  Procedure ObjInClass2()
    Define_Object(obj,cSubs2)
    Define_Object(obj2,cSubs2)
    obj\Set(1,66)
    obj\Set(2,99)
    obj2\Set(1,266)
    obj2\Set(2,299)
    test(obj\Get(1),=,66)
    test(obj\Get(2),=,99)
    test(obj2\Get(1),=,266)
    test(obj2\Get(2),=,299)
    test(obj\clonefrom(obj2),=,#True)
    test(obj\Get(1),=,266)
    test(obj2\Get(1),=,266)
    obj\Set(1,399)
    test(obj\Get(1),=,399)
    test(obj2\Get(1),=,266)
   
    ;ProcedureReturn 0
  _EndProcedure
  Procedure ObjInClass3()
    Define_Object(obj,cDeep5)
    Define_Object(obj2,cDeep5)
    Define i
    For i=1 To 6
      obj\Set(i,i)
      obj2\set(i,i*10)
    Next
    For i=1 To 6
      test(obj\get(i),=,i)
      test(obj2\get(i),=,i*10)
      test(obj\getfake(i),<>,obj2\getfake(i))
    Next
    test(obj\getfake2(),<>,obj2\getfake2())
    test(obj\getfake3(),<>,obj2\getfake3())
    test(obj\CloneFrom(obj2),=,#True)
    For i=1 To 6
      test(obj\get(i),=,i*10)
      test(obj2\get(i),=,i*10)
      test(obj\getfake(i),<>,obj2\getfake(i))
    Next
    test(obj\getfake2(),<>,obj2\getfake2())
    test(obj\getfake3(),<>,obj2\getfake3())
    For i=1 To 6
      obj\Set(i,i)
    Next
    For i=1 To 6
      test(obj\get(i),=,i)
      test(obj2\get(i),=,i*10)
    Next
    test(obj\CloneFrom(obj),=,#False)
    For i=1 To 6
      test(obj\get(i),=,0)
      test(obj2\get(i),=,i*10)
    Next
  _EndProcedure
  Procedure ObjInClass4()
    Define_Object(obj,cDeep5)
    Define *obj2.cDeep5
    Define i
    For i=1 To 6
      obj\Set(i,i)
    Next
    *obj2=obj\AllocateClone()
    test(*obj2,<>,#False)
    If *obj2
      For i=1 To 6
        test(obj\get(i),=,i)
        test(*obj2\get(i),=,i)
        test(obj\getfake(i),<>,*obj2\getfake(i))
      Next
      test(obj\getfake2(),<>,*obj2\getfake2())
      test(obj\getfake3(),<>,*obj2\getfake3())
      For i=1 To 6
        *obj2\Set(i,i*10)
      Next
      For i=1 To 6
        test(obj\get(i),=,i)
        test(*obj2\get(i),=,i*10)
      Next
     
      Free_Object(*obj2)
    EndIf
  _EndProcedure
 
  ObjInClass()
  ObjInClass2()
  ObjInClass3()
  test(listfake(),=,#True)
  objinclass4()
  test(listfake(),=,#True)
  ;}
 
  TestName="Reset Test";-{ Reset Test
  Procedure ResetTest()
    Protected_Object(obj1,cVar)
    obj1\Set(20)
    test(Obj1\Get(),=,20)
    obj1\Reset()
    test(obj1\Get(),=,0)
  _EndProcedure
  ResetTest()
  ;}
 
 
  Procedure timetest1()
  EndProcedure
  Procedure timetest2()
    Define  var1.cvar__class__struc
    Define int.cvar
  EndProcedure
  Procedure timetest3()
    Define_Object(var1,cvar)
  _EndProcedure
 
  Define start=ElapsedMilliseconds()
  Define count=0
 
 
 
 
  _FakeEnd
 
 
 
 
  CompilerIf #PB_Compiler_Debugger
    TestName="All objects disposed?"
    test(oop::counter__object,=,0)
    test(oop::counter__allocate__object ,=,0)
   
   
  CompilerEndIf
 
  CompilerIf #False
    PrintN(Str( Sizeof_Class(cDeep1)))
    PrintN(Str( Sizeof_Class(cDeep2)))
    PrintN(Str( Sizeof_Class(cDeep3)))
    PrintN(Str( Sizeof_Class(cDeep4)))
    PrintN(Str( Sizeof_Class(cDeep5)))
  CompilerEndIf
 
  CompilerIf #False
    PrintN("")
    count=0
    start=ElapsedMilliseconds()
    Repeat
      timetest1()
      count+1 
    Until ElapsedMilliseconds()-start>100
    PrintN("Timetest1:"+count)
   
    count=0
    start=ElapsedMilliseconds()
    Repeat
      timetest2()
      count+1 
    Until ElapsedMilliseconds()-start>100
    PrintN("Timetest2:"+count)
   
    count=0
    start=ElapsedMilliseconds()
    Repeat
      timetest3()
      count+1 
    Until ElapsedMilliseconds()-start>100
    PrintN("Timetest3:"+count)
  CompilerEndIf
 
 
 
 
  PrintN("")
  PrintN("")
  If TestResult
    ConsoleColor(10,0)
    PrintN( "Test OK!")
  Else
    ConsoleColor(12,0)
    PrintN( "Test Fail!") 
  EndIf
  Input()
  CloseConsole()
  End
CompilerEndIf
Last edited by GPI on Sun Sep 20, 2015 9:17 pm, edited 1 time in total.
User avatar
fsw
Addict
Addict
Posts: 1603
Joined: Tue Apr 29, 2003 9:18 pm
Location: North by Northwest

Re: Module oop and EnableClass

Post by fsw »

Seems to work just fine.
Thanks for sharing.

I am to provide the public with beneficial shocks.
Alfred Hitshock
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Module oop and EnableClass

Post by Fred »

That's quite some use of the macro processor :)
GPI
PureBasic Expert
PureBasic Expert
Posts: 1394
Joined: Fri Apr 25, 2003 6:41 pm

Re: Module oop and EnableClass

Post by GPI »

Thats the only way to enable class-handling without a preprocessor. I can't solve one big problem: _procedurereturn, _endprocedure and _end. I need a possibility to detect the end of a variable... If anybody had a better idea, please let me know.

btw. i updated my code a little bit. Objects in the Properties are now possible and a new default-method reset() exist.
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: Module oop and EnableClass

Post by Lunasole »

Thanks. Looks nice, will try it later in some app.
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
IndigoFuzz

Re: Module oop and EnableClass

Post by IndigoFuzz »

This is incredible work and extremely useful :) Thank you so much!
Post Reply