PDA

View Full Version : ThinBASIC OOPification



ErosOlmi
13-03-2014, 17:30
Hi all,

in next thinBasic version (I'm almost ready) there will be a little more OOPification :) of standard ThinBasic TYPEs.
As you may already aware, you can define Functions inside TYPEs more or less like having methods in classes for languages supporting OOP.

The new features I've added will be:


type extension (similar to class inheritance)
You can create a TYPE that Extends another TYPE functionality
a kind of functions polymorphic when same function name is defined in derived types
Extended TYPEs will inherit base TYPE elements and functions. Base Functions can be redefined in Extended type


In case you would like to test new features:
http://www.thinbasic.biz/projects/thinbasic/thinBasic_1.9.12.0.zip

I still need to develop error checking so you might experience some GPF for those new features if you do not follow the rules but it should work.
Example in \thinBasic\SampleScripts\OOP\Example_030_Extends.tbasic


A little example count more than 1000 words:

Uses "console"

'-----------------------------------------------
'-----------------------------------------------
Type t2D
x As Long
y As Long

Init As Function
ToString As Function
End Type

Function t2D.Init(ByVal x As Long, ByVal y As Long) As Long
Me.X = x
Me.Y = y
End Function

Function t2D.ToString() As String
Function = "(" & Me.x & "," & Me.Y & ")"
End Function

'-----------------------------------------------
' t3D extends t2D type adding a new element/property
' and redefining 2 type functions
'-----------------------------------------------
Type t3D Extends t2d
Z As Long

Init As Function
ToString As Function
End Type

Function t3D.Init(ByVal x As Long, ByVal y As Long, ByVal z As Long) As Long
Me.X = x
Me.Y = y
Me.Z = z
End Function

Function t3D.ToString(Optional ByVal sSep As String) As String
If sSep = "" Then sSep = ","
Function = "(" & Me.x & sSep & Me.Y & sSep & Me.z & ")"
End Function


'-----------------------------------------------
'-----------------------------------------------

Dim p3D As t3D
Dim p2D As t2D

p3D.Init(10, 20, 30)
p2D.Init(100, 200)

PrintL "SizeOf p2D =", SizeOf(p2D)
PrintL "p2D ToString =", p2D.ToString
PrintL
PrintL "SizeOf p3D =", SizeOf(p3D)
PrintL "p3D ToString =", p3D.ToString("-")

PrintL "----------------------------"
PrintL "All done, press a key to end"
WaitKey

ReneMiner
13-03-2014, 18:16
that sounds like some good news :)

Petr Schreiber
13-03-2014, 20:39
This is good news! :D

The OOPification is great, code units I design at work are all encapsulated in "super types".
I like the ME., it is shorter than THIS. and much more... personal :D


Petr

ReneMiner
14-03-2014, 08:44
...I like the ME., it is shorter than THIS...

Just to make sure,
ME <> THIS !
ME indicates an element of some TYPE inside a type-function, THIS indicates a member of a CLASS inside a class-method. Just so sorry the other languages don't have to care about that difference since none of them has functional types as tB has them :D

@Eros,

for the "init" - which is a certainly often used function to any type - (guess I suggested something similar already long time ago...) - how about some implemented default-Init-Function for all Type's?

Somewhat alike this:



Type t_2D
X as Long
Y as Long
End Type
' there's no "Init as Function"
' simple variables as Long in Type...

' the built-in Init-function to the Type would work somewhat alike this:
Function t_2D.Init(Optional Byval X as Long, Optional Byval Y as Long) As DWord
' assume there's something alike "Local Me As t_2D At VarPtr(FunctionCalledFrom)"
Me.X = X
Me.Y = Y
Function = Varptr(Me) ' could return Me-VarPointer for further usage..., <>0 means success...

End Function

' I (user) just would call it then
Dim myPoint1 as t_2D
myPoint1.Init(12,34) ' so X will be 12, Y 34 then
'or
Dim myPoint2 as t_2D
myPoint2.Init() ' here X and Y are 0...



so pretty much the function takes all subsets (like X as Long, Y as Long...) of the type-declaration as Optional function-parameters.

Now extend this to types with other types embedded




Type t_2D
' the embedded type
X as Long
Y as Long
End Type

Type t_Maintype
A As Byte
B As Byte
Pos as t_2D ' now this is no "simple variable"...
C As Byte
End Type
' neither Init here, because built-in...

Dim Example(123) as t_Maintype

' I could call it like this:
Local myOverlay As t_Maintype At Example(42).Init(1,2, MKL$(45, 67), 3 )



how would the "built-in Init-function to all types" take my parameters here? ;)

Perhaps change from "Init" to "Set" or "Be" ?

ErosOlmi
14-03-2014, 13:59
Rene,

I was so happy to see you posting again ... :p ... but after this post ... not so happy :D
I will think about it.
I already have some nice additional implementations.

Ciao
Eros

ReneMiner
14-03-2014, 14:07
-oh I was only absent because I was hooked to some excessive "game-testing" for a while (as excessive as I use to code at other times) since I have no real idea what useful script to write next...
Did the "Like"-expression-developement get any further in the meantime so it will allow UDTs soon?

