PDA

View Full Version : Module classes



ErosOlmi
22-08-2010, 19:52
I'm currently working on a new way of developing modules and modules features that I'm so excited that I want to share a little initial info with all of you


I will call this new way "module classes" Why the term classes? Some reasons:

because it will be possible to use dot notation for module methods
because in some way it will be the start of a new way of programming modules that will be very close to OOP but compiled
because if you have latest Power Basic compiler 905 you will be able to use PowerBasic Classes in thinBasic modules and use the same classes in thinBasic scripts wrapping the needed modules

For the moment I will not give you too much inside details but I will show you what kind of scripts you will be able to use and how easy will be to develop new modules in this new way.

So let's start from a thinBasic script example. Pay attention to the new syntax.

Uses "LL2"
'---The above module implements a CLASS named cLinkedList
'---That CLASS name will be usable to define new object variables
'---derived from that available classes

Type tData
x As Long
y As Long
w As Long
h As Long
AnArray(100) As Ext
End Type

'---Define a variable of cLinkedList CLASS
'---During DIM of a new class variable nothing will happen
'---other than internal allocation of a new variable derived from
'---a class. You have to later call NEW to create a real object
'---Out from the indicated class. See below
Dim MyLL As cLinkedList


Dim lCounter As Long
Dim t1 As Double
Dim t2 As Double
Dim MyData As tData

'---Create the object and call (if present) default constructor
'---Default constructor parsing is responsibility of module
'---programmer so you can define whatever syntax for it
'---In the below case syntax is:
' constructor[(ByVal UseStrings As Long [, ByVal SortItems As Long])]
MyLL = New cLinkedList

t1 = Timer
For lCounter = 1 To 10000
MyData.x = lCounter
'---Call another method that will add some key/data pairs
'---After method name, thinBasic Core engine will pass responsibility
'---to parse syntax to module method so module programmer has all the freedom
'---to define whatever syntax for the method
'---In this case synatx is: .AddString(ByVal sKey As String, ByVal sData As String)
Myll.AddString("CODE" & lCounter, MyData)
Next
t2 = Timer

'---Call other methods
MyLL.Count

MsgBox 0, "Total time: " & Format$(t2 - t1, "#0.000")

'---When appropriated (end of script or exit from function, ...),
'---default class destructor will be internally executed
'---for every object variable
'---Having a class destructor is not mandatory



Now let's see what will be needed in module in order to tell thinBasic Core engine about new classes.
Here below some PowerBasic code extrated from a module I'm working on as example and that I will distribute as source code for learning when done:



'----------------------------------------------------------------------------
Function LoadLocalSymbols Alias "LoadLocalSymbols" (Optional ByVal sPath As String) Export As Long
' This function is automatically called by thinCore whenever this DLL is loaded.
' This function MUST be present in every external DLL you want to use with thinBasic
' Use this function to initialize every variable you need and for loading the
' new symbol (read Keyword) you have created.
'----------------------------------------------------------------------------

Local RetCode As Long
Local pClass As Long

pClass = thinBasic_Class_Add("cLinkedList", 0)

'---If class was created
If pClass Then

RetCode = thinBasic_Class_AddMethod(pClass, "_Create" , %thinBasic_ReturnNumber , CodePtr(LList_Create ))
RetCode = thinBasic_Class_AddMethod(pClass, "_Destroy" , %thinBasic_ReturnNumber , CodePtr(LList_Free ))

RetCode = thinBasic_Class_AddMethod(pClass, "AddString" , %thinBasic_ReturnNumber , CodePtr(LList_AddString ))
RetCode = thinBasic_Class_AddMethod(pClass, "Count" , %thinBasic_ReturnNumber , CodePtr(LList_Count ))

End If
End Function


Of course thinBasic module can have the usual way of managing module functions and new module classes all at the same time. So nothing will change in usual way of handling modules, you will just have a new weapon.

Conclusion
In next few weeks I will give more info and possibly a new thinBasic beta version where you will be able to experiment the creation of new classes.
For the moment this is all I can tell you.
Just to add that the above thinBasic script example is already working here in my machine.


I will now work on the following areas:

integrating module classes into numeric and string expressions
passing objects to sub/functions as parameters
managing arrays of objects
integrate objects inside UDT

