Question
· Apr 30, 2018

How to set dynamic variable names ?

Hi ,

Does anyone know how to dynamically set a variable, for example 

set Counter = 1

set x_Counter ="test"  in Cache Object script.  I tried with EXECUTE XECUTE ("set x"_Counter "="_DIAGS_""), but it does not work.

Thanks

Discussion (7)1
Log in or sign up to continue

Nope its just that i have variables like Diag1, Diag2,Diag2 and in my loop i might get data for Diag1 or sometimes Diag1, Diag2 so i must assigned values into them dynamically rather than using separate if conditions like,

if (diagCounter = 2){
    set DIAGNOSIS2 = DIAGS
    }elseif (diagCounter = 3){
    set DIAGNOSIS3 = DIAGS
    }

Anyways thanks for your answer.

For completeness, here's an extension of the above example that actually works the way you'd expect (using PublicList to handle scope, and New to avoid leaking any variables):

Class DC.Demo.Indirection
{

ClassMethod Driver() [ PublicList = x ]
{
    New x
    Do ..Run()
    Do ..RunSets()
    Do ..Run()
}

ClassMethod Run() [ PublicList = x ]
{
    Set x = 5
    Try {
        Write @"x"
    } Catch e {
        Write e.DisplayString()
    }
    Write !
    Try {
        Xecute "write x"
    } Catch e {
        Write e.DisplayString()
    }
    Write !
}

ClassMethod RunSets() [ PublicList = x ]
{
    Set x = 5
    Set @"x" = 42
    Write x,!
    Xecute "set x = 42"
    Write x,!
}

}

Results:

USER>d ##class(DC.Demo.Indirection).Driver()
5
5
42
42
5
5
 
USER>w

USER>

But that doesn't mean it's a good idea to do things like this.

Most of the time, you don't really need to use XECUTE/indirection/etc - there is usually a better way to accomplish the same thing. Furthermore, in modern coding practices, XECUTE and name indirection probably will not work the way you expect, because they can only access public variables (not those in the scope of your method). For example, given the following class:

Class DC.Demo.Indirection
{

ClassMethod Run()
{
    Set x = 5
    Try {
        Write @"x"
    } Catch e {
        Write e.DisplayString()
    }
    Write !
    Try {
        Xecute "write x"
    } Catch e {
        Write e.DisplayString()
    }
}

ClassMethod RunSets()
{
    Set x = 5
    Set @"x" = 42
    Write x,!
    Xecute "set x = 42"
    Write x,!
}

}

The output when run in terminal is:

USER>Do ##class(DC.Demo.Indirection).Run()
<UNDEFINED> 9 zRun+3^DC.Demo.Indirection.1 x
<UNDEFINED> 9 zRun+9^DC.Demo.Indirection.1 x
USER>d ##class(DC.Demo.Indirection).RunSets()
5
5
USER>d ##class(DC.Demo.Indirection).Run()
42
42

Your code certainly should not rely on such scoping behavior. There are ways around this (for example, adding  [ PublicList = x ] to the method signature, using New, etc.), but they are messy and difficult to understand and maintain.

In your particular case, using a local array would probably be a better approach - for example:

set x(counter) = DIAGS

Although if you provided more context for why you think you need to dynamically set variables, the community might have other suggestions.