PureBasic Forum
https://www.purebasic.fr/english/

How to call methods from the result of another interface?
https://www.purebasic.fr/english/viewtopic.php?f=13&t=71028
Page 1 of 2

Author:  Mistrel [ Sat Jul 14, 2018 6:39 am ]
Post subject:  How to call methods from the result of another interface?

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:
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:
;/ Allowed
obj.SomeObject=*instance

;/ Not allowed?
Procedure.SomeObject ProcA()
  ProcedureReturn *instance
EndProcedure

Author:  NicTheQuick [ Sat Jul 14, 2018 9:37 am ]
Post subject:  Re: How to call methods from the result of another interface

This ist not possible but it exists a feature request to make it possible.

Author:  Mistrel [ Sat Jul 14, 2018 9:57 am ]
Post subject:  Re: How to call methods from the result of another interface

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.

Author:  mk-soft [ Sat Jul 14, 2018 10:24 am ]
Post subject:  Re: How to call methods from the result of another interface

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.

Author:  Mijikai [ Sat Jul 14, 2018 11:25 am ]
Post subject:  Re: How to call methods from the result of another interface

How about:
Code:
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:
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:
Public\VT\Object\Message()

Author:  Mistrel [ Sat Jul 14, 2018 12:23 pm ]
Post subject:  Re: How to call methods from the result of another interface

I don't think a structure union would work if the public interface does not align with the vtable.

Author:  Mijikai [ Sat Jul 14, 2018 12:32 pm ]
Post subject:  Re: How to call methods from the result of another interface

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

Author:  Mistrel [ Sun Jul 15, 2018 4:58 am ]
Post subject:  Re: How to call methods from the result of another interface

I've looked at this more closely. Wouldn't it result in an additional VT field for every object in the call chain? :|

Code:
Object\VT\getA\VT\getB\VT\getC()


Compared to:

Code:
Object\getA()\getB()\getC()


There's also no way to pass arguments in the call chain except to the last method.

Author:  Mijikai [ Sun Jul 15, 2018 6:35 am ]
Post subject:  Re: How to call methods from the result of another interface

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:
Object\VT\getA\VT\getB\VT\getC()


Compared to:

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

Author:  Mistrel [ Sun Jul 15, 2018 7:53 am ]
Post subject:  Re: How to call methods from the result of another interface

Say I have a world object of players and want to teleport one to 0,0,0.

Code:
world\getPlayer("Bugsy22")\teleport(0,0,0)


I can't chain these as per your workaround because:

Code:
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:
world\getPlayer\ <- this is pointer to a structure and I can't pass arguments

Author:  Mijikai [ Sun Jul 15, 2018 9:30 am ]
Post subject:  Re: How to call methods from the result of another interface

I dont rly see the problem...
Code:
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.

Author:  mk-soft [ Sun Jul 15, 2018 11:32 am ]
Post subject:  Re: How to call methods from the result of another interface

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:
;-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()

Author:  Mijikai [ Sun Jul 15, 2018 11:51 am ]
Post subject:  Re: How to call methods from the result of another interface

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.

Author:  mk-soft [ Sun Jul 15, 2018 12:20 pm ]
Post subject:  Re: How to call methods from the result of another interface

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.
Quote:
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...

Author:  Mijikai [ Sun Jul 15, 2018 12:52 pm ]
Post subject:  Re: How to call methods from the result of another interface

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.

Page 1 of 2 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/