Ciao
Eros

Michael Hartlef
22-08-2010, 20:31
Interesting! Does this mean that we will be able to define classes in thinbasic too?

ErosOlmi
22-08-2010, 20:34
For the moment classes will work from a module point of view.
When I will publish examples it will be more clear.

What I can say now is that I'm building all the "inside" structures in order to consider the possibility to have classes also created directly in source code but if and when this will be reality I cannot say.

Petr Schreiber
22-08-2010, 20:38
I see this as big step forward,

can't wait to use it in modules :occasion:


Petr

kryton9
23-08-2010, 00:38
Very exciting!

ErosOlmi
23-08-2010, 15:45
Developed:

string and numeric expressions involving module classes methods
declaring and using classes inside functions/subs


It seems to start to see the light ;)
I'm quite optimistic on this new set of features.

ErosOlmi
31-08-2010, 19:20
I'm going on with this new idea.

In order to test possibilities, I've added a Timer class in thinBasic Core engine and the syntax will be simple like:


DIM MyTimer AS cTimer '---Create a new object instantiated by cTimer class
MyTimer = New cTimer '---Call default constructor

MyTimer.Start '---Start timer
MyTimer.Elapsed '---If no Stop in the middle, it will give intermediate timing
MyTimer.ElapsedToString("#0.000") '---Same as Elapsed but with possibility to format
MyTimer.Stop '---Stop the timer. From this time, Elapsed will return time between start and stop events



Arrays of objects are already working

I'm working now on:

REDIM arrays of objects on the fly calling default constructor/destructor
passing objects to functions as BYREF parameters
objects as UDT elements

Ciao
Eros

Michael Hartlef
31-08-2010, 19:44
Cool, with thinAir support the user with auto completition?

ErosOlmi
31-08-2010, 19:46
That is a dream that sooner or later will become reality.
At the moment is a bit later than sooner, sorry

Petr Schreiber
01-09-2010, 09:07
It's looking great Eros!


Thanks,
Petr

ErosOlmi
01-09-2010, 10:34
If you think some statement of Core can be transformed into compiled class to be used in next beta version, I can have a look while testing this new feature.

Ciao
Eros

largo_winch
01-12-2011, 17:39
hello eros. one question to your first post to new module classes. the example with "ll2" (cLinkedList) module does working with


Dim MyLL As cLinkedList '?



or the development isn't perfect for that classes module? "method" and "class" are underlayed with blue syntax, so I can imagine this commands are still included in last thinbasic issue. I've tested this example and got an error (code 30) "Variable not defined or misspelled Keyword". that's correct?

it's possible to know more about your compiling on powerbasic side? would be very nice to see more.

bye, largo

Charles Pegge
01-12-2011, 18:48
Hi Eros,

I think we can get a near perfect match for modules written in Oxygen. I presume the value returned by the _create procedure is the address of the new object.

It would be great to see the full source code of your test module showing how you do it in PB.

Charles

PS: one specific question: do you pass the object pointer automatically when calling the module class procedures or must this be retrieved with thinBasic_ParseLong

ErosOlmi
01-12-2011, 23:23
I will publish as soon as I can a module example that implements a class but first I need to release new thinBasic version 1.9 (that is under development now)

@Charles:
yes it is a pointer to the new class.
No, it is not necessary to parse the pointer but thinBasic will pass the pointer to all compiled method wrapper
Please a little more patience and I will publish all.

Charles Pegge
02-12-2011, 00:11
Thanks Eros,

I wanted to find out whether any further bells and whistles were required from the Oxygen side to complete the OOP module interface.

And as far as I can tell, no further constructs are required, and we are in sync :)

Your scheme will also work quite well with non OOP modular code.

Charles


Here is a tentative outline for an Oxygen OOP based module.





uses "oxygen"


dim as string src


src="


#file "thinBasic_LList.dll"






'SUBSET OF THINCORE


