Page 2 of 2
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 12:57 pm
by Mijikai
mk-soft wrote:
P.S.
The call you wish for would have to be implemented by compiler.
r1 = {IsObject *VT-stack1 = }\getA\{IsObject *VT-stack2 = }\getB\{IsObject *VT-stack3 = }\getC() {*VT-stack3\Release()} {*VT-stack2\Release()} {*VT-stack1\Release()}
Its not a wish what i showed works.
Unless this is not aimed at me but the original request.
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 12:58 pm
by mk-soft
You can provide functions in a structure. However, this has nothing to do with interfaces.
For this you have to define the function with ProtoType.
However, it is a problem to pass the pointer to your own data.
But there's one trick I've got to figure out...
Link:
https://www.purebasic.fr/german/viewtop ... =8&t=30347
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 1:01 pm
by Mijikai
mk-soft wrote:You can provide functions in a structure. However, this has nothing to do with interfaces.
For this you have to define the function with ProtoType.
However, it is a problem to pass the pointer to your own data.
But there's one trick I've got to figure out...
Well this works just fine for me...
Code: Select all
Structure PUBLIC_VTABLE_STRUCT
;...
*Object.iObject;<- Interface !!!
EndStructure
And you always get the pointer to it, access it and or call any function...
Code: Select all
Procedure.i Something(*VT.PUBLIC_VTABLE_STRUCT);<- function of the public interface
;...
EndProcedure
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 5:05 pm
by Mistrel
I looked at the suggestions provided by both mk-soft and Mijikai. The problem still comes down to functions being unable to return anything other than primitives.
Consider how I want to chain methods:
The problem lies squarely with the return value for getBox(). Because its return value cannot be defined as an interface or as a pointer to a specific structure, then the compiler cannot complete the chain.
Can't do any of these:
Code: Select all
Declare.SomeStruct getBox()
Declare.SomeStruct* getBox()
Declare.SomeInterface getBox()
Only this for pointer results:
Therefore the chain cannot be completed:
Code: Select all
getBox()\getWidth() <- how can it call getWidth()?
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 6:16 pm
by #NULL
I guess return values are simply not lvalues
Code: Select all
Procedure.s f(s.s)
ProcedureReturn s
EndProcedure
Debug PeekS(@f("abc")) ; doesn't peek into a string temporary because it's just the same
Debug PeekS(@f()) ; as the function pointer
; output:
; ㅈ僀䡐䠨襈⑄䠨䒋䀤襈뀅☒䠀璋⠤赈⑼䠨뇕荈Ⴤ襈䣦쟇
; ㅈ僀䡐䠨襈⑄䠨䒋䀤襈뀅☒䠀璋⠤赈⑼䠨뇕荈Ⴤ襈䣦쟇
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 6:23 pm
by Mijikai
Mistrel wrote:I looked at the suggestions provided by both mk-soft and Mijikai. The problem still comes down to functions being unable to return anything other than primitives.
Consider how I want to chain methods:
The problem lies squarely with the return value for getBox(). Because its return value cannot be defined as an interface or as a pointer to a specific structure, then the compiler cannot complete the chain.
Can't do any of these:
Code: Select all
Declare.SomeStruct getBox()
Declare.SomeStruct* getBox()
Declare.SomeInterface getBox()
Only this for pointer results:
Therefore the chain cannot be completed:
Code: Select all
getBox()\getWidth() <- how can it call getWidth()?
You can assign any return value to the vtable - structure and use it directly or
through any of the interface functions.
Code: Select all
Interface box
GetWidth.i()
EndInterface
Interface obj
GetBox.i()
GetBoxWidth.i()
EndInterface
Structure OBJ_VTABLE
;...
*Box.box;< - interface!!!
EndStructure
Structure OBJ_STRUCT
StructureUnion
*Interface.obj
*VT.OBJ_VTABLE
EndStructure
EndStructure
Global Object.OBJ_STRUCT
Procedure.i CreateObject()
;will create and return the object interface (with custom vtable)
EndProcedure
Procedure.i GetBoxInterface()
;will create/get a box interface!
EndProcedure
Procedure.i GetBox(*VT.OBJ_VTABLE);function of the object interface
*VT\Box = GetBoxInterface();<- get the box interface and assign it to the vtable
EndProcedure
Procedure.i GetBoxWidth(*VT.OBJ_VTABLE);function of the obj interface
ProcedureReturn *VT\Box\GetWidth()
EndProcedure
Object\Interface = CreateObject();<- create the object interface
Object\Interface\GetBox();<- get the box interface
Object\VT\Box\GetWidth();<- call GetWidth() directly through the vtable
Object\Interface\GetBoxWidth();<- call GetWidth() through a object interface function
I mean you could even just do this:
Code: Select all
;...
Private *Box.box
*Box = Object\Interface\GetBox():*Box\GetWidth()
;...
If no access through the obj interface is required.
Re: How to call methods from the result of another interface
Posted: Mon Jul 16, 2018 2:54 am
by Mistrel
Mijikai, I think you misunderstand. SomeObject is returning a BoxObject which has its own interface. In this example it only has one box. What if it's a collection of boxes?
Here is a more complete example if the current limitations and where the call chain gets stuck:
Code: Select all
;/ -- [[ BoxObject ]]- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
DeclareModule BoxObject
Interface Public
getWidth()
getHeight()
EndInterface
Structure VTable
*getWidth
*getHeight
EndStructure
Structure Class
*vTable
width.i
height.i
EndStructure
;/ Static
Declare setVTable(*vTable.Class)
Declare new()
EndDeclareModule
Module BoxObject
;/ Static
Global vTable.VTable
setVTable(@vTable)
Procedure new()
Protected *instance.Class
*instance=AllocateStructure(Class)
*instance\vTable=@vTable
*instance\width=123
*instance\height=456
ProcedureReturn *instance
EndProcedure
Procedure getWidth(*this.Class)
ProcedureReturn *this\width
EndProcedure
Procedure getHeight(*this.Class)
ProcedureReturn *this\height
EndProcedure
Procedure setVTable(*vTable.VTable)
*vTable\getWidth=@getWidth()
*vTable\getHeight=@getHeight()
EndProcedure
EndModule
Interface BoxObject Extends BoxObject::Public
EndInterface
;/ -- [[ SomeObject ]] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
DeclareModule SomeObject
Interface Public
getBox()
EndInterface
Structure VTable
*getBox.getBox
EndStructure
Structure Class
*vTable
*box.BoxObject
EndStructure
;/ Static
Declare setVTable(*vTable.Class)
Declare new()
EndDeclareModule
Module SomeObject
;/ Static
Global vTable.VTable
setVTable(@vTable)
Procedure new()
Protected *instance.Class
*instance=AllocateStructure(Class)
*instance\vTable=@vTable
;/ SomeObject has a BoxObject
*instance\box=BoxObject::new()
ProcedureReturn *instance
EndProcedure
Procedure getBox(*this.Class)
ProcedureReturn *this\box
EndProcedure
Procedure setVTable(*vTable.VTable)
*vTable\getBox=@getBox()
EndProcedure
EndModule
;/ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
Interface SomeObject Extends SomeObject::Public
EndInterface
box.BoxObject=BoxObject::new()
;/ BoxObject has default values
Debug box\getHeight()
Debug box\getWidth()
obj.SomeObject=SomeObject::new()
;/ SomeObject has a BoxObject which has dimensions
Debug obj\getBox()\ ; <- Can't do it
Re: How to call methods from the result of another interface
Posted: Mon Jul 16, 2018 3:16 am
by Mistrel
This is interesting and you would think that it might work but it does not:
Code: Select all
Interface BoxObject
EndInterface
Structure SomeObject
getBox.BoxObject
EndStructure
*obj.SomeObject=0
; [Error] Garbage at the end of the line.
Debug *obj\getBox() ; <- Can't do it
It seems like a hard limitation that we can't call functions in this way.
Re: How to call methods from the result of another interface
Posted: Mon Jul 16, 2018 7:34 am
by Mijikai
Mistrel wrote:This is interesting and you would think that it might work but it does not:
Code: Select all
Interface BoxObject
EndInterface
Structure SomeObject
getBox.BoxObject
EndStructure
*obj.SomeObject=0
; [Error] Garbage at the end of the line.
Debug *obj\getBox() ; <- Can't do it
It seems like a hard limitation that we can't call functions in this way.
Heres a working example:
Code: Select all
Interface BoxObject
GetBox.i()
EndInterface
Structure SomeObject
*getBox.BoxObject
EndStructure
Global *obj.SomeObject
Procedure.i GetBox(*VT)
Debug "Something"
EndProcedure
Procedure.i GetInterface()
Protected *Interface, *Set.Integer
*Interface = AllocateMemory(SizeOf(Integer) * 2)
If *Interface
*Set = *Interface:*Set\i = *Interface + SizeOf(Integer)
*Set + SizeOf(Integer):*Set\i = @GetBox();<- the inteface will have one function
EndIf
ProcedureReturn *Interface
EndProcedure
*obj = AllocateStructure(SomeObject);<- structure needs to be allocated
*obj\getBox = GetInterface();<- assign a interface
*obj\getBox\GetBox();<- call it
A interface always needs a vtable you cant use it without.
Re: How to call methods from the result of another interface
Posted: Mon Jul 16, 2018 5:40 pm
by mk-soft
@Mistrel
You're a little lost now.
I've now rebuilt my example the way you need it.
Unfortunately Purebasic cannot do this:
What Mijikai means, I called at the bottom of the test.
Example Update 1.6
Code: Select all
;-TOP
; Example 1.6
; ***************************************************************************************
DeclareModule Public
Interface iDefault
Addref()
Release()
EndInterface
Structure sDefault
*vTable.iDefault
Refcounter.i
EndStructure
EndDeclareModule
Module Public
EndModule
; ***************************************************************************************
DeclareModule BoxObject
Interface iBoxObject Extends Public::iDefault
GetWidth()
GetHeiht()
EndInterface
Declare New()
EndDeclareModule
Module BoxObject
Structure sBoxObject Extends Public::sDefault
dx.i
dy.i
EndStructure
Procedure Addref(*this.sBoxObject)
With *this
\Refcounter + 1
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Addref - Refcounter: " + \Refcounter
ProcedureReturn \Refcounter
EndWith
EndProcedure
Procedure Release(*this.sBoxObject)
With *this
If \Refcounter = 0
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Destroy - Refcounter: " + \Refcounter
FreeStructure(*this)
Else
\Refcounter - 1
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Release - Refcounter: " + \Refcounter
EndIf
ProcedureReturn \Refcounter
EndWith
EndProcedure
Procedure GetWidth(*this.sBoxObject)
With *this
ProcedureReturn \dx
EndWith
EndProcedure
Procedure GetHeight(*this.sBoxObject)
With *this
ProcedureReturn \dy
EndWith
EndProcedure
; -----------------------------------------------------------------
Procedure New()
Protected *this.sBoxObject
With *this
*this = AllocateStructure(sBoxObject)
If *this
\vTable = ?vtBoxObject
\Refcounter = 0
\dx = Random(400, 100)
\dy = Random(300, 10)
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " New - Refcounter: " + \Refcounter
EndIf
ProcedureReturn *this
EndWith
EndProcedure
; -----------------------------------------------------------------
DataSection
vtBoxObject:
Data.i @Addref()
Data.i @Release()
Data.i @GetWidth()
Data.i @GetHeight()
EndDataSection
EndModule
; ***************************************************************************************
DeclareModule CircleObject
Interface iCircleObject Extends Public::iDefault
GetRadius()
EndInterface
Declare New()
EndDeclareModule
Module CircleObject
Structure sCircleObject Extends Public::sDefault
r.i
EndStructure
Procedure Addref(*this.sCircleObject)
With *this
\Refcounter + 1
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Addref - Refcounter: " + \Refcounter
ProcedureReturn \Refcounter
EndWith
EndProcedure
Procedure Release(*this.sCircleObject)
With *this
If \Refcounter = 0
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Destoy - Refcounter: " + \Refcounter
FreeStructure(*this)
Else
\Refcounter - 1
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Release - Refcounter: " + \Refcounter
EndIf
ProcedureReturn \Refcounter
EndWith
EndProcedure
Procedure GetRadius(*this.sCircleObject)
With *this
ProcedureReturn \r
EndWith
EndProcedure
; -----------------------------------------------------------------
Procedure New()
Protected *this.sCircleObject
With *this
*this = AllocateStructure(sCircleObject)
If *this
\vTable = ?vtCircleObject
\Refcounter = 0
\r = Random(400, 100)
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " New - Refcounter: " + \Refcounter
EndIf
ProcedureReturn *this
EndWith
EndProcedure
; -----------------------------------------------------------------
DataSection
vtCircleObject:
Data.i @Addref()
Data.i @Release()
Data.i @GetRadius()
EndDataSection
EndModule
; ***************************************************************************************
; ***************************************************************************************
DeclareModule MyObject
Interface iMyObject Extends Public::iDefault
GetBox()
GetCircle()
EndInterface
Structure sMyObject Extends Public::sDefault
*Self.iMyObject
*Box.BoxObject::iBoxObject
*Circle.CircleObject::iCircleObject
EndStructure
Declare New()
EndDeclareModule
Module MyObject
Procedure Addref(*this.sMyObject)
With *this
\Refcounter + 1
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Addref - Refcounter: " + \Refcounter
ProcedureReturn \Refcounter
EndWith
EndProcedure
Procedure Release(*this.sMyObject)
With *this
If \Refcounter = 0
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Destoy - Refcounter: " + \Refcounter
\Box\Release()
\Circle\Release()
FreeStructure(*this)
Else
\Refcounter - 1
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " Release - Refcounter: " + \Refcounter
EndIf
ProcedureReturn \Refcounter
EndWith
EndProcedure
Procedure GetBox(*this.sMyObject)
With *this
\Box\Addref()
ProcedureReturn \Box
EndWith
EndProcedure
Procedure GetCircle(*this.sMyObject)
With *this
\Circle\Addref()
ProcedureReturn \Circle
EndWith
EndProcedure
; -----------------------------------------------------------------
Procedure New()
Protected *this.sMyObject
With *this
*this = AllocateStructure(sMyObject)
If *this
Debug "[" + Hex(*this) + "] " + #PB_Compiler_Module + " New - Refcounter: " + \Refcounter
\vTable = ?vtMyObject
\Self = *this
\Box = BoxObject::New()
\Circle = CircleObject::New()
EndIf
ProcedureReturn *this
EndWith
EndProcedure
DataSection
vtMyObject:
Data.i @Addref()
Data.i @Release()
Data.i @GetBox()
Data.i @GetCircle()
EndDataSection
EndModule
; ***************************************************************************************
;- Test
Define.MyObject::iMyObject *obj1
Define.BoxObject::iBoxObject *box1
Define.CircleObject::iCircleObject *Circle1
Debug "New MyObject..."
*obj1 = MyObject::New()
Debug "Get Box 1"
*box1 = *obj1\GetBox()
Debug "DX: " + *box1\GetWidth()
Debug "DY: " + *box1\GetHeiht()
Debug "Get Circle 1"
*Circle1 = *obj1\GetCircle()
Debug "R : " + *Circle1\GetRadius()
Debug "Release box 1"
*box1\Release()
*Circle1\Release()
Debug "Release obj 1"
*obj1\Release()
Debug "This is not possible because purebasic cannot resolve the object chain."
;r1 = *obj1\GetBox()\GetWidth()
Debug "Trick... but not good"
Define *obj2.MyObject::sMyObject
*obj2 = MyObject::New()
Debug "DX: " + *obj2\Box\GetWidth()
Debug "R : " + *obj2\Circle\GetRadius()
Debug "Release obj "
*obj2\Self\Release()
Re: How to call methods from the result of another interface
Posted: Wed Oct 16, 2019 3:23 am
by deathmx
Hmm would this style of organization help you? Maybe it's a bit much but if i were wanting to make a work around it maybe something close to this. Note: This was quick coding so i didn't add any memory freeing management.
I am trying to show some of the possible flexibility and alternative methods all in one

