(Suggestion) adding a bit of reflection to JUCE


#1

I’ve made a class, which is called RestorableObject, which was really really helpful for me, to do things faster, and maybe something like this would nice addition for Juce.
The idea is that every-Data Object/Container should be derived from RestoreableObject.
Then every RestoreableObject provides additional functions like createXMLString, createXML, saveToFile, restoreFromFile, generate Hash etc.
Internally RestoreableObject works with ValueTree.
But there is a reason why the classes not work directly with ValueTree: speed (if you do dsp-stuff you wouldn’t use a valueTree for that), typesafity, stability, simplicity (its easier to use local variables instead to do this with a value-tree).

Example you want to store this data-structure:

class MyPoint { public: int x,y }

Now adding RestoreableObject, which has three virtual functions which needed to be overwritten.
getIdentifier(),doSaveItems(),doRestoreItems()

[code]class MyPoint : public RestoreableObject
{
public:
int x,y;

Identifier getIdentifier()
{
	return "MyPoint"
};

void doSaveItems()
{
	saveItem("x",x);
	saveItem("y",y);
};

void doRestoreItems()
{
	x=restoreItem("x", defaultValue);
	y=restoreItem("y", defaultValue);
};

}[/code]

If you have object which is a line, it uses two points

[code]class MyLine : public RestoreableObject
{
public:
MyPoint p1,p2;

Identifier getIdentifier()
{
	return "MyLine"
};

void doSaveItems()
{
	saveItemObject("p1",p1);
	saveItemObject("p2",p2);
};

void doSaveItems()
{
	restoreItemObject("p1",p1);
	restoreItemObject("p2",p2);
};

void paintLine(Graphics &g);

}[/code]

If you have document to store, which stores a various number of lines, you can do that

[code]
class MyProject : public RestoreableObject
{
public:
OwnedArray lines;

Identifier getIdentifier()
{
	return "MyProject"
};

void doSaveItems()
{
	for (int i=0; i<lines.size; i++)
		saveItemArrayMember("lines",i,lines[i]);
};

void doSaveItems()
{
	while (restoreItemArrayMember("lines",lines))
	{
	};
};

}[/code]

Then if you want to save the whole document, it automatically generates a XML File.

then the file content is something like this

<Project> <Lines> <Member> <MyLine> <MyPoint x="10" y="20"> <MyPoint x="30" y="40"> </MyLine> </Member> <Member> <MyLine> <MyPoint x="100" y="200"> <MyPoint x="300" y="400"> </MyLine> </Member> </Lines> </Project>


#2

Well, I do similar things all the time, with methods that look like this:

[code]void restoreState (const ValueTree& savedState)
{
x = savedState [“x”];
}

const ValueTree saveState()
{
ValueTree state;
state.setProperty (“x”, x);
return state;
}[/code]

but I’ve never found a situation where having a base class would have produced a better solution…?


#3

ehm, yes you are 100% right with that, if you only use it for restore/save purposes

But somehow I think its nice to have a equal interface for all data-storing objects, or rather all data-objects have the same base-class, like the Component-class is the base of all GUI-Classes

  • if you have a Model/View architecture, you can make a base view-Component, with interacts with Model(RestoreableObject) and have special methods to get the data (lock-free interprocess communication, etc.),

  • you can make a array of different classes and can do something like getIdentifer() / hasMember(“x”), like in a script language with reflection

  • use the same mechanism for saving Arrays with various sizes of RestoreableObjects

  • if every Class like Rectangle, Range, BigInteger, Colour and also bigger Objects like AudioDeviceManager, Image etc. have the same interface, it would speed up developing time a lot, you only have to saveObject(myRectangle), instead of thinking about what’s the best practise.


#4

ok, a alternative would be to extend the VariantType with all this different classes, but i think how a method should be stored should be described in its own class


#5
  • and you could do nice debugging utilities which are displaying all data-structures in a tree-view.

#6
  • or just extend the variant-type so it can also be a restoreableObject like other primitives like int, bool etc.

#7

No, you’re getting carried away with base classes.

Sure, you could say that it’d be a good thing if all the library classes implemented a common pair of load/save functions - but they could do that without needing to inherit from a common base class. The base class adds nothing of value that I can think of. When an object is serialising its members, it already knows their types, it doesn’t need to refer to them all by an abstract base class.

(Not to mention that it’d be impossible to add a virtual base-class to any of the copy-by-value types like Rectangle, BigInteger, etc…)