%thinBasic_ReturnNone = 0 'Used in thinBasic_LoadSymbol to define a sub
%thinBasic_ReturnNumber = 20 'Used in thinBasic_LoadSymbol to define a function returning a EXT number
%thinBasic_ReturnString = 30 'Used in thinBasic_LoadSymbol to define a function returning a string
%thinBasic_ReturnCodeByte = 1
%thinBasic_ReturnCodeInteger = 2
%thinBasic_ReturnCodeWord = 3
%thinBasic_ReturnCodeDWord = 4
%thinBasic_ReturnCodeLong = 5
%thinBasic_ReturnCodeQuad = 6
%thinBasic_ReturnCodeSingle = 7
%thinBasic_ReturnCodeDouble = 8
%thinBasic_ReturnCodeCurrency = 9
%thinBasic_ReturnCodeExt = 10
% thinBasic_ForceOverWrite = 1 'Used in thinBasic_LoadSymbol to force symbol over writing


library "thincore.dll"


DECLARE FUNCTION thinBasic_LoadSymbol _
( _
BYVAL SymbolName AS STRING, _
BYVAL ReturnCode AS LONG, _
BYVAL FunctionOrSubPointer AS DWORD, _
OPTIONAL BYVAL ForceOverWrite AS LONG _
) AS LONG




DECLARE SUB thinBasic_ParseNumber (Result AS EXT)
Declare SUB thinBasic_ParseLong (Result As Long)
Declare Function thinBasic_ParseString (ByRef sResult As String) As Ext
DECLARE FUNCTION thinBasic_CheckOpenParens_Optional () AS LONG
DECLARE FUNCTION thinBasic_CheckCloseParens_Mandatory () AS LONG
DECLARE FUNCTION thinBasic_CheckComma_Optional () AS LONG






declare sub thinBasic_Class_Add (string cn,long m)
declare sub thinBasic_Class_AddMethod (long pt,string na,long rt, ad)


library ""


extern


'==========
Class LList
'==========


string s
long count


method _create() as sys
'======================
'
'CREATE PERSISTENT OBJECT
'
LList*p : @p=getmemory sizeof(p)
'
'INITIAL VALUES
'
p.s="ok"
p.count=0
return @p
end method




method _Free()
'=============
s=""
freememory @this
end method




method addstring()
'=========================
count++
end method




method ListCount() as long
'=========================
return count
end method




end class




'----------------------------------------------------------------------------
Function LoadLocalSymbols Alias "LoadLocalSymbols" (Optional ByVal sPath As String) As Long, export
' This function is automatically called by thinCore whenever this DLL is loaded.
' This function MUST be present in every external DLL you want to use with thinBasic
' Use this function to initialize every variable you need and for loading the
' new symbol (read Keyword) you have created.
'----------------------------------------------------------------------------

local RetCode As Long
local pClass As Long

pClass = thinBasic_Class_Add("cLinkedList", 0)

'---If class was created
If pClass Then
RetCode = thinBasic_Class_AddMethod(pClass, "_Create" , %thinBasic_ReturnNumber , @LList._Create )
RetCode = thinBasic_Class_AddMethod(pClass, "_Destroy" , %thinBasic_ReturnNumber ,@LList._Free )

RetCode = thinBasic_Class_AddMethod(pClass, "AddString" , %thinBasic_ReturnNumber , @LList.AddString)
RetCode = thinBasic_Class_AddMethod(pClass, "Count" , %thinBasic_ReturnNumber , @LList.Count)

End If


End Function


end extern


"


o2_asmo src
if len(o2_error) then
msgbox 0,o2_error
stop
end if


o2_exec

ErosOlmi
02-12-2011, 01:32
Yes, something like that.
In PowerBasic than your class methods must be wrapped with standard functions to which thinCore engine will pass your class pointer.
More or less like that:


'--------------------------------------------------------------------------------------
FUNCTION LList_AddString( _
BYVAL pList AS LONG _
) AS EXT
'--------------------------------------------------------------------------------------


LOCAL sKey AS STRING
LOCAL sData AS STRING
LOCAL pp AS LONG


'MsgBox FuncName$ & Str$(pList)
pp = thinBasic_CheckOpenParens_Optional
thinBasic_ParseString sKey
IF thinBasic_CheckComma_Mandatory THEN


thinBasic_ParseString sData


IF thinBasic_ErrorFree THEN
IF pList THEN
'---Use the magic REDIM ... AT and the trick is done
REDIM iList(1& TO 1&) AS cIList AT pList


