Question
· Aug 11, 2023

Trailing zero are truncated in %Set method of %DynamicObject

Hi Community,

Whenever I insert a decimal value with trailing zero(ex:12.0000) value in my JSON object dynamically through %Set method. It truncates the trailing zeros. However If I use literal constructors { } It working as expected.  So, In my case the JSON will be generated dynamically. I can't go with "Curly Bracket { } " and the JSON schema not string as well.
Is there any way to fix this?

    set json = { "decimal": 12.000}
    zw json
    set json1= ##Class(%DynamicObject).%New()
    do json1.%Set("decimal", 12.000) ; this is consider as string
    do json1.%Set("decimal1", $FN(12,,2), "number")	
    zw json1
    
    #;output
    json={"decimal":12.000}  ; <DYNAMIC OBJECT>
    json1={"decimal":12,"decimal1":12}  ; <DYNAMIC OBJECT>
Product version: IRIS 2023.1
$ZV: IRIS for Windows (x86-64) 2023.1
Discussion (2)2
Log in or sign up to continue

The numeric values inside a %DynamicObject can be a JSON number,  an ObjectScript Decimal Floating-Point number, an IEEE Binary Floating-Point number or an ObjectScript string containing the characters of an ObjectScript numeric literal.  The ObjectScript Decimal and the IEEE Binary numeric types do not keep track of trailing zeroes.  The JSON numbers do keep track of the trailing zero.  A JSON number or an ObjectScript string containing a numeric literal will loose their trailing zeroes as soon as an ObjectScript arithmetic expression uses those values as an operand.

Creating a %DynamicArray with the square-bracket syntax, [ ], or creating a %DynamicObject with the curly-bracket syntax, { }, will do parsing using JSON syntax which keeps the trailing zeroes.  However, if an ObjectScript expression is using the [ ] or { } syntax and an enclosed value is further enclosed inside round-bracket syntax then round brackets will enclose a single ObjectScript run-time expression which will be parsed using ObjectScript syntax rules.  (See json3 variable below for an example.)

If you evaluate a %DynamicObject element containing a JSON number with either ObjectScript property evaluation or with a simple ObjectScript %Get("propName") method evaluation then you get an ObjectScript Decimal value (or maybe an IEEE Binary value.)  E.g.:

USER>set json2 = { "decimal": 12.000, "decimal2":12.000E150}     

USER>zwrite json2                                                
json2={"decimal":12.000, "decimal2":12.000E150}  ; <DYNAMIC OBJECT>

USER>write json2.decimal,!,json2.%Get("decimal"),!,json2.decimal2
12
12
12000000000000000496000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Note that the JSON 12.000E150 was converted to the IEEE Binary value $DOUBLE(12.000E150) which is written containing the digits "496" as the 18th, 19th and 20th significant digits.  This occurs because of the rounding that occurs when doing the default conversions in both directions between binary floating-point values and decimal textual values.

[[ In case you want to see the fully accurate value of $DOUBLE(12.000E150), without any rounding modifications, the decimal value would be:
USER>write $FNUMBER(json2.decimal2, "G", 152)
12000000000000000496865878364855385636201248056368359870735338409167261627934342176354867336792577149743475436957677626049325994240678780913402110803968.0
which has 151significant decimal digits in its fully accurate representation in decimal. ]]

A more complex %Get method evaluation, %Get("decimal2", , "json") , will return a string containing the JSON syntax representation of the element.  E.g.:

USER>set json3 = { "decimal2":12.000E150, "OSnumber":(.12)}                                

USER>write json3.%Get("decimal2", , "json"),!,json3.OSnumber,!,json3.%Get("OSnumber", , "json")
12.000E150
.12
0.12

Note that .12 is an ObjectScript numeric value, while the strings 12.000E150 and 0.12 are syntactically legal JSON values.

It would be nice if the  %Set(key,value,type) method of the %DynamicObject class accepted "json" as a supported 'type' argument value, *BUT* it does not.  That would make it possible to add a JSON syntax numeric literal to an existing %DynamicObject using
    DO json3.%Set("decimal2", "12.000E150", "json")
Maybe someone should suggest such a feature extension to the %Set method.