Building a dynamic Object: how can I use variables?
Hi developers!
In a method I need to return a result as a dynamic object aka JSON Object. And here is my logic:
Classmethod Planets() as%DynamicObject {
set val1="Jupiter"
set val2="Mars"// this doesn't work! cannot compile
return {"value1":val1, "value2":val2}
}So I need to do the following:
Classmethod Planets() as%DynamicObject {
set val1="Jupiter"
set val2="Mars"
set result={}
set result.value1=val1
set result.value2=val2
return result
}The second case works. Maybe I'm preparing the Dynamic Object in the wrong way? Can we just use variables inside JSON? Or should I create an object and initialize it manually?
Could you share your experience with it, please?
Comments
In InterSystems IRIS, the construction and manipulation of dynamic objects like JSON objects can be achieved in various ways using the %DynamicObject class.
Issue with Direct JSON Syntax Incorporating Variables
When attempting return {"value1":val1, "value2":val2}, you are utilizing JSON literal syntax directly with variables. This won't work because ObjectScript does not dynamically interpret variables within such JSON literals. Instead, it requires an explicit declaration or assignment for each field.
Correct Dynamic Object Construction
For initializing dynamic objects with variables, you need to use step-by-step assignment. Below is an example:
ClassMethod Planets() As %DynamicObject
{
Set val1 = "Jupiter"
Set val2 = "Mars"
Set result = {}
Set result.value1 = val1
Set result.value2 = val2
Return result
}
This approach builds the dynamic object incrementally and ensures compatibility.
Alternative Using %DynamicObject Methods
The %DynamicObject class provides built-in methods like Set to explicitly set fields in the object. This method allows specifying both the key and value dynamically:
Set json = {}
Do json.%Set("value1", val1)
Do json.%Set("value2", val2)
Return json
Both approaches work because the dynamic object understands individual assignments and ensures proper serialization to JSON format. This clarifies that within ObjectScript, variables must be individually assigned to object properties rather than being interpreted directly in literal JSON syntax [1].
Sources:
Put your variables into parentheses, i.e.
return {"value1":(val1), "value2":(val2)}Apparently, someone at ISC got a huge discount on parentheses (the easy solution) instead of requiring that these damned parentheses only be used when the assignment is an expression (and the user-friendly version would be: only when the expression contains the [ or ] operators!).
justmy2cents
Sounds like a great idea of enhancement, thanks for sharing, @Julius Kavay !
I'm not sure it's a great idea, think about this code:
Set true="it's a good idea"
Set false="it's a bad idea"
Set dObj={"idea":true, "doubt":false}
😉
Set dObj={"idea":(true), "doubt":(false)}
Do you think this is better? ;)
Actually, my another proposal is to have true and false as part of the language, where true=1 and false 0 or similar for booleans.
Actually, my another proposal is to have true and false as part of the language, where true=1 and false 0 or similar for booleans.Isn't that the case now?
set true="1",
false=0,
j={"a":true,"b":false,"c":(true),"d":(false)}
</FONT><FONT COLOR="#0000ff">set </FONT><FONT COLOR="#808000">iter </FONT><FONT COLOR="#000000">= </FONT><FONT COLOR="#808000">j</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">%GetIterator</FONT><FONT COLOR="#000000">()
</FONT><FONT COLOR="#0000ff">while </FONT><FONT COLOR="#808000">iter</FONT><FONT COLOR="#000000">.</FONT><FONT COLOR="#0000ff">%GetNext</FONT><FONT COLOR="#000000">(.</FONT><FONT COLOR="#808000">key</FONT><FONT COLOR="#000000">, .</FONT><FONT COLOR="#808000">value</FONT><FONT COLOR="#000000">, .</FONT><FONT COLOR="#808000">type </FONT><FONT COLOR="#000000">) </FONT><FONT COLOR="#800080">{
</FONT><FONT COLOR="#0000ff">write </FONT><FONT COLOR="#008000">"key = "</FONT><FONT COLOR="#000000"></FONT><FONT COLOR="#808000">key</FONT><FONT COLOR="#000000"></FONT><FONT COLOR="#008000">", value = "</FONT><FONT COLOR="#000000"></FONT><FONT COLOR="#808000">value</FONT><FONT COLOR="#000000"></FONT><FONT COLOR="#008000">", type = "</FONT><FONT COLOR="#000000">_</FONT><FONT COLOR="#808000">type</FONT><FONT COLOR="#000000">,!
</FONT><FONT COLOR="#800080">}</FONT>
Output:
key = a, value = 1, type = boolean
key = b, value = 0, type = boolean
key = c, value = 1, type = string
key = d, value = 0, type = number
Bravo, @Vitaliy Serdtsev !
But I cannot set true and false in advance before any interaction with JSON/%Dynamic Object/%Dynamic Array.
Or can? )
Same thing, just different:
set true="1",
false=0,
j={}do j.%Set("a",1,"boolean")
do j.%Set("b",0,"boolean")
set j.c=true
set j.d=false
set iter = j.%GetIterator()
while iter.%GetNext(.key, .value, .type ) {
write "key = "_key_", value = "_value_", type = "_type,!
}
Output:
key = a, value = 1, type = boolean
key = b, value = 0, type = boolean
key = c, value = 1, type = string
key = d, value = 0, type = number
This all is very helpful for understanding how to cope with JSON in IRIS. thanks a lot @Vitaliy Serdtsev
I fail to see the problem:
- true:==> $$$OK
- false:==> $$$NOTOK
do I miss siómething ?
Or is the intention to mix ISOS with JavaScript ???
For JSON, it's essential to support true and false, as it is expected by the majority of Web and mobile UI frameworks. So IRIS can recieve a lot of JSON llike:
{"p1":true,"p2":false}And should be able easily response with;
{"p1":false,"p2":true}, and not:
{"p1":$$$NO,"p2":$$$YES}That is already true as seen in Vitaliy's comment above. Personally, I prefer to use {}.%New() and then use the %Set method because you can provide a third argument to explicitly say whether the value you are adding is a number, string, boolean, stream, etc. to eliminate any ambiguity. We have alphanumeric fields that should be considered strings, but if they happen to be all numbers, they are incorrectly inserted as numeric values in JSON if we don't specify.
Great point, @David Hockenbroch about JSON types, thank you!
bye, bye clear rules
👿
>>>> on the way to embedded obfuscation and confusion
Nota Bene: I adopted Robert Cemper's suggestion ISOS, as shorthand for InterSystemsObjectScript
According to my opinion, your ISOS example (and the way, how JSON was implemented by ISC), is a mix of a little bit ISOS and a little bit JSON.
Why? Take this example:
set myObject = { "p1":"abcd", "p2":true, "p3":value, "p4":(sum+2) }
<- ObjScript -><-------------------- JSON------------------------->The example starts with an ISOS syntax and proceeds with JSON syntax.
Unfortunately, the last two properties (p3, p4) are invalid JSON properties.
So we have a perfect mixture!
Remember, ISOS does not have literal constants (like true, false and null) and JSON neither has variables (like value) nor expressions, like (sum+2).
Since the current implementation has been in use for several years, a reimplementation is (probably) impossible. With other words, the bottom line is, unwillingly, but we have to accept the status quo...
@Julius Kavay hits the point:
true of false as system constants is breaking the rules and
the long-practiced idea and principles behind ISOS and before
( @Joel Solon : isn't it ?)
You may ask for $TRUE or $FALSE system constant / variable
Until this, you are free to define your own $ZTRUE or $ZFALSE using
%ZLANGV00.mac to extend the language.
It's all ready for use to extend the language according to your needs and taste
On the side of javascript this will do the job.
str={test1:'true',test0:'false'}
Object { test1: "true", test0: "false" }
str1 = JSON.stringify(str)
'{"test1":"true","test0":"false"}'
str1 = str1.replaceAll('"true"','true').replaceAll('"false"','false')
'{"test1":true, "test0":false}'
str = JSON.parse(str1)
Object { test1: true, test0: false }So i have to do it for python also. True and False replace by true and false.
Thank you, @Julius Kavay !