ABL : dynamically invoking methods

DevTeam

Member
Hi,

I've searched documentation about dynamic programming in ABL, and I've found information about dynamic-new and dynamic-cast. But there seems to be no implementation of "dynamic-method" or "dynamic-invoke" making it possible to call a method whose name is in a variable.

Was my searching too light ? Would anyone have a workaround, or is it simply not possible yet and expected in a later version of OE ?

Thanks in advance.

Julien
 

Casper

ProgressTalk.com Moderator
Staff member
How do you use that for an object instance?
The in-handle atribute expects a handle. But there is no handle to a class instance, there is just a reference...

It seems to me that the 'objects' they talk about are system objects like session and file-info....

But saying this, I agree with Thomas that overloading is a much stronger concept in most cases.

Casper.
 

DevTeam

Member
First of all, thanks to the three of you for your answers.

I have no specific example in mind, but let's imagine a .p server program whose job is to receive messages from client programs according to a given protocol...

For instance :
- the message "inst@myClass1@valParam1@valParam2" means instantiating the class "myClass", with parameter values needed for its constructor.
After the instantiation, the server returns an identifier of this instance and the resulting "OUTPUT" parameters.

- Then the client side sends the message "inv@1@myMethod@valParam1@valParam2@valParam3", standing for the execution of the method "myMethod" on the instance identified by "1" with the following parameter values.


I can manage the first message with the use of DYNAMIC-NEW, but I can't think of a way to manage the second call as DYNAMIC-INVOKE does not exist yet.


I'm not asking if there's a better way to complete this example (even if advice's always good enough to be listened to), but I am wondering why only "half of the job" has been done with reflection implementation, and whether it will be handled in next OE releases.


Joey, the CALL object seemed a good idea to me too but, as Casper figured, it only works with handles. Trying to use it with class instances results in a "myClass.cls is an object and cannot be use in a RUN statement. Use the NEW statement to instanciate it" (this is a translation of the Progress error originally in French).


Julien
 

tamhas

ProgressTalk.com Sponsor
PSC admits that the reflection job is only partly done and it is on the roadmap, but without any time frame, so I wouldn't hold your breath.

Frankly, I dislike these dynamic everything designs since it makes it impossible to document and control what the application is doing. It completely voids the advantages of compile time checking we get with OO.
 

DevTeam

Member
PSC admits that the reflection job is only partly done and it is on the roadmap, but without any time frame, so I wouldn't hold your breath.

Frankly, I dislike these dynamic everything designs since it makes it impossible to document and control what the application is doing. It completely voids the advantages of compile time checking we get with OO.

If you want to create generic programs (without using include files), you can't do without "dynamic everything designs", and that's a good thing dynamic queries and RUN VALUE exist in 4GL.

Of course I agree with you on the advantages of compile-time checking, but that shouldn't change too much habits of people who are used to execution time checking in 4GL...

Good to know something is planned for a complete implementation of reflection.
 

tamhas

ProgressTalk.com Sponsor
I don't see the virtue in generic programs. Much better to put that energy into a good framework and program generation and then you have programs which are closely suited to purpose, not trying to do everything anyone ever wanted.

Somehow, I also don't see having lived with run time errors all these years as a virtue, especially when there is now a way to avoid them.
 

cwills

New Member
I agree, having to call a method dynamically generally indicates a 'design smell'. There are some cases where you need to use reflection to invoke methods (do carefully). Below is an example of how you could invoke a method dynamically:

File 1: CallMethod.p

Code:
ROUTINE-LEVEL ON ERROR UNDO, THROW.
DEFINE INPUT PARAMETER obj AS CLASS {1} NO-UNDO.

&if {4} = Yes &then
  {1}:{2}({3}).
&else
  obj:{2}({3}).
&endif

File 2: MethodInvoker.cls

Code:
ROUTINE-LEVEL ON ERROR UNDO, THROW.
CLASS MethodInvoker:

   METHOD PUBLIC STATIC VOID Invoke(INPUT obj AS Progress.Lang.Object, 
                                    INPUT methodName AS CHARACTER,
                                    INPUT methodParams AS CHARACTER,
                                    INPUT isStatic AS LOGICAL):
    DO ON ERROR UNDO, THROW
       ON QUIT UNDO, RETURN ERROR NEW Progress.Lang.AppError("Quit condition occured",0) 
       ON STOP UNDO, RETURN ERROR NEW Progress.Lang.AppError("Stop condition occured",0):
      RUN CallMethod.p(INPUT obj) obj:GetClass():TypeName methodName methodParams isStatic.
    END.
    
  END METHOD.

END CLASS.

Then you can simply call MethodInvoker:Invoke passing in the object and method you wish to invoke...
 

DevTeam

Member
Thanks for this workaround, I'm not used to using preprocessor arguments in RUN statements.

I'll try it with simple examples first (but it may be quite difficult to deal with methods returning values or declaring OUTPUT parameters).
 

tamhas

ProgressTalk.com Sponsor
Recognize that this is either a compile time only solution or a solution which requires the user to have a license which will allow compiling on the fly. I don't think either one is likely to help you much. If compile time only helps, there are various generator techniques for getting the right thing in there which are cleaner than this argument approach. It is unlikely you want to allow compile on the fly as a general solution.
 
Top