scriptsharp icon indicating copy to clipboard operation
scriptsharp copied to clipboard

Passing the same function as an argument creates different ss.Delegate objects.

Open colin-dumitru opened this issue 13 years ago • 4 comments

Currently, when passing a function as an argument to another method a ss.Delegate object is created for each call. This will cause an unpredictable behavior when comparing methods received as a parameter. For example, take the fallowing method from an Event class.

public void Subscribe(EventHandler handler, Nullable<Boolean> unique) {
            if (unique == true && this._handlers.Contains(handler))
                return;

            this.._handlers.Add(handler);
        }

the method adds another function to a list which will be used later when firing the event. This compiles to :

subscribe: function GLSharp_Core_Event$subscribe(handler, unique) {
            if (!!unique && this._handlers.contains(handler)) {
                  return;
            }
            this._handlers.add(handler);
      }

The fallowing line is an example of calling the Subscribe method:

test.Subscribe(Handler, false);

Which compiles into:

test.subscribe(ss.Delegate.create(this, this._handler), false);

As you can see, the condition this._handlers.Contains(handler) always evaluates to false, because the list does not contain the actual functions but the ss.Delegate wrappers, which are created for every call of the Subscribe method. Currently, One workaround that I can think of is to create a compare method:

private Boolean MethodsEqual(EventHandler m1, EventHandler m2) {
            return (bool) Script.Literal("(m1._targets[0] == m2._targets[0]) && (m1._targets[1] == m2._targets[1])", null);
        }

colin-dumitru avatar Apr 19 '12 14:04 colin-dumitru

The workaround that makes more sense to me is to cache the delegate instance on the object itself if it is to be reused.

There was a thought to do this in Delegate.create, by passing in a 3rd argument - the name of the function, so it can lookup in a cache of delegates stored on the object instance itself.

Another workaround is to use a static method if the handler doesn't refer to any instance members. In that case, the function is used directly, rather than creating a delegate instance which binds together a method and an instance to invoke the method on.

nikhilk avatar Apr 22 '12 17:04 nikhilk

This is marked as fixed now. Can I ask what version/commit the fix is in?

ProdigySim avatar Oct 08 '12 19:10 ProdigySim

This is fixed in the upcoming 0.8 release. You can either checkout the "cc" branch and build, or download a preview build, i.e. its not final yet.

A preview of that release (yesterday's build) was shared on the downloads page for the repository. Since then a couple of bug fixes have been made, and there will be another preview build later today. If you're up for it, definitely give the preview build a shot, and report back with any issues you find.

nikhilk avatar Oct 08 '12 20:10 nikhilk

@nikhilk maybe need to tag the issue with the appropriate version number

andrewharry avatar Oct 08 '12 22:10 andrewharry