Do closures work at all in Javascript on Max?

Jan 4, 2010 at 7:46am

Do closures work at all in Javascript on Max?

Hi,

I have just started to use Max (5.1.1, for Live) and I notice some irregularities when trying to establish callback functions written in Javascript. It seems that when passing functions to external objects (like LiveAPI), the function is passed by name (or, if I use a literal function, as a string) to the underlying object, invalidating all references to closed-over variables. Now, I can imagine how to work around this restriction by passing the callback arguments through ‘this’, but that is much less modular and much more error prone than just using closures. Is there any fix for this in the works?

Consider

function record_clip(track)
{
var clip_nr = find_free_clip(track);

function set_clip_length()
{
var live = new LiveAPI(this.patcher);
live.path = ['live_set', 'tracks', track, 'clip_slots', clip_nr, 'clip'];
live.set('loop_end', 4.0);
post('clip length set'); post();
}

var live = new LiveAPI(this.patcher, set_clip_length);

live.path = ['live_set', 'tracks', track];
live.set('arm', 1);

live.path = ['live_set', 'tracks', track, 'clip_slots', clip_nr];
live.property = 'has_clip';
live.call('fire');
}

which generates these errors:

js: livetest.js: Javascript ReferenceError: set_clip_length is not defined, line 148
js: livetest.js: Javascript ReferenceError: track is not defined, line 140

Thanks,
Hans

#47545
Jan 6, 2010 at 11:50am

I fixed some closure issues in jsliveapi post-5.1.1. Send me a PM with your email address and OS if you want to do some testing.

Jeremy

#171031
Jan 6, 2010 at 12:00pm

Sorry, just realized that this forum software doesn’t support PMs. Send me an email at jeremy@cycling74.com with that info, if you’re interested.

#171032
Jan 15, 2010 at 2:06am

As I previously documented on this forum, closures don’t work in callbacks only.

http://tinyurl.com/max-js-task-destroys-closure

There’s a simple workaround though!

// Tasker is a  class with a single method, Run, that applies the given function
// with the given "this" and args.
//
// Tasker works around the issue documented in
// http://tinyurl.com/max-js-task-destroys-closures.
function Tasker(object, method, args) {
  this.object = object;
  this.method = method;
  this.args = args;
  this.running = false;  // Perfect for adding a listener to!                                                  

  this.Run = function() {
    this.running || this.Execute();
  };

  this.Stop = function() {
    if (this.running) {
      this.task = this.task && this.task.cancel() && false;
      this.running = false;
    }
  };

  this.Execute = function() {
    this.Stop();
    this.method.apply(this.object, this.args);
  };

  // Schedule this.Loop to run after a delay.
  this.Schedule = function(delay) {
    this.task = this.NewTask();
    this.task.schedule(delay);
    this.running = true;
    return this.task;
  };

  // This method is overriden in tests.
  this.NewTask = function() {
    return new Task(this.Execute, this);
  };
};
#171033
Jan 15, 2010 at 11:31pm

The canonical URL for this code is http://www.swirly.com/Max/js/util/tasker.js

#171034
Jan 16, 2010 at 11:13am

Hi
Maybe check out the “net.loadbang” stuff – I think there is a Groovy instantiation that may help you out….
Cheers

#171035

You must be logged in to reply to this topic.