ReneMiner
14-03-2014, 18:53
and... - forget about the init/set/be- we still can use


With Example(42)
...

:D

And to make sure I've understood:
I need to re-write the functions and re-introduce them for the extended type (t3d) only if I don't want it to use the same function as the base-type (t2D) but to be "user-defined"?

ErosOlmi
14-03-2014, 19:55
Yes

Extended TYPE will get all the items (properties) and functions (methods) of the base TYPE
If you create in the extended TYPE a function with the same name of the base Type, in that case the new function will win.

Charles Pegge
14-03-2014, 22:45
Hi Eros,

Really nice implementation. You don't even need to use the 'class' word!

My thoughts on inheritance in general:

Inheritance turns out to be less useful as a major concept of OOP than was originally conceived. Petr mentioned the term 'Supertypes' which I take to mean a collection of object types which can be totally different but have the same interfaces, same function names. For example you could have diverse objects like text, sounds, textures, backgrounds, 3d objects which could all have create() set(), get() render() and delete() methods in common but may be structurally unrelated on the inside.

Petr Schreiber
15-03-2014, 08:48
Hi Charles!,

I actually use the term supertypes for any type with functions currently. Your idea of interfaces is good one, and could be pushed further syntactically :p (Like TYPE GameObject Implements IRenderable, ITransformable )

Hi Rene!,

great to see you around again!


Just to make sure,
ME <> THIS !
ME indicates an element of some TYPE inside a type-function, THIS indicates a member of a CLASS inside a class-method.


Traditionally, BASIC languages use ME for the same thing as THIS, just have a look at VB.NET. I don't differentiate between supertype and class, they are both tools for achieving object oriented design.


Petr

ReneMiner
15-03-2014, 08:55
vb uses Me for a form - so inside a vb-code-module "Me" refers to the "current window-code"-class. At least it was that way til vb 6.0 - what they do now? I don't know...

Charles Pegge
15-03-2014, 11:43
Compatibility with OxygenBasic Objects

Oxygen can read and write thinBasic Object members, using Oxygen methods

this. prefixes (optional) instead of me.
bstring should be used for compatibility with thinBasic string

This tests member alignment


uses "oxygen"

type vector3f
x as single
y as single
z as single
end type

type color4f
r as single
g as single
b as single
a as single
end type

type ObjectClass
pos as vector3f
ang as vector3f
col as color4f
init as function
act as function
end type

function ObjectClass.init(v as single) as long
me.ang.y=v
end function

function ObjectClass.act() as long
msgbox 0,"Q.ang.y: " & me.ang.y
end function

dim Q(10) as ObjectClass
Q(2).init(1.5)
Q(2).act '1.5
dim as long pt
pt=varptr(Q(1))

dim as string src

src="
type vector3f
single x,y,z
end type
type color4f
single r,g,b,a
end type
class ObjectClass
pos as vector3f
ang as vector3f
col as color4f
method init(single v)
ang.y=v
end method
method act()
print "Q.Ang.y: " ang.y '1.5
end method
method mulangy(single f)
ang.y*=f
end method
end class
'
ObjectClass Q at *#pt
Q(2).act
Q(2).mulangy 10
"

o2_basic src
if o2_errno then
msgbox 0,o2_error
stop
else
o2_exec
end if

Q(2).act '15


PS: I'm using thinBasic in Ubuntu 12 :)

RobbeK
15-03-2014, 13:47
That's great, Charles & Eros.
Works well here :

(In some languages inside Object EndObject With Endwith -- you don't need the "dotting" , but that's only a "habit" imo)
I like the idea of inheritance .. tried something and that copying and pasting is somewhat boring + (as Charles mentions) it are the methods determening the system-logic.


thank you Rob

ReneMiner
15-03-2014, 17:09
playing around for some sniff of "privacy" - very basic, incomplete, just a direction...


#MINVERSION 1.9.12.0.

Uses "console"

Alias DWord As Heap

' virtual object at heap...

Type t_virtual_object
hPtr As Heap

Create As Function
Destroy As Function

End Type

Function t_virtual_object.Create() As Heap

' allocate default-space for any child-type
Me.hPtr = HEAP_Alloc(SizeOf(Me))
' Memory_Set( Me.hPtr, VarPtr(Me), SizeOf(Me) ) ...not yet... need to store type of Me somehow...

Return Me.hPtr

End Function

Function t_virtual_object.Destroy() As Heap

If HEAP_Size(Me.hPtr) Then HEAP_Free(Me.hPtr)
Me.hPtr = 0
Return 0

End Function
' - - - - - - - - - - - - - - - - - - - - - - - - - -

Type t_hString Extends t_virtual_object
Create As Function
SetText As Function
GetText As Function
StrLen As Function
End Type

Function t_hString.Create(Optional ByVal s As String ) As Heap

If s <> "" Then Me.hPtr = HEAP_AllocByStr(s)
Return Me.hPtr
End Function

Function t_hString.SetText(ByVal s As String) As Heap

If HEAP_Size(Me.hPtr) Then
HEAP_Free(Me.hPtr)
Me.hPtr = 0
EndIf

