Namespace != object
-
-- yep and as I suspect:
Engine.dumpAsJSON(myObj1, "my.json"); .. .. .. var myObj2 = Engine.loadFromJSON("my.json");
leaves myObj2 = undefined
even tho my.json looks like this:
{ "soundName": "S", "group": 17, "planSet": [ { "soundName": "B", "group": 2, "preWait": { "minVal": 4, "currentVal": 10, "maxVal": 25 }, "postWait": { "minVal": 1, "currentVal": 1, "maxVal": 1 }, "aCurve": 0.5, "aTime": 0, "aLevel": 0, "hTime": 100, "dCurve": 0.43, "dTime": 50, "sLevel": 100, "rTime": 0 } ], "targetPlan": function (target){ for (idx= 0;idx<this.planSet.length;idx++) { if (this.planSet[idx].soundName == target) return this.planSet[idx]; }; } }
-
@Lindon - yep loadFromJSON wont load object definitions...so serialisation will be a problem...
-
@Lindon Does it work if you save the object definition as a string and use the
exec
command? -
@d-healey dunno - I will try --- tomorrow...
err.. looking up exec gives me this:https://www.w3schools.com/jsref/jsref_regexp_exec.asp
--which is seraching in strings
-
@Lindon I have a video about the
exec
command waiting to be edited, basically it executes a string as if it was a line of code, but it's a bit finicky and I haven't tried it with functions.So you could do something like this.
var myCommand = "Console.print('HELLO WORLD');"; exec(myCommand);
-
@Lindon said in Namespace != object:
garbage collection
Don't worry about garbage collection. This only gets a problem if you have cyclic references, which are pretty easy to avoid:
var x = {}; var y = {}; x.child = y; y.child = x; // <= Baam, leak
A tree normally doesn't have references from the child back to the parent, so unless you specifically want to shoot yourself in the foot, it doesn't matter.
BTW, there's a cyclic reference checker built into HISE, that would detect the cycle in the (trivial) example above and spit out an error.
-
Oh and to your original question:
Back in the C days when there was no OOP built into the language, people were using POD structs (= plain old data) along with functions that take a reference to that object and manipulate it. This is pretty similar to what I would suggest trying out in HiseScript.
So instead of a "real" OOP approach where you create objects that contain methods that operate on themselves you'll write "global" functions (or tuck them into a namespace for increased code clarity), then pass any object to it as parameter:
namespace MyObjectFunctions { inline function initObject(obj) { obj.myVariable = 2; } inline function printVariable(obj) { Console.print(obj.myVariable); } } const var objList = []; for(i = 0; i < 1200; i++) { var obj = {}; MyObjectFunctions.initObject(obj); objList.push(obj); } for(o in objList) MyObjectFunctions.printVariable(o);
This is equivalent to the "correct" OOP way (I'm using C++ here, but you'll get the point)
class MyFunctionObject { void init() { myVariable = 2; } void printVariable() { Console.print(myVariable); } int myVariable; }; MyFunctionObject objList[1200]; for(int i = 0; i < 1200; i++) objList[i].init(); for(auto& o: objList) o.printVariable();
As you can see, there is not much overhead compared to Javascript, but this separation between data and logic keeps things tidy - you can serialize the data using JSON etc.
-
@Christoph-Hart yeah this is sort of what I feared - now I have a lot of additional code to write to serialise and unseralise these arrays....when (as you say) I'm using simple pretty strict tree structures for my object collection.... so no garbage collection leaks -- it just seems a shame the JSON dump and load commands wont dump AND load objects - pretty ironic given the JSON acronym...
-
@d-healey said in Namespace != object:
@Lindon I have a video about the
exec
command waiting to be edited, basically it executes a string as if it was a line of code, but it's a bit finicky and I haven't tried it with functions.So you could do something like this.
var myCommand = "Console.print('HELLO WORLD');"; exec(myCommand);
Sadly:
myTester = exec(Engine.loadFromJSON("test2.js")); var myCommand = "var mTestyNew = {'SoundName':'B','group':2};"; exec(myCommand);
where test2.js contains:
var myTestFile2 = { "soundName": "S", "group": 17, "planSet": [ { "soundName": "B", "group": 2, "preWait": { "minVal": 4, "currentVal": 10, "maxVal": 25 }, "postWait": { "minVal": 1, "currentVal": 1, "maxVal": 1 }, "aCurve": 0.5, "aTime": 0, "aLevel": 0, "hTime": 100, "dCurve": 0.43, "dTime": 50, "sLevel": 100, "rTime": 0 } ], "targetPlan": function (target){ for (idx= 0;idx<this.planSet.length;idx++) { if (this.planSet[idx].soundName == target) return this.planSet[idx]; }; } };
Results in an object called mTestyNew (so that works) and myTester = undefined,so the LoadFromJSON fails...
Even if it worked I have no idea how I would save an object in a way that would "exec"
It looks like what Im asking for is
JSON.stringify() <---which seems to be present, so I can turn an object into a string
and
JSON.parse() <-- which is missing so I cant turn it back into an object
however this works:var TestOutString = JSON.stringify(myObject); var TestNewObj = eval(TestOutString);
So all I need now is a way to save this string.....
-
But isn't the only problem the fact that you put a function into the object? JSON is a data format so you can't put logic in it...
-
Oh, and this:
var myTestFile2 = { "soundName": "S", "group": 17, "planSet": [ { "soundName": "B", "group": 2, "preWait": { "minVal": 4, "currentVal": 10, "maxVal": 25 }, "postWait": { "minVal": 1, "currentVal": 1, "maxVal": 1 }, "aCurve": 0.5, "aTime": 0, "aLevel": 0, "hTime": 100, "dCurve": 0.43, "dTime": 50, "sLevel": 100, "rTime": 0 } ], "targetPlan": function (target){ for (idx= 0;idx<this.planSet.length;idx++) { if (this.planSet[idx].soundName == target) return this.planSet[idx]; }; } };
is Javascript, not JSON. You need to remove the
var myTestFile2 =
at the beginning so it's just the object declaration... -
@Christoph-Hart yes - both these post pretty much sum up the problem:
var myTester = eval(Engine.loadFromJSON("test2.js"));
where test2.js =
{ "soundName": "S", "group": 17, "planSet": [ { "soundName": "B", "group": 2, "preWait": { "minVal": 4, "currentVal": 10, "maxVal": 25 }, "postWait": { "minVal": 1, "currentVal": 1, "maxVal": 1 }, "aCurve": 0.5, "aTime": 0, "aLevel": 0, "hTime": 100, "dCurve": 0.43, "dTime": 50, "sLevel": 100, "rTime": 0 } ] };
results in myTester =
{ "dump": Method, "clone": Method }
So we see LoadFromJSON will not load any kind of object......unless I'm doing something silly(quite possible)
and
"But isn't the only problem the fact that you put a function into the object? JSON is a data format so you can't put logic in it..."So yes JSON definitely ISNT working properly, and even if it was then it wouldnt do whats needed here. However there is a way to "unserialise" a string into an object WITH its functions, as well as a way to serialise an object WITH its functions
Just theres no way to save a string in HISE....
Hold on I WAS doing something silly...that eval is not required....stiull I'd like a way to serialise and unseralise WITH functions and we seem to be most of the way there... 'cept for save and load string...
-
I can't speak about
eval
because this is an easter egg that David found by accident :)But the normal JSON dump method works as it should:
var x = { "obj1": [12, 15, 16], "p2": ["alpha"] }; Engine.dumpAsJSON(x, "myTest"); var y = Engine.loadFromJSON("myTest");
Look at
y
in the object viewer (right click on the row in the scriptwatch table). You'll see that it perfectly clones the x object via the external file. -
@Christoph-Hart yeah _ I think I got there before you - me being silly - it works for objects as long as they are just data, so not really objects just structs really... so I guess I'm back to having some external function for every method I want on an object I would like to "save" - its messy. Back to looking at namespaces again...
-
But why is that messy? You most definitely don't want logic code in a user readable JSON dump? And if you rewrite the function
inline function saveTargetPlan(obj, target) { for (p in obj.planSet) // changed it to a range-based loop for you ... { if (p.soundName == target) return p; } }
and put it in a separate file with proper namespacing, I don't see how it can be more messy than the other solution...
-
@Christoph-Hart well you're going to have to excuse me I'm an old SmallTalk programmer - encapsulation is nearly everything...