📜 ⬆️ ⬇️

New dynamic objects and JSON support in InterSystems Caché

Dynamism of A Dog on a Leash (1912) Giacomo Balla In general, in InterSystems Caché, both dynamic objects and JSON support have been around for quite some time, but in version 2016.1 they were rethought, and the implementation code was transferred from the COS level to the kernel / C level, which made it possible to significantly improve performance in these areas. That is new and how to go (as well as how to maintain compatibility with previous versions) I will discuss in this article.

JSON features


And start with an example. Now this syntax works and this is the biggest innovation in COS syntax:

Set object = { "property": "val", "property2": 2, "property3": null } Set array = [ 1, 2, "string", true ] 

As you can see, JSON is now a full part of COS. What happens with such an assignment? The object object becomes an instance of the class % Library.Object , and array is an instance of the class % Library.Array . They are both dynamic objects.

Dynamic objects


Dynamic objects in Cache were in the past - in the form of the % ZEN.proxyObject class, but now the code has been moved to the core, due to which a significant increase in speed has been achieved. All classes of dynamic objects are inherited from % Library.AbstractObject , which provides the following functionality:
')

Transition from% ZEN.proxyObject


So, do you want to move from % ZEN.proxyObject and various heirs of % Collection.AbstractIterator to use the heirs of% Library.AbstractObject? This is easy and there are several methods:


The use of the first method is obvious in general, but we’ll dwell on the other two in more detail.

Macros


Sample code for a set of macros that, depending on the availability of% Library.AbstractObject, work with either the new or the old class of dynamic objects.

Macros
#if $$$ comClassDefined ( "% Library.AbstractObject" )
#define NewDynObj ## class (% Object).% New ()
#define NewDynDTList ## class (% Array).% New ()
#define NewDynObjList $$$ NewDynDTList
#define Insert (% obj,% element) do% obj. $ push (% element)
#define DynObjToJSON (% obj) w% obj. $ toJSON ()
#define ListToJSON (% obj) $$$ DynObjToJSON ( % obj )
#define ListSize (% obj) % obj. $ size ()
#define ListGet (% obj,% i) % obj. $ get (% i-1)
#else
#define NewDynObj ## class (% ZEN.proxyObject).% New ()
#define NewDynDTList ## class (% ListOfDataTypes).% New ()
#define NewDynObjList ## class (% ListOfObjects).% New ()
#define Insert (% obj,% element) do% obj.Insert (% element)
#define DynObjToJSON (% obj) do% obj.% ToJSON ()
#define ListToJSON (% obj) do ## class (% ZEN.Auxiliary.jsonProvider).% ObjectToJSON (% obj)
#define ListSize (% obj) % obj.Count ()
#define ListGet (% obj,% i) % obj.GetAt (% i)
#endif
#define IsNewJSON ## Expression ($$$ comClassDefined ( "% Library.AbstractObject" ) )

Using
Here is the code:
Set obj = $$$ NewDynObj
Set obj . prop = "val"
$$$ DynObjToJSON ( obj )

Set dtList = $$$ NewDynDTList
Set a = 1
$$$ Insert ( dtList , a )
$$$ Insert ( dtList , "a" )
$$$ ListToJSON ( dtList )

In Cache version 2016.1+, the following code will be compiled into int:
set obj = ## class ( % Library.Object ). % New ()
set obj . prop = "val"
w obj . $ toJSON ()
set dtList = ## class ( % Library.Array ). % New ()
set a = 1
do dtList . $ push ( a )
do dtList . $ push ( "a" )
w dtList . $ toJSON ()

And in previous versions in:
set obj = ## class ( % ZEN.proxyObject ). % New ()
set obj . prop = "val"
do obj . % ToJSON ()
set dtList = ## class ( % Library.ListOfDataTypes ). % New ()
set a = 1
do dtList . Insert ( a )
do dtList . Insert ( "a" )
do ## class ( % ZEN.Auxiliary.jsonProvider ). % ObjectToJSON ( dtList )


Class abstraction


An alternative is to create a class that abstracts the dynamic object used, for example:

Class Utils.DynamicObject
Class Utils.DynamicObject Extends% RegisteredObject
{
/// Property that stores a real dynamic object
Property obj;
Method % OnNew () As% Status
{
#if $$$ comClassDefined ( "% Library.AbstractObject" )
Set .. obj = ## class ( % Object ). % New ()
#else
Set .. obj = ## class ( % ZEN.proxyObject ). % New ()
#endif
Quit $$$ OK
}
/// Get dynamic properties
Method % DispatchGetProperty ( pProperty As% String ) [ Final ]
{
Quit .. obj . % DispatchGetProperty ( pProperty )
}
/// Setting dynamic properties
Method % DispatchSetProperty ( pProperty As% String , pValue As% String ) [ Final ]
{
Do .. obj . % DispatchSetProperty ( pProperty , pValue )
}
/// Convert to JSON
Method ToJSON () [ Final ]
{
#if $$$ comClassDefined ( "% Library.AbstractObject" )
Write .. obj . $ toJSON ()
#else
Do .. obj . % ToJSON ()
#endif
}
}

The use is completely analogous to the usual class:

Set obj = ## class ( Utils.DynamicObject ). % New ()
Set obj . prop = "val"
Do obj . ToJSON ()

What to choose


You decide. The variant with the class looks more familiar; the variant with macros will be somewhat faster due to the absence of intermediate calls. For the MDX2JSON project , I chose the macro option. The transition was quick and painless .

JSON performance


JSON generation speed increased by an order. In the project MDX2JSON there are tests for generating JSON speed . Download and make sure!

findings


New dynamic objects and improvements in JSON support allow you to speed up your applications.

Links


» Documentation
» Community.intersystems.com article on JSON
» Class Utils.DynamicObject

Source: https://habr.com/ru/post/272059/


All Articles