.
Code: Select all
DeclareModule world
Interface _
getwidth()
getheight()
EndInterface
Interface Main_Methods
ShowBoxes()
newbox(Name$,x,y,width,height)
EndInterface
Structure box
*interface
x.l
y.l
width.l
height.l
EndStructure
Structure main
*interface
Map *Box._()
EndStructure
Structure NewObject
*Functions.Main_Methods
*Vars.main
EndStructure
Declare create()
EndDeclareModule
Module world
Procedure create()
*new.main = AllocateStructure(main)
*new\interface = ?Main_Methods
*object.NewObject = AllocateStructure(NewObject)
*object\Functions = *new
*object\Vars = *new
ProcedureReturn *object
EndProcedure
Procedure NewBox(*self.main,Name$,x,y,width,height)
With *self
AddMapElement(\Box(),name$)
*this.box = AllocateStructure(box)
*this\x = x
*this\y = y
*this\width = width
*this\height = height
*this\interface = ?Box_Methods
\Box() = *this
EndWith
EndProcedure
Procedure showboxes(*self.main)
Debug "name: x,y,width,height"
ForEach *self\Box()
*this.box = *self\Box()
Debug MapKey(*self\Box()) + ":" + Str(*this\x) + "," + Str(*this\y) + "," + Str(*this\width) + "," + Str(*this\height)
Next
EndProcedure
Procedure GetWidth(*self.box)
ProcedureReturn *self\width
EndProcedure
Procedure getheight(*self.box)
ProcedureReturn *self\height
EndProcedure
DataSection
Main_Methods:
Data.i @showboxes(),@newbox()
Box_Methods:
Data.i @getwidth(),@getheight()
EndDataSection
EndModule
*Galaxy.world::NewObject = world::create()
*Galaxy\Functions\newbox("Small",0,0,10,10)
*Galaxy\Functions\newbox("Medium",0,0,100,100)
*Galaxy\Functions\newbox("Large",0,0,1000,1000)
*Galaxy\Functions\newbox("Random",Random(1000),Random(1000),Random(1000),Random(1000))
*Galaxy\Functions\ShowBoxes()
Debug "Large Width:" + Str(*Galaxy\Vars\Box("Large")\getwidth())
Debug ""
Debug "Lets get all the heights"
ForEach *Galaxy\Vars\Box()
Debug MapKey(*Galaxy\Vars\Box()) + "::" + "Height = " + Str(*Galaxy\Vars\Box()\getheight())
Next