How to call methods from the result of another interface?

Just starting out? Need help? Post your questions and find answers here.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

How to call methods from the result of another interface?

Post 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
User avatar
NicTheQuick
Addict
Addict
Posts: 1224
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: How to call methods from the result of another interface

Post by NicTheQuick »

This ist not possible but it exists a feature request to make it possible.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: How to call methods from the result of another interface

Post 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.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to call methods from the result of another interface

Post 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.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: How to call methods from the result of another interface

Post 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:

Code: Select all

Public\VT\Object\Message()
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: How to call methods from the result of another interface

Post by Mistrel »

I don't think a structure union would work if the public interface does not align with the vtable.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: How to call methods from the result of another interface

Post 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.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: How to call methods from the result of another interface

Post 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? :|

Code: Select all

Object\VT\getA\VT\getB\VT\getC()
Compared to:

Code: Select all

Object\getA()\getB()\getC()
There's also no way to pass arguments in the call chain except to the last method.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: How to call methods from the result of another interface

Post 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? :|

Code: Select all

Object\VT\getA\VT\getB\VT\getC()
Compared to:

Code: Select all

Object\getA()\getB()\getC()
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?
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: How to call methods from the result of another interface

Post 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
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: How to call methods from the result of another interface

Post 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.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to call methods from the result of another interface

Post 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()
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: How to call methods from the result of another interface

Post 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.
User avatar
mk-soft
Always Here
Always Here
Posts: 5335
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to call methods from the result of another interface

Post 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...
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: How to call methods from the result of another interface

Post 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.
Post Reply