Indirection Different In Terminal Than In Method
If I open a terminal and type the following commands, sc is an error:
set validator = "sc = ##class(%Library.Numeric).IsValid(""BLAH"")" set @validator write sc
At the end, when I write sc I get:
0 L'BLAH9 DOCXT010,#e^zIsValid+1^%Library.Numeric.1^1e^^^1
However, if I call the following class method using the arguments "%Library.Numeric" and "BLAH", sc is undefined
ClassMethod testvalidator(class As %String, value As %String) As %Status { set validator = "sc = ##class("_class_").IsValid("""_value_""")" write validator,! set @validator write sc,! quit sc }
When it tries to write sc, I get:
write sc,! ^ <UNDEFINED>zvalidator+4^DXT4.tagvalue.1 *sc
And I can't figure out what's making that different. Why would this behave differently in this method than doing the same thing line by line in the terminal?
Product version: Caché 2018.1
$ZV: Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2018.1.2 (Build 309U) Mon Mar 4 2019 15:07:46 EST
You have a problem with the scoping!
Indirection has a global scoping, you have to put things with indirection in a global scope:
Thank you, Julius! It was that, and my class wasn't ProcedureBlock.
All classes are ProcedureBlock by default, you need to manually set [Not ProcedureBlock] if you don't want to compile classes to Procedures. It's highly recommended to use ProcedureBlock though.
I was updating code someone else wrote a few years ago, and they had set [Not ProcedureBlock] on the class. I'm not sure why.
As @Sergei.Shutov pointed out, you can switch off the procdere block by a keyword for the whole class. Additionaly, you can switch on or off the procedure block keyword for a particular method too. In your case:
Use $CLASSMETHOD and you won't have such issues:
He (@David Hockenbroch) is playing with inderection, using $classmethod() instead of ##class(classname).methodname(...) does not solve the scoping problem:
ClassMethod testvalidator(class As %String, value As %String) As %Status { set validator = "sc = $classmethod(class, ""IsValid"", value)" write validator,! set @validator write sc,! quit sc }
The above method gives you the same <UNDEF> error because of non global scoping! By using indirection both variables (validator and sc) must have global scope.
Well in case of $classmethod you don't need to use an indirection at all to achieve the same result. I would avoid using indirection if at all possible.
@Sergei Shutov You missed the point.
validator
is typically stored as part of the individual data record to handle various types of checks within your class to provide the highest flexibility. Think of language or geographically related checking.
You can't bypass the challenge.
Neither by $classmetho() nor any code generator as this is all static code frozen and inflexible a runtime.
Creating a check routine by field or by record is not a realistic solution
Why?
A case where user must be able to:
Can be solved in many ways, without indirection (aka executing code stored as a string).
I usually provide a base class, which a user must extend and populate with his own methods. After that in the source app, just call SubclassOf Query from %Dictionary.ClassDefinition to get all implementation and show them to a user to pick from.
Works good enough.
The question was (see the original post), why does a command work in a terminal but not in a method. And, as you know, the answer lies in the scoping. I would say, he (@David Hockenbroch) tries to learn and understand the nature of indirection and is not working on a production grade problem.
But maybe I'm wrong... who knows.
Social networks
InterSystems resources
Log in or sign up
Log in or create a new account to continue
Log in or sign up
Log in or create a new account to continue
Log in or sign up
Log in or create a new account to continue