If s <> "" Then Me.hPtr = HEAP_AllocByStr(s)
Return Me.hPtr

End Function

Function t_hString.StrLen() As Long

Return HEAP_Size(Me.hPtr)

End Function

Function t_hString.GetText() As String
Return HEAP_Get(Me.hPtr)

End Function

Dim foo As t_hString
If foo.Create("this is very important") Then

PrintL foo.GetText()
PrintL "Length is " + foo.StrLen()
PrintL

foo.SetText("this is more funny")
PrintL foo.GetText()
PrintL "Length is " + foo.StrLen()
PrintL

foo.Destroy()
PrintL "- check:"
PrintL "Length is " + foo.StrLen()
PrintL
Else
PrintL "should not happen"
EndIf


PrintL "----------------------------"
PrintL "All done, press a key to end"
WaitKey



btw. I think it should be mentioned in the help file, section "thinBasic language\Data types and variables\Type" that functions can be part of a type too now.
And maybe some remark in "thinBasic Modules\Core (thinBasic Core Engine)\UDT Functions" that these are not about user-defined functions of UDTs - or maybe add a clue/branch here.

ReneMiner
17-03-2014, 14:44
just for the idea: the "inheritance" has more ways of usage than just "oop".

Imagine some GUI, controls as buttons, textboxes and more which now all can have a type of the actually needed size for that control. Previously there was only the Union-way - which is an enormous waste of memory if you consider a timer-control needs the same memory as some listview
Now one can have base-controls requiring a minimum of memory and extend any of them with the needed control-specific properties and proceed them altogether in the base-types functions - that's really cool :cool:

RobbeK
17-03-2014, 20:59
Ah, thanks ReneMiner ..

Can you explain about the union way ? (you mean they all have their private memory allocation ?).
I'm a little bit familiar with FOOP (Lisp) -- you can copy objects and change the "bits" needed , but those not changed are linked by reference to the original. (not sure about the mechanism behind subclasses ... it's somewhat complicated (for me))

best Rob

ReneMiner
18-03-2014, 07:44
ok, imagine to have a type that shall serve to hold the data for all controls, might be dimensioned in an array. Somewhat like



Type '...nay


too cumbersome, just check out the attached unit file which is kind of small, incomplete TBGL-GUI-engine limited to one monospaced font
To test-run try one of the templates then - has to be saved into the same folder. I did not finish because around that time Types in tB became functional so I wanted to redo it from scratch anyway and now having the posibillity to have different sized "childs" due to Extends there are totally new ways possible to handle this

The things I mean you can see at TYPE t_CTRL_OWT which contains the "base-type" and check in codebrowser for a note "UNION" - very lowest -
all controls finally have the same size but their individual data gets interpreted different.
The point is, I had to use the same memory for any control and not to waste any space I had to use free/unused properties like .Checked sometimes in a control-specific different exceptional way, so xyz.Checked not always meant "xyz.Checked"... Now using Extends makes it possible each control to have exactly the data it needs = Much more overview & clean, readeable script-structure

RobbeK
18-03-2014, 21:52
Thanks Reneminer, I'll study it to catch up with all this !

(vielen Dank) Rob

ReneMiner
03-04-2014, 14:21
Using the new possibilities extensively I've experienced that there are often somewhere stored Indexes of array-elements are not accessable from within the type-function - so it's not possible to just retrieve some index of the current into some pattern/condition fitting element from a type-function and to compare this Index later within another function of that type.

Anyway a variable could have some property which tells who in the world current Me exactly is. Now if there's no additional waste of memory for such identifier wanted or needed for each element - there is a simple way if the type we talk about is used for one array-variable only:




Type t_Type
Static current As DWord ' Static is same memory to all elements of that type
someFunctionCheck As Function
otherFunctionDo As Function
End Type

Function t_Type.someFunctionCheck( something As Any )
If something And Me Then

Me.current = VarPtr(Me)
EndIf

End Function

Function t_Type.otherFunctionDo()

If Me.current = VarPtr(Me) Then
' Me gets a pretty pink hairbow...
Else
' Me gets same old grey hat as all the others
EndIf

End Function

Dim foo(123) As t_Type

'...maybe:
Long i

foo(1).Current = 0 ' delete old information
While i < UBound(foo)
i += 1
foo(i).someFunctionCheck(whatever)
If foo(1).Current Then Exit While ' found out the current matching one, so exit
Wend

'...to find out current foo,
'...different ways thinkable

For i = 1 to Ubound(foo)

If Varptr(foo(i)) = foo(1).Current Then ' could call a type-function instead
' we got a match...
Else
' no match
EndIf

Next
'...


of course one can store the "current elements pointer" to some globals as well if the type is used for more than one array.
So omit the static type member then and


Dim current_foo as DWord
Dim current_moo ...


If use this way on dynamic used arrays make sure to do the checking after redim and before calling the function that uses the information about "current element" since varptrs could have changed.
Anyway can make some local overlay to access current element instantly like


Sub SomeSub()
Local x as t_myType at current_foo
With X
'...
End With
End Sub