attribute_new bug?

    Oct 04 2012 | 12:48 pm
    Hi devs,
    I've just jumped a little bit into attribute craziness. I want to have a C++ vector as an attribute, but as obviously there is no macro for that, I am trying to create the attribute using attribute_new. So, here's what I did:
    class_addattr(classPtr, attribute_new("points", _sym_pointer, ATTR_FLAGS_NONE, NULL, NULL));
    CLASS_ATTR_ACCESSORS(classPtr, "points", getPoints, setPoints);
    CLASS_ATTR_DEFAULT(classPtr, "points", ATTR_FLAGS_NONE, "0. 0. 1. 1.");
    I choose _sym_pointer because that was the option that was the closest to a C++ vector. One weirdness is, that I couldn't really figure out how to set accessors within the attribute_new method. Just by putting it there, I got a compiler error, so finally I needed to use the CLASS_ATTR_ACCESSORS macro for this (although the documentation says that I could have set the accessors directly in attribute_new). But the real bug is: each time when I instantiate the object, I get the following warning (four times for each instantiation, probably because there are four items in the default value list):
    method object_clone called on invalid object
    The same happens if I set the attribute type to _sym_object. However (and this is also weird) if I set the attribute type to _sym_char, everything works fine.
    Is this a bug? And BTW, is there a reason why there is no 'untyped' type selector for an attribute? I mean, even with _sym_pointer, it is not exactly the type of a C++ vector anyway...
    Best, Ádám

    • Oct 04 2012 | 4:16 pm
      Hi Ádám.
      Maybe the problem lies in the fact that you use attribute_new() instead of attr_offset_new().
      In bach we do it this way (with a C struct, not a C++ class, but this shouldn't matter) and it seems to work perfectly:
      class_addattr(c, attr_offset_new(attrname, USESYM(pointer), flags, (method)getter, (method)setter, calcoffset(structname, structmember)));
      hth aa
    • Oct 04 2012 | 7:06 pm
      Hi Andrea,
      no luck here. Even with attr_offset_new, I get the same problem (BTW, at least I figured out that the problem with the accessors was that I forgot to cast them to method).
      Could my problem be related to the fact that I'm not using a pointer to a C++ vector, but an actual C++ vector? Obviously, the best would be if there was a category that supports untyped attributes... But anyway, this is really strange, considering that it works fine for your structs.
      The only reason why I don't like the idea of creating this attribute as a char is, that in that case it would appear in the quick help as a char-attribute, which is not the actual case.
      Best, Ádám
    • Oct 05 2012 | 6:21 am
      Uh, yes, I didn't look at your code carefully enough.
      So, with attribute_new you're asking Max to hold a space for a pointer (32 bits) somewhere and make it your "points" attribute. I'm pretty sure it won't work...
      But, correct me if I'm wrong, if you just put your vector in the object structure and make it a pointer attribute with attr_offset_new, then you should be able to do whatever you want with the getter and setter - as long as you have one getter/setter couple for each vector attribute.
    • Oct 05 2012 | 11:15 am
      Yes, that's what I suppose too. In fact, my 'points' vector is included in the object structure. And the real weirdness is, that the warning won't happen if I declare it as a non-pointer type (like char or float), only for 'object' and 'pointer'. BTW, there's no functional bug; since I have my own getters and setters, the object runs fine even when I get the warnings. I also figured out that the warning as caused when I call CLASS_ATTR_DEFAULT on my attribute, if I don't do so, then I don't get a warning. So I really don't understand why this is happening...
    • Oct 05 2012 | 3:11 pm
      Thanks. Could you please try what happens if you add CLASS_ATTR_DEFAULT to your code?
      Thanks, Ádám
    • Oct 05 2012 | 4:12 pm
      Hi Nicolas,
      thanks for verifying. I'm actually not developing an UI object for this, nevertheless, I'm also using a dictionary for this object and have the CLASS_FLAG_NEWDICTIONARY set.
      Could please a guru from Cycling '74 jump into this thread and clarify what's happening?
      Thanks, Ádám
    • Oct 09 2012 | 6:50 pm
      Sorry, but the dictionary constructor currently only works with UI objects.
      best, Tim
    • Jan 16 2013 | 8:11 am
      well, I have a 'dirty' solution for now (see the [sadam.interpol] object's 'points' attribute). I used CLASS_ATTR_FLOAT to create my attribute, and then defined my custom accessors. Now everything works as expected and I'm not getting any warnings. However, the attribute show up as a 'float' in the Max inspector, which is not very elegant. My main is this:
      common_symbols_init ( );
      sadam::interpol::classPtr = class_new ( "sadam.interpol", ( method ) sadam::interpol::create, ( method ) sadam::interpol::destroy, sizeof ( sadam::interpol::ObjectClass ), 0L, A_GIMME, 0 );
      sadam::interpol::classPtr->c_flags |= CLASS_FLAG_NEWDICTIONARY;
      class_addmethod ( sadam::interpol::classPtr, ( method ) sadam::interpol::intEval,   "int",       A_LONG, 0 );
      class_addmethod ( sadam::interpol::classPtr, ( method ) sadam::interpol::floatEval, "float",     A_FLOAT, 0 );
      class_addmethod ( sadam::interpol::classPtr, ( method ) sadam::interpol::listEval,  "list",      A_GIMME, 0 );
      class_addmethod ( sadam::interpol::classPtr, ( method ) sadam::interpol::assist,    "assist",    A_CANT, 0 );
      class_addmethod ( sadam::interpol::classPtr, ( method ) stdinletinfo,               "inletinfo", A_CANT, 0 );
      class_addmethod ( sadam::interpol::classPtr, ( method ) object_obex_dumpout,        "dumpout",   A_CANT,  0 );
      CLASS_ATTR_SYM ( sadam::interpol::classPtr, "method", ATTR_FLAGS_NONE, sadam::interpol::ObjectClass, methodName );
      CLASS_ATTR_ACCESSORS ( sadam::interpol::classPtr, "method", NULL, sadam::interpol::setMethod );
      CLASS_ATTR_DEFAULT_SAVE ( sadam::interpol::classPtr, "method", ATTR_FLAGS_NONE, "linear" );
      CLASS_ATTR_LABEL ( sadam::interpol::classPtr, "method", ATTR_FLAGS_NONE, "Interpolation Method" );
      CLASS_ATTR_ENUM ( sadam::interpol::classPtr, "method", ATTR_FLAGS_NONE, sadam::interpol::MethodFactory::getMethods ( ) );
      CLASS_ATTR_ORDER ( sadam::interpol::classPtr, "method", ATTR_FLAGS_NONE, "1" );
      CLASS_ATTR_FLOAT ( sadam::interpol::classPtr, "points", ATTR_FLAGS_NONE, sadam::interpol::ObjectClass, points );
      CLASS_ATTR_ACCESSORS ( sadam::interpol::classPtr, "points", sadam::interpol::getPoints, sadam::interpol::setPoints );
      CLASS_ATTR_DEFAULT_SAVE ( sadam::interpol::classPtr, "points", ATTR_FLAGS_NONE, "0. 0. 1. 1." );
      CLASS_ATTR_LABEL ( sadam::interpol::classPtr, "points", ATTR_FLAGS_NONE, "Fixed Points" );
      CLASS_ATTR_ORDER ( sadam::interpol::classPtr, "points", ATTR_FLAGS_NONE, "2" );
      class_register ( CLASS_BOX, sadam::interpol::classPtr );
      sadam::copyright ( class_nameget ( sadam::interpol::classPtr )->s_name, "A generic interpolation/extrapolation tool", 2012 );
      return 0;
      Hope that helps, Ádám