Being compatible with the dictionary passing system (dict object)

Luigi Castelli's icon

Hi there,

I am working on an external that wants to be compatible with the dict family of objects.
To achive that, I fill a dictionary with the object's attributes, then register the dictionary and send it out an outlet. Finally the dictionary is unregistered and freed.
My doubts arise because the dictionary is freed right after being sent out the outlet, and therefore any reference or delayed use of it will result in pointing to bogus memory. However the code seems to work. At least if I pass my dictionary to a dict object. This is because the dict object clones any dictionary received in its inlet right away, and thanks to Max stack-based execution model, the outlet-sending function does not return until all computation below the outlet has completed. Therefore, my dictionary is always freed after it is cloned.

My question is: it safe to rely on this property?
Are there gonna be scenarios where the above no longer holds true and Max will unforgivingly crash?

Here is the code in question:

t_dictionary *d = NULL;

d = dictionary_from_object_attributes(x);
if (d) {
    t_atom argv[1];

    d = dictobj_register(d, &x->uniqueid);

    atom_setsym(argv, dictobj_namefromptr(d));
    object_obex_dumpout(x, gensym("dictionary"), 1, argv);

    object_free(d);  // will call dictobj_unregister()
}

Thanks a lot for any advice.

- Luigi

Timothy Place's icon

Hi Luigi,

It sounds like you've grok'd the way Max's dictionaries work completely correctly.

That means you are correct that if, for example, you dictionary message is passed through a qlim or deferlow object that there will no longer be a dictionary bound to the name with which your dictionary was registered. So what will happen?

The object receiving the dictionary, assuming it is written correctly, will call a function like dictobj_findregistered_retain(), which will simply return an error because there is no dictionary associated with the symbol. So assuming the external receiving the dictionary is written correctly and properly handles the error then there should be no concern about crashing.

Hope this helps,
Tim

Luigi Castelli's icon

ok, thanks a lot Tim.

However is this a good design strategy?
I am asking because I am left with a choice to make.

Let me explain:
in my object I have many attributes.
In the above example I pack all the attributes into my dictionary and then output the dictionary.
The dictionary is created on the fly when a "getdictionary" message is received and it is destroyed right before the corresponding method would return.

The alternative strategy would be to maintain a registered dictionary inside my object. The dictionary will basically keep a copy of all attributes and it will be always in existence and ready to be used throughout the object's life. Of course this would require a little bit more management on my part because every time an attribute is changed I will also have to update the dictionary.

I am not crazy about the latter approach because I would basically have to keep the same data twice in my object, and make sure that it is always in sync. (meaning the dictionary and attributes don't hold different data)

However this approach would make the behavior a little more consistent and obvious to the end user.
What would you recommend and how does plot~ deal with this issue?

Many thanks

- Luigi

Timothy Place's icon

There are a lot of different ways you could handle it. You could cache the dictionary in your object struct, but then worry about updating the contents except for when a request is made. The dictionary then is a "last snapshot" of your attributes. This, in effect, is the same as what you have now but the dictionary message will survive asynchronous message passing.

The approach I just mentioned is, in fact, exactly how the plot~ object handles this situation.

Cheers,
Tim

Luigi Castelli's icon

Yes, I like the approach you suggest. The only drawback being that in case of objects that would reference a dictionary (instead of cloning it) this approach would break. Is there any object in the dict family that actually references a registered dictionary, without cloning it?

- Luigi

Timothy Place's icon

The dict.strip example in the SDK is one example.

Cheers,
Tim