In an attempt to simplify child -> parent return data, I decided to see if I could implement a reliable stack structure within TM1 to easily pass values between functions without having to write anything to a cube. My main requirements were:
1) No cube writes - I wanted to see if I could easily pass values between processes without having to rely on cubes (and views); I want simple, functional programming style returns
2) Minimal code - this will never fly if I have to remember to initialize/call 5+ TIs
3) No outside code - can only use TM1 functions and objects
What I came up with expands the functionality of session variables by allowing multiple values to be returned through a reference to a dimension acting as a stack. The basic concept is as follows:
Code: Select all
StringSessionVariable('session.stack'); /* reference to the stack name (private) */
StringSessionVariable('session.stack_prefix'); /* reference to a predefined prefix (private) */
StringSessionVariable('session.stack_return'); /* reference to a popped value (public)
NumericSessionVariable('session.stack_pointer'); /* reference to the stack pointer (private) */
NumericSessionVariable('session.stack_sanity'); /* reference to the sanity check (public) */
The stack_sanity variable is included as a sort of macro to ensure that our stack is always in sync. On each successful pop or push the stack_sanity variable is redefined to DIMSIZ(session.stack) - stack_pointer. In this way, we can ensure that our stack is synced in case of a bad run that causes our pointer to be misaligned with the current element count. It is probably safer to check that stack_sanity is equal to 0 before using a popped value.
A simple implementation could look something like the following:
Code: Select all
StringSessionVariable('session.stack_return');
NumericSessionVariable('session.stack_sanity');
ExecuteProcess('push', 'psStr', 'test1'); /* push "test1"; the stack will initialize if not already done */
ExecuteProcess('push', 'psStr', '15'); /* push "15"; all values are pushed as strings - ints must be cast
appropriately before use after popping */
ExecuteProcess('pop', 'pnType', 0); /* pop the last value ("15") LIFO style */
if (session.stack_sanity = 0); /* check that we're synced */
asciioutput('test_file.csv', session.stack_return); /* session.stack_return contains our popped value */
endif;
If you want to pop multiple values, consider pushing the number of elements you want to pop as the final element of the stack. Then when you pop the first value in a different process, you can use that as the condition for a while loop to pop the rest of the values.
This may not be game changing and probably won't ever see anything more than a development environment, but it was at least fun to play with. If you're interested, the code with the sample implementation can be found at my github link: https://github.com/bgregs514/tm1_code