Jump to content


Photo

ToJson / FromJson


  • Please log in to reply
9 replies to this topic

#1 Robyn

Robyn

    Member

  • Members
  • PipPip
  • 35 posts

Posted 25 June 2012 - 05:33 PM

I have returned to this to pick up using the concepts of class to save globals to disk frequently. When I search forums for 'class', 'OOP, or 'object' I don't get much help on class. I was hoping there would be an article just explaining it. However since I have done OOP in other languages that is OK for me, but some sort of overview would be good. The magic ingredient which I can find nothing on apart from the fact that I have tried it and it works is this function toJson() and fromJson(). Is there any documentation on that. You mention in one of the posts that using (1) packs in a different way, are there other options, what does it actually do. I do have it working but would like to know what I have done. Thanks

#2 AzeoTech

AzeoTech

    Guru

  • Administrators
  • PipPipPipPipPip
  • 4608 posts

Posted 26 June 2012 - 11:30 PM

I guess you needed to search for "object oriented". Here's the post you are looking for:

http://www.azeotech....h__1#entry12804

However, that link doesn't talk about fromJson() or toJson() because they are newer features, so I'll summarize here, with the assumption that you understand what json is and if not, you can search the web since its almost as common as XML.

If you have an object with member variables, you can create a string that describes the contents of those member variables by calling its toJson() function. All user objects have one. The result is a string in json format that holds all the values of all the member variables. It also includes a few extra fields that describe the class name. As you noticed, you can pass 1 to it and it will add CRLF's to the output to make it more readable, but this makes for a bigger and slower to parse string. This string can be stored in another variable or persisted to a file. By default, toJson() will do all the member variables, but you can tell DF not to do certain variables by adding the word "transient" into the variable declaration, so instead of:

local x

you'd do:

local transient x

You'd do this with variables that are important to the class while running, but not to the persistence of the class.

Note that toJson() will automatically call toJson() on member variables that are objects, as well as properly handle arrays, so you can store complex structures with a single function call.

Now the fromJson() function takes one of those strings you created with ToJson() and recreates the object. There are two versions of this function. There is a global fromJson() function, which, provided all the classes referenced by the string you pass to it have been defined, will create all the appropriate objects and populate their member variables from the string. There is also a member function fromJson() for any object which basically does the same thing, except that you provide the starting point object. This would be used if you wanted to populate an existing object without creating a new one.

There are two rather useful uses for these functions, and perhaps you will come up with more:

1) persisting objects and complex object trees: you can simply call toJson() on the top object, write the resulting string to disk, and then to recreate the object tree, read the string from disk and call fromJson() with it. In my opinion, this is the future way to store customer specified settings rather than using registry variables or csv files. You can create an object that holds all your settings that your customer might change, and then easily persist that to disk and restore it on restart

2) object copy: doing x = y when y is an object makes x hold a reference to the same object as y. This means x and y point to the same thing. There is no built in way to do an object copy, i.e. making x have a copy of y, but not the exact same object so a change in the object y would not affect object x. This is actually true of many languages, certainly C++. However, you can copy objects in DAQFactory by doing toJson() on the source, and then fromJson() on the destination. This won't copy transient variables (which presumably shouldn't be copied), but it will copy everything else, including nested objects.

#3 Robyn

Robyn

    Member

  • Members
  • PipPip
  • 35 posts

Posted 26 June 2012 - 11:56 PM

Thanks for that, I was not aware of the Json property being so common and have not come across it before. I will chase up more information on it but what you have given here is sufficient for me to press on with.

#4 Robyn

Robyn

    Member

  • Members
  • PipPip
  • 35 posts

Posted 27 June 2012 - 02:24 AM

Just one farther question with Json. I started using a class and Json as you describe to save variables for persistency. I started to save some multidimensional arrays ie MyArray[6][10] and I don't think old Jason is handling that correctly. Does it only handle single dimensional arrays ie MyOtherArray[6]?

#5 Robyn

Robyn

    Member

  • Members
  • PipPip
  • 35 posts

Posted 27 June 2012 - 03:00 AM

Re my last posting, I have made up this test sequence

class KKK
// these globals are saved to disk and restored on restart
local MyArray = {{1,2,3,4,5,6,7,8,9,10},{7,2,1,3,4,5,3,4,3,2}}
local a=1
local b=2
local c=3
endclass

