When parameter callbacks get called

How about this?

parameter.integer("Q",0,100,-50,function(a) if a>0 then callback() else Q=50 end end)

ie set the value to an illegal value initially, then in the callback function, test for an illegal value. If it is illegal, set to the initial value, otherwise run the callback function.

That doesn’t work. If the initial value is out-of-bounds, it takes the nearest legal value.

My mistake, I thought it worked, but Codea is applying the minimum before the function runs, curses!

I prefer this approach.

function setup()
    parameter.integer("Balls",1,10,3, BallsChanged)
end

function BallsChanged()
    if pBalls==nil then pBalls=1 return end
    print("Balls=",Balls)
end

I realise this creates a global variable, but it’s a whole lot easier to understand than a closure.

It works by accident. I reversed the condition and the then/else parts. It should do the exact same thing, but it doesn’t.

    parameter.integer("Q",0,100,-50,function(a) if a < 0 then Q=50 else callback() end end)

I think I understand why, too. In the meantime, any of the other mechanisms is safer to rely on until if/when Simeon fixes it.

@Ignatz. Global variables are evil. I’ve written programs containing tens of thousands of lines of code which had but one global variable–the one representing the app (you need something to be the entry point). Closures aren’t that bad, once you “get” the language’s syntax. Lua is actually helpful in that anything that causes an indent in the code sets up a new lexical scope. Most languages have exceptions of various kinds that you have to remember–Lua is very regular that way.

@starblue - yes, but for the vast majority of users of Codea, closures are a mystery, and they may never even write hundreds of lines in one project.

So I think there is room for both an optimal and a simpler, good-enough-most-of-the-time solution :slight_smile:

@starblue - here’s your next challenge. In my code above, if I slide from 3 to 7, the callback fires for each of 4, 5, 6 and 7. How do I make it only fire on 7?

I can use a timer to delay executing the callback for (say) 1 second, to allow the user time to finish, but is there a better solution?

@Ignatz: It seems unfair to expect that the majority of Codea users won’t be able to understand closures. I think you’re selling a lot of people short, including yourself. Honestly, they’re not so hard. It seems odd to me to refuse to learn to use a tool that might be perfect for the job, especially in this case when using that tool is pretty easy. I’ll be a monkey’s uncle if I’m going to stop posting code that highlights one of the wonderful advantages of Lua! :smiley:

Anyway, one solution to your challenge, assuming I understand it correctly:

-- reusable callback generator;
-- returns wrapper that invokes callback when 
-- passed a value between min and max.
-- if max is omitted, it defaults to min.
function ranged(callback, min, max)
    max = max or min
    return function(value)
        if value >= min and value <= max then
            callback(value)
        end
    end
end

function setup()
    -- the callback we want to invoke when our parameter is in range
    local function onInRange(value)
        print("value", value, "is in range")
    end

    --set up a parameter to invoke onInRange when value is 7
    parameter.integer("someValue", 1, 10, 3, ranged(onInRange, 7))
end

I don’t understand the question. A parameter callback gets the value and presumably puts it somewhere else not affected by the parameter; that should take microseconds. If you don’t want it right away, don’t use a parameter–its corresponding global can be read any time. Anyway, my initial question has been answered.

Thanks, @toadkick.

I can assure you that most Codea users don’t understand closures. There is a huge number of users who don’t post on the forum, but are struggling to learn Codea. I see the traffic through my tutorials (which include closures). So a simple alternative is helpful, sometimes, although I also like to see the best solution posted.

Actually, my latest query was more to do with situations where a change in parameter requires quite a lot of code to run, eg maybe a parameter where you select scenarios that need substantial setting up. If I want to change from scenario 2 to scenario 5, I don’t want to run the setup code three times, ie from 2 to 3, from 3 to 4, and from 4 to 5. I want to just switch to 5. I think a timed response is probably the only approach to prevent the callback firing continuously. Anyway, it’s not important, I was just wondering about it.

@Ignatz I think that that situation is where you start implementing your own UI controls.

@Andrew_Stacey - I don’t think I wanted to hear that! :-/

@Ignatz: Actually your idea is not bad, and could work. There’s actually a name for that process of delaying for a bit to give things time to “settle down”. It’s called debouncing. underscore.js has a debounce function, but it’s a little trickier to port to Lua due to it’s use of setTimeout (fwiw tween.delay could be substituted for setTimeout).

I didn’t think of tween.delay, thank you…

I fear I may have missed the waggon a little on this… However i would actually agree with @Simeon’s initial decision, the value of the parameter changes from nil or another value to the specified initial value and each time the parameter is adjusted. However currently the behaviour is a little odd when the value doesn’t technically change when its initialised:

    print(_G["test"])

    test = 0

    print(_G["test"])

    parameter.integer("test",0,100,0,function() print(test) end)
    
    print(_G["test"])

-- prints
-- nil
-- 0
-- 0 -- callback
-- 0

I would also be inclined to avoid any setup / heavy or dependant logic in callbacks from parameters, in my opinion to do so would just be asking for headaches considering its user input :slight_smile: