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
Thanks
Comments
underscore (_) is not allowed in variable names
eventually, you mean set @("x"_Counter) = DIAGS
XECUTE ("set x"_Counter_"="""_DIAGS_"""") should work too
and BTW, what's dynamic about it?
do you mean an array x(Counter) ????
Thank you Tim!
You finally gave me a hint why to use
as a Method_Parameter. I never saw serious reasons for it.
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,
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.
Try indirection: ObjectScript Indirection
f counter=1:1:10 {
set @(var_counter)="test"
}
zw
Or, using the XECUTE command
f counter=1:1:10 {
set myCmd="set @(var_counter)=""test"""
XECUTE myCmd
}
zw
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.