global k = new(KKK)

private ihandle
private string strJ

strJ = k.toJson()
// save the globals to disk in case of restart etc
ihandle = File.Open("C:\DAQFactory\persist.txt",0,1,0,0)
File.Write(ihandle,strJ)
File.Close(ihandle)


// get the globals back from disk
ihandle = File.Open("C:\DAQFactory\persist.txt",1,0,0,0)
strJ = File.Read(ihandle,File.GetLength(ihandle))
File.Close(ihandle)
k = fromJson(strJ)


// now do some mods
k.MyArray[0][2] = 11
k.MyArray[1][3] = 44


strJ = k.toJson()
// save the globals to disk in case of restart etc
ihandle = File.Open("C:\DAQFactory\persist.txt",0,1,0,0)
File.Write(ihandle,strJ)
File.Close(ihandle)

// get the globals back from disk
ihandle = File.Open("C:\DAQFactory\persist.txt",1,0,0,0)
strJ = File.Read(ihandle,File.GetLength(ihandle))
File.Close(ihandle)
k = fromJson(strJ)
c = 4

It certainly does not preserve the values or structure of MyArray as it goes. Have I done something wrong here or is the problem that it does not handle the multi dimensional array?
Thanks
Robyn

#6 AzeoTech

AzeoTech

    Guru

  • Administrators
  • PipPipPipPipPip
  • 4608 posts

Posted 27 June 2012 - 10:39 AM

Yeah, I'm going to say it probably doesn't work with multidimensional arrays. Technically, json doesn't support it either, but instead supports arrays of arrays and that's actually about what you'd have to do, though probably as an array of objects which are simply arrays. You lose a lot of the convenience of multidimensional arrays though. What is the use of these?

#7 Robyn

Robyn

    Member

  • Members
  • PipPip
  • 35 posts

Posted 27 June 2012 - 03:15 PM

One case I have is where multiple pumps are irrigating multiple blocks of crop. I was keeping the run times in an array WateringTime[Pump Number][Block Number]
But thanks for your clarification, I will probably copy each pump to a single dimensional array before saving it. Just an extra step.
Thanks

#8 AzeoTech

AzeoTech

    Guru

  • Administrators
  • PipPipPipPipPip
  • 4608 posts

Posted 27 June 2012 - 09:18 PM

Consider making a crop block and object, then each pump an object as well that contains an array of crop blocks it feeds. This would also allow you to have different #'s of crop blocks for each pump.

#9 SteveMyres

SteveMyres

    Advanced Member

  • Members
  • PipPipPip
  • 361 posts
  • Gender:Male
  • Location:Phoenix Area

Posted 07 January 2014 - 07:49 PM

How would you go about having a pump object with a variable number of block objects?  Have a base pump class and derive from that a pump class with each unique block count?  What would be the advantage?

 

Also, how can object-oriented languages like C++ NOT have a built in object copying function??  Doesn't that kind of half break the entire concept?



#10 AzeoTech

AzeoTech

    Guru

  • Administrators
  • PipPipPipPipPip
  • 4608 posts

Posted 07 January 2014 - 11:29 PM

I'm not quite sure exactly what the application is.  So, each pump can irrigate multiple blocks?  But can more than one pump irrigate the same block?  I would probably make a block class and a pump class, then instantiate an object for each pump and one for each block.  Each block would hold a reference to the pump that irrigates it, and you'd probably have an array of pumps as well.  Remember more than one thing can reference an object.

 

As for why there is no built in copy function in object oriented languages: 

1) many objects have lots of internal variables that are related to the state of the object and should not be copied.  The compiler can't tell which are which.  DAQFactory adds a "transient" modifier to local variables to mark them as such, which just makes it so those locals are excluded from the toJson() function

2) many member variables are connected to other things.  For example, if you had an object for a serial port, and a member variable for the baud rate, the object probably will want to reinitialize the port whenever the baud rate is changed.  A simple copy feature wouldn't know to do this.  Likewise, it is hard to know exactly when any particular member variable should be copied during the initialization period.

 

So, most OO languages simply make you create your own copy function.  C++ has something called a copy constructor, which allows you to do things like x = y where both are objects, but you still have to write the code to actually copy the member variables.