When parameter callbacks get called

This is not a question but an observation–maybe everyone else knows this but I didn’t. When you add a callback function to a parameter, it not only gets called when the value changes but when it’s initialized too. I had assumed it wouldn’t be called since I hadn’t interacted with it yet (and could do something different in that case), but it gets called anyway. The documentation states for “parameter.integer”: “callback: function, this function will be called whenever the parameter is changed, it will be given the parameter value as an argument”. I’ve only tested “parameter.integer” but I assume the same happens for the other kinds of parameters. Just a heads up.

Yes, this is known. And there is a way to avoid this ‘fire-at-first-pass’. If you are interested, i’ll post it.

I’ve written my own, but I’d like to see yours–maybe I’ll learn some new Lua.

I debated whether to call the function immediately when implementing parameters.

My reasoning was that the value does change — if you create a parameter it will set the initial value of your variable. So it felt like sending the callback message was the right thing to do.

That said, I am not convinced it is the right way to go and would be happy to change the behaviour so that it only calls the callback on changes after the parameter has been established.

Your thoughts?

Hello @Simeon. Good to read some from you!
You remember this big discussion we had, me and @Toackick? Well i have not changed my mind: i see no practical interest in this ‘fire immediately’ thing. It just comes into the way most of the time. And generally we set the initial value of the param to its initial value, so it didnt really change. The good paradigm would be (in my opinion): ‘fire when the user touches the UI component’, which is what it is made for.

Good point. I am leaning towards that behaviour as well.

Hi @Simeon. I don’t have an inherent problem with it, it’s just that the documentation led me to expect a different behavior.

My first impression, though, is that it’s less useful. It could be argued that firing on initialization is different from other firings because it is due to a non-interactive event.

In the program I’m writing, I’m implementing a “command”, which completes normally when the user adjusts the parameter, but they can also exit without doing anything to the parameter. The implementation is: To complete the command normally, I set a class’s ivar (= instance variable) based on the callback. During instance instantiation the ivar is set to nil, and the parameter gets its initial value. If the user adjusts the parameter, the callback is called and the ivar is set, but if the user never interacts with it, the ivar remains nil and I can do something different. At least that’s what I expected it to do. As it is, both the parameter and the ivar always get set, but the first time it wasn’t the user doing it, meaning I have to come up with another scheme for detecting that the user exited without doing anything.

If you can argue the other scenario, I’m listening. But I tend to agree that firing parameter callbacks should be reserved for explicit user interactions.

@Jmv38, please post your example.

@starblue I’m in agreement with you. I was just explaining why I had made the initial decision about when the callback fires — in retrospect it was the wrong decision.

I agree with not firing immediately

@starblue: here is a function I’ve lifted from underscore.js and ported to Lua for a Codea/Lua utility library I’ve been working on:

function after(times, fn)
    return function(...)
        times = times - 1
        if times < 1 then
            return fn(...)

Basically, whatever function you pass into after() will not be called until after the returned wrapping function has been invoked times number of times. Here’s an example for an integer parameter. The first time the callback is called, nothing will happen:

