Indirection example does not work
Here's a simple indirection snippet. It fails with <UNDEFINED> error and I'm not sure why.
ClassMethod ind()
{
kill info
set active = 1
set reactive = 2
for i="active","reactive" {
set info(i)= @i
}
zw info
break
}
I'm getting this exception: <UNDEFINED>zind+5^test.Client.1 *active
Comments
Wow. Confirm that for IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2019.1.0S
But why? "@" introduces an additional stack, right? And what is above in stack should be visible. Or not?
Quoting doc: "Name indirection, argument indirection, and XECUTE commands that appear within a procedure are not executed within the scope of the procedure."
https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCOS_usercode_indirxecjob
Consider method:
Class Test.test [ Abstract ]
{
ClassMethod ind()
{
kill info
set active = 1
set i="active"
set @i = "global scope"
break
}
}
Output:
USER>do ##class(Test.test).ind()
break }
^
<BREAK>zind+5^Test.test.1
USER 2d1>w
active="global scope"
<Private variables>
active=1
i="active"
Notice private variables and public variables.
No, indirection does not introduce additional stack, as far as I know. It works with variables that are visible in public (global) scope, not in private scope of procedure.
Working example:
<FONT COLOR="#000080">Class dc.test </FONT><FONT COLOR="#000000">[ </FONT><FONT COLOR="#000080">Abstract </FONT><FONT COLOR="#000000">]
{
</FONT><FONT COLOR="#000080">/// d ##class(dc.test).Test1()
ClassMethod </FONT><FONT COLOR="#000000">Test1() [ </FONT><FONT COLOR="#000080">ProcedureBlock </FONT><FONT COLOR="#000000">= 0 ]
{
</FONT><FONT COLOR="#0000ff">new </FONT><FONT COLOR="#800000">active</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">reactive</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">info</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#800000">i
</FONT><FONT COLOR="#0000ff">kill </FONT><FONT COLOR="#800000">info
</FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">active </FONT><FONT COLOR="#000000">= 1
</FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">reactive </FONT><FONT COLOR="#000000">= 2
</FONT><FONT COLOR="#0000ff">for </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"active"</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#008000">"reactive" </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">info</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">)= @</FONT><FONT COLOR="#800000">i
</FONT><FONT COLOR="#800080">}
</FONT><FONT COLOR="#0000ff">zw </FONT><FONT COLOR="#800000">info
</FONT><FONT COLOR="#000000">}
</FONT><FONT COLOR="#000080">/// d ##class(dc.test).Test2()
ClassMethod </FONT><FONT COLOR="#000000">Test2() [ </FONT><FONT COLOR="#000080">PublicList </FONT><FONT COLOR="#000000">= (active, reactive) ]
{
</FONT><FONT COLOR="#0000ff">new </FONT><FONT COLOR="#800000">active</FONT><FONT COLOR="#000000">, </FONT><FONT COLOR="#800000">reactive
</FONT><FONT COLOR="#0000ff">kill </FONT><FONT COLOR="#800000">info
</FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">active </FONT><FONT COLOR="#000000">= 1
</FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">reactive </FONT><FONT COLOR="#000000">= 2
</FONT><FONT COLOR="#0000ff">for </FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">=</FONT><FONT COLOR="#008000">"active"</FONT><FONT COLOR="#000000">,</FONT><FONT COLOR="#008000">"reactive" </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#800000">info</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#800000">i</FONT><FONT COLOR="#000000">)= @</FONT><FONT COLOR="#800000">i
</FONT><FONT COLOR="#800080">}
</FONT><FONT COLOR="#0000ff">zw </FONT><FONT COLOR="#800000">info
</FONT><FONT COLOR="#000000">}
}</FONT>
The correct way is:
ClassMethod ind() [ PublicList = (active,reactive) ]
{
new active,reactive
kill info
// the above command (kill info) is a kind of NOP (no-operation)
// at the time of entry into a methode there are no variables,
// except those in the public list (if defined)
set active = 1
set reactive = 2
for i="active","reactive" {
set info(i)= @i
}
zw info
break
}
If you want to use name-indirection in a procedure block, then
- variables, used by indirection, must be made public (via PublicList)
- and, depending on the situation, should be saved with the NEW command