Help with indirection and variable scope
Hello fellows, I need you wisdom.
In my organization we code in ObjectScript and .int everyday. When I joined nobody knew barely nothing about classes and their use was almost only for storage definition purpose. During my self-learning in caché I discovered the object oriented programming and class developing was possible in caché and started to code in .cls . Being something self-taught, I may have some basic doubts I'd have missed in my documentation readings.
With this scenario in mind, it is common that we use the @ operator to use wildcards for storing same data structures in different named tables, or playing with indexes. And relating to this I have found a problem in classes I don't know how to get rid off.
I'll try to put an example as generic and understandable as I can:
In OS .int we use this:
Indirection() N (evenTotal) set TABLES(0)="EVEN" set TABLES(1)="ODD" for i=1:1:100 { set table = TABLES((i#2)) set @(table_"("_i_")")=i // Xecute alternative, same issue ; set cmd = "set "_table_"("_i_")="_i ; x cmd } set evenTotal=0 set i="" for { set i=$O(EVEN(i)) Q:i="" set evenTotal = evenTotal+EVEN(i) } zw evenTotal Q
It works and when finished no variables are in memory after execution (besides evenTotal, included in NEW).
But when I do this in .cls:
ClassMethod Indirection() { set TABLES(0)="EVEN" set TABLES(1)="ODD" for i=1:1:100 { set table = TABLES((i#2)) set @(table_"("_i_")")=i // Xecute alternative, same issue ; set cmd = "set "_table_"("_i_")="_i ; x cmd } set evenTotal=0 set i="" for { set i=$ORDER(EVEN(i)) QUIT:i="" set evenTotal = evenTotal+EVEN(i) } zwrite evenTotal }
I get evenTotal zero. Inside the method I can zwrite EVEN and I see the values, but the ORDER goes empty and if I do 'write EVEN(2)' I get UNDEFINED, although I see the value though a zwrite. It's very confusing.
A side effect I get using @ is EVEN and ODD jumps in memory after the method execution. I don't want them in memory.
Playing with the PublicList keyword has not worked for me.
How can I make the 'ObjectScript .int' example work properly in .cls?
Nowadays I try to evade this practice in cls, and some rare times I add the variables to the publicList and try to KILL them before the end of the method. Has worked so far.
to allow Indirection in your case or eXecute to work, you have to set
see: https://docs.intersystems.com/iris20212/csp/docbook/DocBook.UI.Page.cls?KEY=ROBJ_method_procedureblockand my related article: https://community.intersystems.com/post/summary-local-variable-scoping
Thanks for the reply. I've tried that too, but if I set the ProcedureBlock to 0, all the variables stay loaded in memory after the method execution, which is worse than having only the ones used inside the indirection.
Is it a dead end? There is no chance to have it working?
I read about $XECUTE accepting parameters. I tried some aproaches without good results. Could it work using that, @Robert Cemper ?
Also, thanks a lot for the link, it's a very interesting post.
Next variant
or using %EVEN,%ODD instead of EVEN, ODD
I think that that's not valid as "in theory" he doesn't know the name of variables. I would try this:
ClassMethod Indirection()
{
set TABLES(0)="EVEN"
set TABLES(1)="ODD"
for i=1:1:100
{
set table = TABLES((i#2))
set @table@(i)=i
}
zw @table
set evenTotal=0
set i=""
for
{
set i=$ORDER(@table@(i)) QUIT:i=""
set evenTotal = evenTotal+@table@(i)
}
zwrite evenTotal
}
BINGO ! You are right!
Saludos,
Ok so, to summarize the thread:
Requirements:
1.- Work with variable table names.
2.- Being able to 'see'/'use' them (i.e. the evenTotal count)
3.- Not having the variables loaded in memory after method execution.
In 'ObjectScript+.int' you can have all 3. In '.cls' you can only have 1 and 2, waiving point 3.
Options in '.cls' from better to worse in my opinion are:
a. The cleanest option I've seen is @Jose Tomas Salvador version. This option still doesn't have the point 3 but you can kill the variables before leaving the method.
b. Before 'Jose Tomas version' my choice was adding the variables to public list, and trying to kill them before leaving the method. Although it breaks the not knowing the names thing.
c. Using percent variables (obscure, and also my colleages don't know well percent vars, so risky too)
d. Set ProcedureBlock=0 (worst choice in my opinion as it makes visible all variables)
Thank you very much for your help as I was a bit anxious with this thing thinking there was a better option and I was too clumsy to find it.
AS you push on "nothing in memory" which is not related at all to INDIRECTION
I have streamlined your code to not leave any traces in memory.
OLÉ
Take into account that variables created with indirection are always public even if they're created within a procedure (in this case a classmethod with ProcedureBlock = 1 by default). So to avoid them to be in memory outside the method, you'll have to kill them.
What about this one:
Social networks
InterSystems resources
Log in or sign up
Log in or create a new account to continue
Log in or sign up
Log in or create a new account to continue
Log in or sign up
Log in or create a new account to continue