A TADS3/adv3 module for binding a method to a context

Another little module: bind github repo.

This provides a simple method binding mechanism. Sample usage:

         // fn is the foozle method on foo.
         local fn = bind(&foozle, foo);

         // call the bound method, equivalent to foo.foozle()
         fn();

Args can also be bound:

      // fn() will be foo.foozle('bar')
      local fn = bind(&foozle, foo, 'bar'); 
      fn();

Pure convenience stuff, but useful if you’re using a lot of callbacks that are methods on objects.

2 Likes

Minor update: fixed argument handling so that mixing bound and unbound arguments now works correctly.

So given an object defined as:

foo: object
        foozle(arg0, arg1) {
                "\ncalled foozle(\'<<toString(arg0)>>\',
                        \'<<toString(arg1)>>\')\n ";
        }
;

We get…

        // All arguments bound
        fn = bind(&foozle, foo, 'foo0', 'bar0');
        fn();

Produces:

called foozle('foo0', 'bar0')

…and…

        // No arguments bound.
        fn = bind(&foozle, foo);
        fn('foo1', 'bar1');

Outputs:

called foozle('foo1', 'bar1')

And finally:

        // Mix of bound and unbound args.
        fn = bind(&foozle, foo, 'foo2');
        fn('bar2');

Outputs:

called foozle('foo2', 'bar2')

Note that bind() doesn’t do any checking of argument counts, so it’s up to you to keep track of the usage, same as if you were calling the method directly.

2 Likes

A minor usage note. Here’s an example of how to assign a bound method to a property on a different object and then call it on the second object:

class Bar: object
        cb = nil
        construct(fn?) {
                if(dataTypeXlat(fn) != TypeNil)
                        setMethod(&cb, fn);
        }
        callback([args]) {
                if(propType(&cb) == TypeNil) return;
                (cb)(args...);
        }
;

Then if you have something like

foo: object
        baz(arg?) {
                "\ncalled baz(<<toString(arg)>>)\n ";
        }
;

…then you can do something like…

        // fn() will be foo.baz()
        fn = bind(&baz, foo);

        // Now obj.callback() will be fn, which is foo.baz()
        obj = new Bar(fn);

…and so in this example…

obj.callback(true);

…will output…

called baz(true)

Just writing that all out because this is one of my main use cases for the entire binding mechanism and it took a little fiddling around to get it working.

2 Likes

Bump for a bugfix. Bound methods should now return the correct return value to external callers.

1 Like