Forums > Javascript

Do closures work at all in Javascript on Max?

January 4, 2010 | 7:46 am

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


January 6, 2010 | 11:50 am

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


January 6, 2010 | 12:00 pm

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.


January 15, 2010 | 2:06 am

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);
  };
};

January 15, 2010 | 11:31 pm

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


January 16, 2010 | 11:13 am

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


Viewing 6 posts - 1 through 6 (of 6 total)