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?
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:
CLIENT reads subroutinesâ names from DYNSUB (e.g. SUB1, SUB2âŚ) and saves them to an array (this already works)
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âŚ
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
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?
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.
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 :-))
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.
Iâve finished my Unit-Test-Framework (see [url]http://tech.forums.softwareag.com/viewtopic.php?t=22200[/url]) 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