Page 1 of 1

It is possible to call a procedure by using its address?

Posted: Tue Nov 08, 2016 5:33 pm
by Wolfram
Can someone tell me is it possible to call a procedure this way…?

Code: Select all

Procedure Test_A()
  
  Debug "A"
EndProcedure

Procedure Test_B()
  
  Debug "B"
EndProcedure


Dim MyFnctions.i(100)

MyFnctions(0) = @Test_A()
MyFnctions(1) = @Test_B()

;can I call Test_A() by using the stored address in MyFnctions(0)???

Re: It is possible to call a procedure by using its address?

Posted: Tue Nov 08, 2016 5:39 pm
by TI-994A
Like this:

Code: Select all

Procedure Test_A()
  Debug "A"
EndProcedure

Procedure Test_B(t.s)
  Debug t
EndProcedure

Dim MyFnctions.i(100)

MyFnctions(0) = @Test_A()
MyFnctions(1) = @Test_B()

CallFunctionFast(MyFnctions(0))
CallFunctionFast(MyFnctions(1), @"B")

Re: It is possible to call a procedure by using its address?

Posted: Tue Nov 08, 2016 5:45 pm
by Wolfram
Thanks!
I hope it is what it suggested - fast. ;-)

Re: It is possible to call a procedure by using its address?

Posted: Tue Nov 08, 2016 6:46 pm
by wilbert
Wolfram wrote:I hope it is what it suggested - fast. ;-)
When it comes to speed, I think using Prototype would be a little bit faster.

Re: It is possible to call a procedure by using its address?

Posted: Tue Nov 08, 2016 11:16 pm
by netmaestro
Is that old thing still here? Should be deprecated by now imho. It's limited to integers as parameter, not so for prototypes:

Code: Select all

Prototype ThisKindOfProc(a.i, b.s)

Procedure DoSomeOfThis(a.i, b.s)
  Debug "My name is " + b
  Debug "I am " + Str(a) + " years old"
EndProcedure

Global This.ThisKindOfProc = @DoSomeOfThis()

This(100, "Hillary")
I vote with Wilbert on this one.

Re: It is possible to call a procedure by using its address?

Posted: Tue Nov 08, 2016 11:42 pm
by Wolfram
Thanks for the Prototype example, but my idea was to call a Procedure depends of a result.
Normally you must use select to run the right Procedure depends of the result.
This is a lot of work for me and the computer, if I have 100 different results.

Code: Select all

Procedure Test_A()
  Debug "A"
EndProcedure

Procedure Test_B()
  Debug t
EndProcedure

Dim MyFnctions.i(100)

MyFnctions(0) = @Test_A()
MyFnctions(1) = @Test_B()


CallFunctionFast(MyFnctions(result))

Re: It is possible to call a procedure by using its address?

Posted: Wed Nov 09, 2016 6:20 am
by TI-994A
Wolfram wrote:Thanks for the Prototype example, but my idea was to call a Procedure depends of a result.
Yes; sadly, prototypes can't be used in arrays, lists, or maps. If you need to pass values other than integers with CallFunctionFast(), simply store them in a string, pass the string address, and read the value with the corresponding ValX() function.

Code: Select all

Procedure passTypes(nbr, txt.s, flt.s)
  Debug nbr
  Debug txt
  Debug ValF(flt)
EndProcedure

myFunc = @passTypes()
CallFunctionFast(myFunc, 123, @"Hello!", @"456.789")
Not very elegant, but it's a viable workaround. :wink:

Re: It is possible to call a procedure by using its address?

Posted: Wed Nov 09, 2016 7:37 am
by wilbert
Prototype with Runtime example

Code: Select all

; >> Runtime Procedures <<

Runtime Procedure Fn0()
  Debug "A"
EndProcedure

Runtime Procedure Fn1(n)
  Debug n
EndProcedure

Runtime Procedure Fn2(n)
  Debug n*n
EndProcedure

Runtime Procedure Fn3(s.s)
  Debug s
EndProcedure

Runtime Procedure Fn4(s.s)
  Debug LCase(s)
EndProcedure

Runtime Procedure Fn5(s.s)
  Debug UCase(s)
EndProcedure


; >> Prototypes for different kind of functions <<

Prototype FnProto()
Prototype FnProto1Arg(arg1.i)
Prototype FnProto1StrArg(arg1.s)


; >> Structure with all kind of function prototypes <<

Structure FnStruct
  StructureUnion
    FnAddr.i
    Call.FnProto
    Call1Arg.FnProto1Arg
    Call1StrArg.FnProto1StrArg
  EndStructureUnion
EndStructure


; >> Count Runtime Procedures <<

FnCount = 0
While IsRuntime("Fn" + Str(FnCount) + "()")
  FnCount + 1
Wend


; >> Runtime Procedures to Array <<

If FnCount
  Dim Fn.FnStruct(FnCount - 1)
  i = 0
  While i < FnCount
    Fn(i)\FnAddr = GetRuntimeInteger("Fn" + Str(i) + "()")
    i + 1
  Wend
EndIf


; >> Test the procedures <<

Fn(0)\Call()
Fn(1)\Call1Arg(100)
Fn(2)\Call1Arg(100)
Fn(3)\Call1StrArg("Prototype method")
Fn(4)\Call1StrArg("Prototype method")
Fn(5)\Call1StrArg("Prototype method")

Prototype without Runtime example

Code: Select all

Procedure Test_A()
  Debug "A"
EndProcedure

Procedure Test_B(n)
  Debug n
EndProcedure

Procedure Test_C(n)
  Debug n*n
EndProcedure

Procedure Test_D(s.s)
  Debug s
EndProcedure



Prototype FnProto()
Prototype FnProto1Arg(arg1.i)
Prototype FnProto1StrArg(arg1.s)

Structure FnStruct
  StructureUnion
    FnAddr.i
    Call.FnProto
    Call1Arg.FnProto1Arg
    Call1StrArg.FnProto1StrArg
  EndStructureUnion
EndStructure

Dim MyFnctions.FnStruct(100)

MyFnctions(0)\FnAddr = @Test_A()
MyFnctions(1)\FnAddr = @Test_B()
MyFnctions(2)\FnAddr = @Test_C()
MyFnctions(3)\FnAddr = @Test_D()

MyFnctions(0)\Call()
MyFnctions(1)\Call1Arg(100)
MyFnctions(2)\Call1Arg(100)
MyFnctions(3)\Call1StrArg("Prototype method")

Another way would be to use DataSection for the function pointers but it does look a bit more complicated I think.

Code: Select all

Procedure Test_A()
  Debug "A"
EndProcedure

Procedure Test_B(n)
  Debug n
EndProcedure

Procedure Test_C(n)
  Debug n*n
EndProcedure

Procedure Test_D(s.s)
  Debug s
EndProcedure


DataSection
  FnAddrTable:
  Data.i @Test_A(), @Test_B(), @Test_C(), @Test_D()
EndDataSection


Prototype FnProto()
Prototype FnProto1Arg(arg1.i)
Prototype FnProto1StrArg(arg1.s)

Structure FnStruct
  Call.FnProto[0]
  Call1Arg.FnProto1Arg[0]
  Call1StrArg.FnProto1StrArg[0]
EndStructure

*F.FnStruct = ?FnAddrTable

*F\Call[0]()
*F\Call1Arg[1](100)
*F\Call1Arg[2](100)
*F\Call1StrArg[3]("Prototype method")