FUNCTION = iList(1&).AddString(sKey, sData)
END IF
END IF


END IF
IF pp THEN thinBasic_CheckCloseParens_Mandatory




END FUNCTION


'--------------------------------------------------------------------------------------
FUNCTION LList_Free( _
BYVAL pList AS LONG _
) AS EXT
'--------------------------------------------------------------------------------------
' If thinBasic_CheckOpenParens_Optional Then thinBasic_CheckCloseParens_Mandatory


IF pList THEN
'---Use the magic REDIM ... AT and the trick is done
REDIM iList(1& TO 1&) AS cIList AT pList


iList(1&).Free


END IF


END FUNCTION


'--------------------------------------------------------------------------------------
FUNCTION LList_Count( _
BYVAL pList AS LONG _
) AS EXT
'--------------------------------------------------------------------------------------
IF thinBasic_CheckOpenParens_Optional THEN thinBasic_CheckCloseParens_Mandatory


IF pList THEN
'---Use the magic REDIM ... AT and the trick is done
REDIM iList(1& TO 1&) AS cIList AT pList


FUNCTION = iList(1&).Count


END IF


END FUNCTION





You can use class pointer to point to your class and than call relevant methods

Hope it is clear enough
In any case please wait till thinBasic 1.9 will be out because it will fix some error in class handling

Eros

Charles Pegge
02-12-2011, 04:19
Thanks Eros,

How does your LList_Create work? Is it a constructor method that receives a null object pointer, or is it a conventional function which takes the role of class-factory like CoCreateInstance...

My code above, assumes it is a constructor method with a null object pointer, but it could easily be placed outside the class and turned into a class factory function.

(Sorry about the awful OOP jargon)


Charles


function LList_create() as sys
'
'CREATE PERSISTENT OBJECT
'
LList*p : @p=getmemory sizeof(p)
'
'INITIAL VALUES
'
p.s="ok"
p.count=0
return @p
end function

ErosOlmi
02-12-2011, 08:14
Here it is

All wrapper functions have a LONG parameter that is the pointer to the compiled class
This LONG param (pList in this case) is the memory area allocated by thinCore to store a pointer to the instantiated class when you defined something like


Dim MyLL As cLinkedList

Of course at DIM time, no class is created but just a variable whose type is Module CLASS. So that pointer will point to null
Consider a module class variable like a DWORD with a structure associated with it. Every time it is encountered during script execution Core engine scan methods and if found it will call wrapped method passing a pointer to the DWORD

When thinCore calls the constructor, it is responsibility tof the programmer to instantiate something, in this case a new module (internal) class named "cLList"


'--------------------------------------------------------------------------------------
FUNCTION LList_Create( _
BYVAL pList AS LONG _
) AS EXT
'--------------------------------------------------------------------------------------
LOCAL nUseString AS EXT
LOCAL nSortList AS EXT


IF thinBasic_CheckOpenParens_Optional THEN
thinBasic_ParseNumber nUseString
IF thinBasic_CheckComma_Optional THEN
thinBasic_ParseNumber nSortList
END IF


thinBasic_CheckCloseParens_Mandatory
END IF


'---In any case I will create the list
IF thinBasic_ErrorFree THEN
IF pList THEN
'---Use the magic REDIM ... AT and the trick is done
REDIM iList(1& TO 1&) AS cIList AT pList


iList(1&) = CLASS "cLList"
iList(1&).Default(nUseString, nSortList)


END IF
END IF


END FUNCTION



Constructor is the wrapped function executed when thinCore encounters a class instantiation line like:


'---Create the object and call default constructor
'---Default constructor parsing is responsibility of module
'---programmer so you can define whatever syntax for it
'---In the below case syntax is:
' constructor[(ByVal UseStrings As Long [, ByVal SortItems As Long])]
MyLL = New cLinkedList(%FALSE, %FALSE)

ErosOlmi
02-12-2011, 12:10
PS: sorry to all if I'm so "light" in replying but I'm currently in a working vortex in my company and I have very little time.
Next week should be better.

Ciao
Eros

Charles Pegge
02-12-2011, 12:15
I look forward to the new possibilities Eros, thanks, and don't work too hard!