I've had a careful think and this is where my brain is at at de-constructing what is going on
We are defining a reporter, make a counter, that uses a local script variable count
But instead of returning a simple value, make a counter returns a mini-script.
and because we are returning something containing a reference to objects/variables/blocks (not sure which) that are within the user-defined reporter make a counter, this keeps the reporter alive?
If i'm OK so far, then my next step is to understand that because the reporter is only returning part of its script (the increment and report value bit), then that is why it keeps incrementing and not resetting itself to 0 + 1 on each invocation.
Consider a variable to be created by the script variables block, and never deleted, just usually made inaccessible. Snap! actually removes them to not leak on everything.
You're doing great, expressing the concept of a closure (a local variable that has become unreachable except for a procedure that survived the function that created it) very precisely!
It's the variable that's kept alive because the script points to it. And the number is kept alive because the variable points to it.
The way you're supposed to think about it is that everything lives forever (which is different from being accessible everywhere -- that's not the case), but the system is permitted to reclaim memory if it can prove that nothing points to it.
And, yes, the SET COUNT TO 0 is evaluated when you call MAKE A COUNTER, but the stuff inside the ring is not evaluated then -- that's the whole point of rings, to contain code without running it. It's when you call the ring (which you do by putting something that points to it in a CALL block) that those inner instructions are evaluated.
It's really beautiful. The "object oriented" languages think they have to invent special language features to provide local persistent variables, but, as the Beatles sang, all you need is lambda. (And lexical scope, so that the variables that are visible inside a procedure are the ones that were visible when the procedure was created, not when the procedure is called.)
Ta
I'm having a bit of practical difficulty in re-creating the example
Here is my make a counter
When I try and make the ask block - The ringify doesn't auto-magically disappear when I drop the inside call into the outside call and I can't seem to remove it (and therefore I can't get it to work)
Oh, you don't need to make an explicit ASK block, just call the function you get when evaluating MAKE COUNTER directly. That is, you can assign an "instance" of what you get from MAKE COUNTER to a variable, say, "counter 1", and then just call "counter 1" passing in the message and parameter as arguments.
No, Jens, calling the instance with a message reports a method, which must itself be called. It has to be this way to allow different methods with different numbers of inputs, without hairing up writing the methods themselves.
To remove the unwanted ring, right-click on the inner CALL block and choose "unringify" from the menu.
Simon, the default behavior of CALL with respect to rings does the right thing for almost all straightforward uses, but once you start rolling your own OOP you have to think about where you do and don't want rings. Which you did, but you didn't know the mechanism to get rid of a ring.
You have
but it should be
You get the "input list" variant by dropping the args block onto the arrowheads at the end of the CALL block. You'll know you're in the right place because you get a red halo over the whole inputs area.
numbers is set to accept multiple inputs
Snap seems to automagically convert that to a list and processes it within the script as a list
But then later, we have to drop the next list onto the arrowheads so that sizes doesn't get upset that it is being passed a list
But since it treats an input list as a list, couldn't it automagically detect that its being passed a list rather than the programmer having to explicitly having use the dropping onto arrowheads.
Or is the overhead too much or is there something further down the rabbit hole that needs this technique?
Or should I go back to working in 6502 machine code?
Imagine that the variadic input is of type List. So inside the procedure, it looks like a list of lists. But outside the procedure, what happens when you drag a list into the first input slot? Is it a "regular" list, a single input, or is it a list of inputs?
So it's easier all around for us not to try to read the user's mind about this. Both recursion and variadic inputs are somewhat advanced techniques, so someone who's using both of them is old enough to read the manual! ;~)