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

  • 0
  • 0
  • 151
  • 4
  • 2

Answers

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...

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.

But why? "@" introduces an additional stack, right? And what is above in stack should be visible. Or not?

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.

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

Comments

Wow. Confirm that for IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2019.1.0S 

Working example:

Class dc.test Abstract ]
{

/// d ##class(dc.test).Test1()
ClassMethod Test1() [ ProcedureBlock = 0 ]
{
  new active,reactive,info,i
  
  kill info

  set active = 1
  set reactive = 2

  for i="active","reactive" {
    set info(i)= @i
  }

  zw info
}

/// d ##class(dc.test).Test2()
ClassMethod Test2() [ PublicList = (active, reactive) ]
{
  new activereactive
  kill info

  set active = 1
  set reactive = 2

  for i="active","reactive" {
    set info(i)= @i
  }

  zw info
}

}