Perform a subroutine dynamically by its name from string

Hello Natural-Community :slight_smile:

I would like to know if it is possible to dynamically perform a subroutine by its name. Given a subprogram DYNSUB like the following (which doesnā€™t work, because PERFORM needs a constant parameter):

DEFINE DATA
PARAMETER
01 #SUBROUTINE (A32) BY VALUE
END-DEFINE
*
PERFORM #SUBROUTINE
*
DEFINE SUBROUTINE ROUTINE1
INPUT (AD=IO) 'in subroutine:' *CURRENT-UNIT
END-SUBROUTINE
*
END

I would like to be able to CALLNAT it and let it perform only the subroutine with the name provided in the parameter like this:

CALLNAT 'DYNSUB' 'ROUTINE1'

Iā€™ve already tried almost every possible way of doing that (e.g. copycodes with parameters, RUN statements with global variables) but none was sufficient for me.

To sum it up: I need a way of calling a single subroutine in a subprogram by providing the subroutineā€™s name in a parameter of the subprogram. And I donā€™t want to switch to CALLNATs with parameters, I need it for subroutinesā€¦

Could anybody please help me or at least confirm that this is not possible in Natural?

Best regards
Stefan

The only way I know is:

  1. Write a Subprogramm dynamically using
define printer output 'SOURCE'
  1. Run the sourcecode (or stow+execute it)

Hi Stefan;

You are correct; the name of a subroutine must be specified explicitly.

However, what you are trying to do is easily accomplished.

For example:

IF #SUBROUTINE = ā€˜ROUTINE1ā€™
PERFORM ROUTINE1
END-IF

If there are to be many subroutines, I would use DECIDE rather than IF.

steve

Dear Steve.

Well, of course that would work. But I really need to call the subroutine from a string, because I donā€™t want to create large IF/DECIDE statements for my many subroutines. I want to be able to call them dynamically via some kind of ā€œreflectionā€ like in Java/.NET.

Perhaps I should tell the whole story: what I want to accomplish is to read the defined subroutinesā€™ names from a subprogramā€™s source. Then I want to call them one by one from the outside:

  1. CLIENT reads subroutinesā€™ names from DYNSUB (e.g. SUB1, SUB2ā€¦) and saves them to an array (this already works)
  2. for each subroutine in the array
    2.1) CLIENT calls DYNSUB with subroutineā€™s name
    2.2) DYNSUB performs subroutine

If I created IF/DECIDE statements in DYNSUB I would need to add a new condition for each new subroutine I add. And that would be duplicated code (which I donā€™t like ;-)) and easy to forgetā€¦

Dear Matthias.

That would work (I have already tried that), but I need to pass parameters around and return to the calling program. And every time RUN is called, the program stack and all parameters are gone :frowning:

Why not have CLIENT CALLNAT DYNSUB and have DYNSUB perform each subroutine? Why have CLIENT determine the subroutine list?

Hi Stefan;

Is there a reason not evident to us yet, why these ā€œsubroutinesā€ could not be subprograms?

If DYNSUB provides an array of ā€œsubroutine namesā€ then executes the subroutines one at a time, when ā€œinvokedā€, why not have DYNSUB execute the subroutines rather than (in addition to?) return the array to the client which then invokes DYNSUB many times?

steve

Iā€™m programming a Unit-Test-Framework for Natural and I want to use subprograms as the TestCases and subroutines as the tests. If I used subprograms as tests I would end up with lots of subprograms with 8 letters that nobody could manage. With subroutines Iā€™ve got 32 letters and can put multiple tests in a TestCase (subprogram) with the same fixture.

The CLIENT is the TestRunner that collects the test results from all tests, so he should know their names and be able to pass a CollectingParameter into them and get it back.

And I want to be able to quickly add a new test (subroutine) to a TestCase (subprogram) without having to add a condition for the subroutineā€™s name to an IF/DECIDE statement because that would be error proneā€¦

If I get the time to finish it, I have written most of a system to allow long names for Natural objects (programs, subprograms, etc).

The heart of the system is a table (Adabas file) that relates fifty character descriptions to internally generated eight character Natural object names.

This all grew out of code to give a longer more descriptive identifier for Natural recordings, which of course have the usual 8 character restriction.

Perhaps you could use a similar table idea to simply relate 8 character subprogram names to longer descriptions.

steve

Dear Steve,

to me that sounds like a ā€œRegistryā€ where a program can register its name (8 letters) under an alias (50 letters) that can be called from other programs!? Thatā€™s another concept I need for unit testing! I want to be able to do some sort of ā€œDependency Injectionā€ in Natural. A colleague of mine already prototyped something like that:

CLIENT registers subprogram SUB1 for Key ā€œCalculateSomethingā€ in the registry
CLIENT calls SUB2
SUB2 needs to ā€œCalculateSomethingā€, asks the registry for the concrete program and gets SUB1 which it calls
SUB1 calculates something

If I want to test SUB2 without having to wait for it to CalculateSomething by calling SUB1 (which is very time consuming ;-)) I do the following:

TESTCLIENT registers STUBSUB1 for Key ā€œCalculateSomethingā€ in the registry
TESTCLIENT calls SUB2
SUB2 asks registry for CalculateSomething and gets STUBSUB1 which it calls
STUBSUB1 does not calculate anything but returns a dummy value instead

This whole concept works with subprograms at the moment because I need to call programs via their names (strings) and this does not work with subroutines (until someone proves the difference here :-))

Hi Stefan;

Just a couple of notes:

Matthiasā€™s suggestion can also be done with USR1035 (check the number, but I think it is correct) which allows you to edit a Natural object.

Your project sounds rather interesting. My utility idea is much more modest. I am concerned with being able to find objects based on keywords; e.g. find all the programs with the words ā€œthird quarterā€ when I need to run a third quarter report.

However, I can see the value of what you are trying to do. Basically, instead of what some of us suggested earlier, using DECIDEs or IFs, you would alter the registry and effect the same decision making as the DECIDEs. Cute. If you combined this with USR1035, you could probably do this for PERFORMs as well.

steve

Iā€™ve finished my Unit-Test-Framework (see http://tech.forums.softwareag.com/viewtopic.php?t=22200) and I used subprograms as TestCases that are called via CALLNAT. But instead of dynamically calling subroutines as the tests inside the subprogram (which apparently doesnā€™t work ;-)) I now parse the TestCasesā€™ source code for strings in IF-clauses that are then used to call a test via a parameter containing the string (take a look at my post for an example). As a result I am not restricted to a maximum of 32 characters per test name and can provide meaningful names to describe the test. Thanks again for helping me figure out that dynamic calls in Natural are not (yet) possible :slight_smile: