Lang.Array.remove not comparing object for Lang.Method -- what i would have expected

method references are objects instances of Lang.Method. II you hold method references in an array (list of callbacks for example)
you are nor able to remove the corresponding one by calling myFuncArray.remove(method(:myCallback)) because it seems the object-Ids (or toString() values?) are used for comparison, and not their hashCode() values.

here some debug-output:

Array content: (each array-member is a method-reference, first value is its toString() value, the second one its hashCode(value))
06:18:19PM:D:BaseDataField [
(Lang.Method)Obj: 122(362),
(Lang.Method)Obj: 134(362),
(Lang.Method)Obj: 140(362),
(Lang.Method)Obj: 148(362),
(Lang.Method)Obj: 331(217),
]

I have a function which should remove one particular entry from the array, also having a Lang.Method object as input parameter:
06:18:19PM:>>:BaseDataField delCbOnCompute: (Lang.Method)Obj: 332(217)
06:18:19PM:<<:BaseDataField delCbOnCompute: (Lang.Boolean)false

So i wonder how remove() and removeAll() compare two objects. Are there some specific comparison patterns for basic types and/or SDK classes ?
Generally spoken it would be great to be able to pass a compare function as parameter to remove() and removeAll().

For me there is a simple workaround which consist to store the Lang.Method object into a class member and re-using that one for deleting from the array, but the disadventages are that it uses some memory in you class instance, the other one is that then the emulator complains about 'Circular References Detected' .

Anyway, for my particular use case i probably have to develop my solution further as i should be able to distinguish between several instances of the same class, each one having registered the same class method into that array.

I observe this behavior with every SDK version 2.x (havn't tried 1.x)
  • Former Member
    Former Member over 7 years ago
    Lang.Array.remove uses the objects .equals() method to compare objects. The Lang.Method() class does not override the .equals() method, and inherits from the base Object type. The base Object type .equals() method just compares the object id, and will only return true if the same object instance is being compared.

    You could create a container object that wraps your method objects, and implement a .equals() method for that class that compares the Method objects by their hashcode. Note that the hashcode method for the Lang.Method object identifies the object only by its method symbol, and not the class in that object, so if there were two method objects that represented the same symbol, but from different classes, this would not uniquely identify those objects. To do that, you would separately need to keep the class reference in the container object, and include it in the comparison.
  • Thanks Brian for the very clear answer.
    I'll do something like you suggest, maybe storing the object.id of the class instance, not the class name itself.
    But interesting enough, that object id must already be stored within Lang.Method(), because having several instances of the same class registering their (same) callback function within my array, every single object is getting properly called when i loop over the array and invoke each of them.
  • Former Member
    Former Member over 7 years ago
    Yes, the method object stores the object instance and the method symbol that were used to create it. You could save the object instance and symbol in the container object, and have it construct a method object only when it needs to invoke the method, and you could compare both elements in the .equals() method.
  • Something like this...

    class Callback
    {
    hidden var _M_object;
    hidden var _M_symbol;

    function initialize(obj, sym){
    _M_object = obj;
    _M_symbol = sym;
    }

    function invoke(){
    var method = _M_object.method(_M_symbol);
    return method.invoke();
    }

    function equals(other){
    return other instanceof Callback &&
    _M_object == other._M_object &&
    _M_symbol == other._M_symbol;
    }

    function toString(){
    return _M_object + ":" + _M_symbol;
    }
    }


    You'd use it like Lang.Method in nearly every way.

    var callback = new Callback(obj, :onCallback);
  • Many thanks for the help! i had wrong expectations of Lang.Array.remove() / Lang.Method.equals() being able to identify Method objects referencing the same method.
  • Former Member
    Former Member over 7 years ago
    Well, it isn't unreasonable to expect the Method object to override .equals() to handle comparisons better, so we could certainly file a request for that, but fortunately there is still a way to work around it.