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