parameter.integer("aParameter", 0, 10, 0, after(2, function(value)

I was curious about how others would implement this. (I’m building up a utilities library as well.) Your version does allow the wrapped function to have any number of arguments–I didn’t consider that, having parameters fresh on my mind (but mine can be easily modified to include that).

Here’s what I came up with:

-- "fn" is a parameter callback. Problem is, they get called during
-- parameter initialization as well as when the parameter changes.
-- Wrap it inside "NO_INIT" to prevent that. The all-caps indicate
-- macro-like usage: write the callback normally, then wrap this 
-- around it to implement the extra behavior. 
function NO_INIT(fn)
            local init = true
                    if init then init = false
                    else fn(v) end

Here’s an example of what I meant by “macro-like”. First write the parameter call normally:

    parameter.integer("Magnitude", 0, 10, 5,
                         self.magnitude= v

Then wrap the callback in NO_INIT to add the behavior the “macro” implements.

    parameter.integer("Magnitude", 0, 10, 5,
                         self.magnitude= v

Syntactically it’s meant to look like a C preprocessor macro, although of course there are no macros expanding anywhere, either inside a preprocessor like C or invoked by a compiler like Lisp.

@starblue: That will do the trick, but there are a couple of reasons I prefer an implementation like underscore’s after():

  1. NO_INIT creates 2 functions after it’s called. after() only creates the 1, so it is a bit cheaper in terms of speed and memory usage/churn.
  2. NO_INIT is very specific: you can only use it in the one case, where you want to ignore the first call. With after(), you can specify any number of times to skip invocation, so it is much more general, and at no extra expense.
  3. you mentioned this, but you can pass parameters to after(), which can be useful.

At any rate, there’s really only so many ways you can do this, and they pretty much all involve wrapping the invocation in a closure, and keeping a local variable to track whether/how many times an invocation was attempted. It’s no surprise that our solutions to this problem look very similar :smiley:

EDIT: also, I realized that you could eliminate the disadvantage of #1 from your function by not wrapping the code in NO_INIT in a self-calling anonymous function. In this case, it’s not doing anything for you, except increasing the overhead of NO_INIT.

I am using an older version of @toadkick code:

-- a solution to remove the 'callback on first pass' from parameter
-- proposed by @Toadkick 
-- http://twolivesleft.com/Codea/Talk/discussion/comment/21160#Comment_21160
local function _wrapCB(cb)
    if not cb then return end
    local _cb, first = cb, true
    cb = function(v)
        if first then first = nil; return end
    return cb

-- these are versions of parameter.* that will NOT fire on first pass
function WFCinteger(name, min, max, init, cb)
    parameter.integer(name, min, max, init, _wrapCB(cb))

@Jvm38: thanks for posting that :smiley: It’s a perfect example of a) how all solutions to this problem will likely use similar mechanisms, b) how easy it is to over-engineer a solution, and c) how painful it is to see code you’ve written in the past once you’ve become even a little more experienced than when that code was written. For my part, programming in JS for my job and being exposed to excellent libraries like underscore.js, backbone.js, jQuery, etc. has broadened my horizons quite a bit, and has even increased my understanding of other languages :slight_smile: Also, like pretty much every time I sit down to hack, I learn new things that make me realize how much there still is that I don’t know :smiley:

But that was only 5 months ago or so? I cant believe your experience has evolved that much in such a short time?? :wink:

Lol, you’d be surprised! I only started hacking in Lua in earnest when Codea was released (my exposure to Lua before then was quite limited), and I only started hacking in JS about a year ago, for my job. I learn new things about both languages every day :slight_smile: For example: I learned yesterday that Lua’s unpack function takes 2 additional, optional parameters:

unpack(tbl, 1, 4) 

will return the values at indices 1-4 in tbl. If tbl contains less than 4 elements, nils will be returns for those. It’s great for making sure trailing nils in a previously packed vararg list are preserved.

Also, I re-learn every day how much I prefer Lua to JS :smiley:

I’m familiar with writing closures in expression-oriented languages like Lisp or Javascript, where it’s easy to make anonymous closures like you stated. Lua is very statement-oriented however, and I find it (a bit) harder setting up the closure, which is why I was curious about others’ examples. What I wish were possible is something like this:

fn = do
       local n = 0
          function counter()
             n = n + 1
             return n

fn() => 1
fn() => 2

but “do” isn’t an expression. That is the way one would write it in Javascript, however (with C syntax, of course).

Anyway, seeing your examples helps me see how to create such code in Lua. Thanks.

@starblue: Don’t get me wrong, anonymous self calling functions have their uses in Lua too, they just aren’t necessary as often in Lua as they are in JS :slight_smile: The reason that you don’t have to do it in this case is because a function’s parameters are effectively already considered local to that function’s environment, and will not “leak” out (i.e., every time you call that function, a new “local” variable is generated inside the function’s environment for each of it’s parameters)

The main reason that you see anonymous self calling functions in JS is because JS variables are scoped to their containing function, whereas Lua local variables are scoped to the containing block. In Lua, a block is anything inside a function, a do/end, a while/end, a for/end, etc. For example, in JS, for loops aren’t usually as useful as the JS functions Array.each, etc, because the scope of the temporary variables inside the for loop leak out into the rest of the containing function.

@toadkick i am not an expert as you, but i 200% agree ‘i prefer lua than JS’

@Jvm38: While I appreciate the flattery, I’m no expert. At best, persistent and inquisitive maybe, but by no means an expert. People post things on this forum every day that amaze and humble me, yourself included.