I don't expect that RPG will support lambda functions, nor iterators, however it will be easy for users to implement this kind of functionality if a local scopeed loop parameter could be provided by RPG to a user procedure. This will provide a better "separation of concerns" and make it possible to isolate user specific list iterations.
The idea is to create a parameter type - like any other except that it is only defined at the prototype for the procedure to be called. And if this "special" parameter is supplied it is maintained by RPG - allocated and initialized before the first iteration begins.
example:
// The prototype - note *scratchpad and inz
dcl-pr myIterator ind ;
counter int(10) options(*scratchpad) inz(0);
myText char(10) ;
end-pr;
dcl-s myReturnText char(10);
// Mainline - get all the text items from my iterator procedure.
// note the "counter" parameter is hidden by client code but provide by RPG
// and initialized by RPG before the invocation of the loop
dow myIterator (myReturnText);
dsply myReturnText;
enddo;
return;
dcl-proc myIterator;
dcl-pi *n ind;
counter int(10);
// This is provided by RPG and is unique memory location for each dow/dou scope
myText char(10) ;
end-pi;
counter += 1;
myText = 'Loop ' + %char(counter);
return counter < 10;
end-proc;
Here I have just defined the hidden parameter in the prototype with option(*scratchpad) - I have no good name for it, but the "scratch pad" concept is also used in SQL UDTF.
The point here with the "scratch pad" idea, is that RPG will - before it enters the loop - provide a dynamic space of memory and initialize it so it is available for the implementation of the iterator procedure. Here I use an "int" but any RPG-native data type should be possible.
By providing a chunk of memory between the RPG code and the iterator code, then the implementation of the iterator code can be made in any other ILE language ( C, CPP , CLLE) and the implementation do not have to know about the mechanics for the RPG client code.
The idea here is to be able to encapsulate i.e. SQL open cursor initially, fetch rows for each successive call and finally close the cursor. Hide and isolate the iterator implementation that so it can be independently unittested.
Iterate through lists that is not arrays is also a use case. Arrays are nicely handled by "for-each". So perhaps this particular feature schuld rather be a part of user implementation in the "for-each" concept.
So what if the main loop in the client code returns within the loop? ( the control is not done by the iterator procedure) - Then RPG will call and run the "on-exit" part of (all active ) iterator implementation procedure(s) if provided. ( how to do that in plain C / CLLE i don't have figured out yet)
For simplicity - i did not provide the on-exit in this example. And this case does not requires explicit cleanup.
In the above example I have used a good old "Ind" as the return value. However, any return value ( bool, char ,int) that can be used in the logical comparison could of course be used.
The reason for the "dynamic and unique" is when this structure is used in a recursive loop / call
While this is an interesting idea, it would be very complex to implement in the compiler, and it would not offer significant enough benefit to RPG programmers. As discussed in the comments, this can already be achieved in RPG now, with the RPG programmer handling any necessary initialization before beginning the loop.
However, this Idea may have future value, so we will add it to an internal list for us to keep in mind for the future.
- IBM Power Systems Development
The CEAC has reviewed this requirement and recommends that IBM view this as a HIGH priority requirement that is important to address.
Background: The COMMON Europe Advisory Council (CEAC) members have a broad range of experience in working with small and medium-sized IBM i customers. CEAC has a crucial role in working with IBM i development to help assess the value and impact of individual RFEs on the broader IBM i community and has therefore reviewed your RFE.
To find out how CEAC help to shape the future of IBM i, see CEAC @ ibm.biz/BdYSYj and the article "The Five Hottest IBM i RFEs Of The Quarter" at ibm.biz/BdYSZT
Sabine Jordan + Sara Anrdres – CEAC Program Manager, IBM
1. Please explain further how the "scratchpad" feature is different from simply defining your own variable to pass as the first parameter.
dcl-pr myIterator ind ;
counter int(10);
myText char(10) ;
end-pr;
dcl-s myCounter int(10);
myCounter = 0;
dow myIterator (myCounter : myReturnText);
dsply myReturnText;
enddo;
return;
2. Please clarify what you meant when you said that having RPG provide the scratchpad variable would allow the implementation of the iterator code to be written in any language. Wouldn't the iterator procedure be the same whether or not RPG supported this feature?
3. About having RPG call the ON-EXIT part of all active iterator procedures, the ON-EXIT part of a procedure is always called when the procedure ends. It cannot be called separately. Please provide more information about the "ON-EXIT" part of your idea.
Thank you.
- IBM Power Systems Development
The CAAC has reviewed this IBM Idea and recommends that IBM view this as a medium priority Idea that should be addressed.
Helping the community to be more creative in RPG will help keep the language relevant. Anywhere we can make the language more normal is a must. Especially with bringing new to i developers to the platform.
Background: The COMMON Americas Advisory Council (CAAC) members have a broad range of experience in working with small and medium-sized IBM i customers. CAAC has a key role in working with IBM i development to help assess the value and impact of individual IBM Ideas on the broader IBM i community and has therefore reviewed your Idea.
For more information about CAAC, see www.common.org/caac
Carmelita Ruvalcaba- CAAC Program Manager
"
scratchpad" sql has different semantics (one per function reference etc.).
RPG have by default static variables if you need global per module state.
You can "sort of" encapsulate SQL based iteration if one wishes. But take in account that cursors are named and per-module (just track "first call" ... body ... "last record").
Just pass the required "per iteration state memory" in a DS passed to the "iterator" function (working instance mem and results).
A native and idiomatic FOR-EACH supporting native access and cursors would be nice, there is a RFE but it was I think closed/rejected....