Page 1 of 2
How to call methods from the result of another interface?
Posted: Sat Jul 14, 2018 6:39 am
by Mistrel
I'm just not starting to move to object-oriented programming in PureBasic to make my code more consistent and portable between the languages I use. I've spent a lot of time getting familiar with how to make things work but this one is stumping me.
If I have an interface method which returns an instance of another object, how do I declare things such that I can call them in sequence?
For example:
Code: Select all
DeclareModule SomeObject
Interface BoxObject
getWidth()
getHeight()
EndInterface
Interface Public
;/ [Error] A structure can't be used with ProcedureReturn.
;getBox.BoxObject()
getBox()
EndInterface
Declare new()
EndDeclareModule
Module SomeObject
Procedure new()
EndProcedure
EndModule
Interface SomeObject Extends SomeObject::Public
EndInterface
obj.SomeObject=SomeObject::new()
;/ [Error] Garbage at the end of the line.
Debug obj\getBox()\getWidth()
I'm returning a reference to an interface. Assigning a reference to a variable declared as an interface works but not for methods within an interface?
Why can't I do this?
Code: Select all
;/ Allowed
obj.SomeObject=*instance
;/ Not allowed?
Procedure.SomeObject ProcA()
ProcedureReturn *instance
EndProcedure
Re: How to call methods from the result of another interface
Posted: Sat Jul 14, 2018 9:37 am
by NicTheQuick
This ist not possible but it exists a feature request to make it possible.
Re: How to call methods from the result of another interface
Posted: Sat Jul 14, 2018 9:57 am
by Mistrel
If this cannot be done then interfaces in PureBasic is toothless.
I was really looking forward to porting some object-oriented code but now I'll have to rewrite a large portion of it.
Re: How to call methods from the result of another interface
Posted: Sat Jul 14, 2018 10:24 am
by mk-soft
Purebasic supports the OOP calling convention.
Not the automatic splitting of calling OOP chains.
In your example, the'GetBoxObject' is missing
The correct sequence is therefore
obj.InterfaceSomeObject = NewSomeObject()
obj2.InterfaceBoxObject =obj\GetBoxObject()
r1 = obj2\GetWidth()
r2 = obj2\GetHeight()
obj2\Release()
obj\Release()
My OOP-BaseClass modules are examples of this.
Re: How to call methods from the result of another interface
Posted: Sat Jul 14, 2018 11:25 am
by Mijikai
How about:
Code: Select all
Structure INTERFACE_STRUCT
StructureUnion
*Interface.iPublic
*VT.PUBLIC_VTABLE_STRUCT;the vtable gets modified to contain iObject -> *Object.iObject!
EndStructureUnion
EndStructure
That allows you to assing or return a interface:
Code: Select all
Global Public.INTERFACE_STRUCT
;...
Public\Interface = InterfacePublic();make a iPublic interface with custom vtable
Public\VT\Object = *Object;pointer to any iObject interface
Then use the VTable to call it:
Re: How to call methods from the result of another interface
Posted: Sat Jul 14, 2018 12:23 pm
by Mistrel
I don't think a structure union would work if the public interface does not align with the vtable.
Re: How to call methods from the result of another interface
Posted: Sat Jul 14, 2018 12:32 pm
by Mijikai
Mistrel wrote:I don't think a structure union would work if the public interface does not align with the vtable.
The structure will expand to the size of the modified (extended) vtable.
This is also possible:
Code: Select all
Interface iPublic
Something.i()
EndInterface
;...
Procedure.i Something(*VT.PUBLIC_VTABLE_STRUCT)
ProcedureReturn *VT\Object\Message()
EndProcedure
A interface function (Something()) of the public interface accesses the supplied
Object interface through the expanded vtable.
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 4:58 am
by Mistrel
I've looked at this more closely. Wouldn't it result in an additional VT field for every object in the call chain?
Compared to:
There's also no way to pass arguments in the call chain except to the last method.
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 6:35 am
by Mijikai
Mistrel wrote:I've looked at this more closely. Wouldn't it result in an additional VT field for every object in the call chain?
Compared to:
There's also no way to pass arguments in the call chain except to the last method.
I dont see why writing out the calls would be a problem.
Wont it get also messy if you write several calls in one line?
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 7:53 am
by Mistrel
Say I have a world object of players and want to teleport one to 0,0,0.
Code: Select all
world\getPlayer("Bugsy22")\teleport(0,0,0)
I can't chain these as per your workaround because:
Code: Select all
world\getPlayer("Bugsy22")\ <- this is an interface and I can't access additional members
It has the same problem as my original post. Using the interface/vtable union is only a partial workaround and brings with it a different problem:
Code: Select all
world\getPlayer\ <- this is pointer to a structure and I can't pass arguments
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 9:30 am
by Mijikai
I dont rly see the problem...
Code: Select all
Public\Interface\GetPlayer("Bugs");<- will get the interface and pass it to the vtable
Public\VT\Teleport(0,0,0);<- will call the function of the passed interface
Make the structure available in the passed vtable and you can use
a function to mess with it or just use it directly.
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 11:32 am
by mk-soft
You have forgotten something essential with the handling of interfaces and objects.
Calling a function in a subobject is not enough.
Wrote about an example of what the process must be like.
Code: Select all
;-TOP
; ***************************************************************************************
DeclareModule MyObject
Interface iBoxObject
Release()
GetWidth()
GetHeiht()
EndInterface
Interface iMyObject
Release()
GetBox()
EndInterface
Declare New()
EndDeclareModule
Module MyObject
Structure sMyObject
*vTable
BoxObject.iBoxObject
EndStructure
Structure sBoxObject
*vTable
Refcounter.i
dx.i
dy.i
EndStructure
Procedure Box_Release(*this.sBoxObject)
With *this
If \Refcounter = 0
Debug "[" + Hex(*this) + "] Box destoy object refcounter: " + \Refcounter
FreeStructure(*this)
Else
Debug "[" + Hex(*this) + "] Box release object refcounter: " + \Refcounter
\Refcounter - 1
EndIf
ProcedureReturn \Refcounter
EndWith
EndProcedure
Procedure Box_GetWidth(*this.sBoxObject)
With *this
ProcedureReturn \dx
EndWith
EndProcedure
Procedure Box_GetHeight(*this.sBoxObject)
With *this
ProcedureReturn \dy
EndWith
EndProcedure
Procedure Box_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) + "] Box new object refcounter: " + \Refcounter
EndIf
ProcedureReturn *this
EndWith
EndProcedure
Procedure Box_GetObject(*this.sBoxObject)
With *this
\Refcounter + 1
Debug "[" + Hex(*this) + "] Box get object refcounter: " + \Refcounter
ProcedureReturn *this
EndWith
EndProcedure
; -----------------------------------------------------------------
Procedure Release(*this.sMyObject)
With *this
Box_Release(\BoxObject)
FreeStructure(*this)
EndWith
EndProcedure
Procedure GetBox(*this.sMyObject)
With *this
ProcedureReturn Box_GetObject(\BoxObject)
EndWith
EndProcedure
; -----------------------------------------------------------------
Procedure New()
Protected *this.sMyObject
With *this
*this = AllocateStructure(sMyObject)
If *this
\vTable = ?vtMyObject
\BoxObject = Box_New()
EndIf
ProcedureReturn *this
EndWith
EndProcedure
DataSection
vtBoxObject:
Data.i @Box_Release()
Data.i @Box_GetWidth()
Data.i @Box_GetHeight()
vtMyObject:
Data.i @Release()
Data.i @GetBox()
EndDataSection
EndModule
; ***************************************************************************************
;- Test
Define.MyObject::iMyObject *obj1, *obj2
Define.MyObject::iBoxObject *box1, *box2
Debug "New MyObject..."
*obj1 = MyObject::New()
*obj2 = MyObject::New()
Debug "Get Object 1"
*box1 = *obj1\GetBox()
Debug *box1\GetWidth()
Debug *box1\GetHeiht()
Debug "Get Object 2"
*box2 = *obj2\GetBox()
Debug *box2\GetWidth()
Debug *box2\GetHeiht()
Debug "Relases box 1"
*box1\Release()
Debug "Relases obj 1"
*obj1\Release()
Debug "Relases box 2"
*box2\Release()
Debug "Relases obj 2"
*obj2\Release()
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 11:51 am
by Mijikai
mk-soft wrote:You have forgotten something essential with the handling of interfaces and objects.
Calling a function in a subobject is not enough.
...
I cant follow you - the solution i proposed does not change the interface itself
but extends the underlinig vtable by adding stuff but not by changing it.
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 12:20 pm
by mk-soft
Unfortunately, there are also rules in the programming.
A deviation in this range definitely leads to errors and is not supported by the compiler.
The call you're trying doesn't go like this...
Maybe someone who speaks better English can discuss this again.
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()}
Purebasic is not OOP, but supports the Object Rules
P.P.S
If you want to see what happens when objects are called up, check out my project 'OOP-BaseClassDispatch'.
This can write log files...
Re: How to call methods from the result of another interface
Posted: Sun Jul 15, 2018 12:52 pm
by Mijikai
mk-soft wrote:Unfortunately, there are also rules in the programming.
A deviation in this range definitely leads to errors and is not supported by the compiler.
The call you're trying doesn't go like this...
So i cant call a function provided by a interface in a structure?
And a structure should not hold more than just the vtable?
Im sorry i dont get it mby its a english barrier.