Feature request: get all properties available from a var

Hi,

while using the JSON class and with it the var class for the first time I was missing an option to get all properties possible for a particiular var to parse a json file with unknown content.

Maybe I overlooked something, but otherwise a I think a function like

StringArray var::getAllProperties()

that returns an array with all possible Identifiers that could be passed to getProperty would be very helpful.

A free function to do this is pretty simple:

static Array<Identifier> getAllPropertyNames (const var& v)
{
    Array<Identifier> names;
    
    if (auto* const obj = v.getDynamicObject())
    {
        auto& properties = obj->getProperties();

        for (const auto& property : properties)
            names.add (property.name);
    }
    
    return names;
}

Usage:

auto* const p = new DynamicObject();

p->setProperty ("name",      "Bob");
p->setProperty ("age",       40);
p->setProperty ("height",    1.7);

var v (p);

auto names = getAllPropertyNames (v);

for (const auto& name : names)
    Logger::writeToLog (name.toString());

Or, for your use-case you could just get the dynamic object, get its properties (a NamedValueSet) and just iterate over all the properties and their values.

1 Like

Have a look at DynamicObject.

if (auto* object = myVar.getDynamicObject()) {
    for (auto prop : object->getProperties())
        DBG ("Property: " << prop.name << " is: " << prop.value);
}
1 Like

Ok cool, thank you. I wouldn‘t have found out that by myself, mostly because there is no description on var::getDynamicObject in the documentation, but it works that way.

But I‘d also like to understand whats happening here, how DynamicObject and var are related. When setting a breakpoint to step into getDynamicObject, I see a dynamic_cast casting a var to a DynamicObject. Could someone explain why this works?

DynamicObject is a kind of ReferenceCountedObject and a var can hold any kind of ReferenceCountedObject. DynamicObject holds a set of name-value pairs (in a NamedValueSet) where the names are Identifier objects and the values are var objects. This is just a special case of ReferenceCountedObject that var knows about in order to be able to represent the JSON-like data. The dynamic_cast is required because var stores the objects as a ReferenceCountedObject* and it may be storing some other kind of ReferenceCountedObject (but this would only be if you were using var for purposes other than serialising and deserialising JSON).

I don’t …

?

There are some dynamic_casts but I think you might be misreading the code?

3 Likes

The var implements the assignment operator for each type it can represent, e.g. this one: var::operator=()

If the lvalue of the equation has already a type, the compiler picks the right override for you. If it is ambiguous, the compile will fail, and you have to do an explicit dynamic_cast<type> to force the compiler to pick that override. And if you use the auto keyword, the compiler cannot know, hence you need to use the explicit cast.

Like @martinrobinson-2 pointed out, getDynamicObject() is just a shorthand, that checks, if the wrapped object is a DynamicObject (by trying the dynamic_cast). It can return a nullptr, because the var might not be an object at all, or any other descendant of ReferenceCountedObject.

2 Likes

Yes I was misreading code :wink:
After reading your explanation and then reading the code again, I now think I got it!