Article
Evgeny Shvarov · Aug 9, 2021 1m read

How do you change namespaces in routines or new $namespace vs znamespace

Hi developers!

Just want to share an old but always relevant best practice on namespaces changing @Dmitry Maslennikov shared with me (again).

Consider method:

classmethod DoSomethingInSYS() as %Status

{

set sc=$$$OK

set ns=$namespace

zn "%SYS"

// try-catch in case there will be an error

try {

// do something, e.g. config change

}

catch {}

 zn ns    ; returning back to the namespace we came in the routine

return sc

}

And with new $namespace the method could be rewritten as:

classmethod DoSomethingInSYS() as %Status

{

set sc=$$$OK

new $namespace

set $namespace="%SYS"

// do something

return sc

}

So! The difference is that we don't need to change the namespace manually as it will be back automatically once we return the method.

and we don't need try-catch (at least for this purpose) too.

3
0 325
Discussion (4)1
Log in or sign up to continue

The key feature here is `new $namespace` command rather than the method of its changing, while `set $namespace="%SYS"` seems to be the preferred one as it is well documented and good looking.

I'd still use try / catch outside namespace changing as there can be security errors on attempt to do it. I mean something like this:

classmethod DoSomethingInSYS() as %Status
{
 set sc=$$$OK
 try { 
   new $namespace
   set $namespace="%SYS" 
   // do something, e.g. config change
 } catch ex {
   // process the error
   set sc=ex.AsStatus()
 }
 return sc 
}

Ah, @Alexey Maslov, you mean if there will be an error this won't change the namespace back even with the "new $namespace" command?

It would change. I mean that try/catch is still needed to handle exceptions that can occur during namespace change or after the change, working in "%SYS" (mostly security violation errors). Otherwise the method can produce unsolicited exceptions.

if there will be an error this won't change the namespace back even with the "new $namespace" command

It would be still "%SYS" inside the `catch` block, so it's unsafe to call any code in its context. Even if you write something like this:

 ...
 try {
   new $namespace
   set $namespace="%SYS"
   ...
 } catch ex {   // process the error
   set sc=ex.AsStatus()
   do ..logErr(sc) // do some debug logging
 }
 return sc

and the ..logErr() call will be successful (generated .int code was not split into parts), the global where the log goes should be the same for all namespaces (e.g. mapped via %ALL pseudo-namespace). There are so many complications that it seems better to avoid any error processing inside the `catch` block above returning the error code. BTW, it sounds reasonable in any case, not only in this one associated with %SYS.