Challenges with Events

I'm working on a project for students and I keep running into problems, so I want to ask...

  1. Shouldn't these have the same behavior (mouse click resets, the keyboard doesn't)?

  2. Why use keystroke events rather than key-pressed and key-released

  3. For a primitive loop (usually "forever"), if the internal command changes, then the changes are updated automatically. This won't work if I pass a command through into a custom block (if I were to make my own "forever" loop). Is there any way to propagate updates through input variables, even far enough to stop all? This doesn't feel possible based on how I guess custom blocks work.

I'm not positive I'm understanding your questions, but I'll try.

  1. WHEN I AM CLICKED, I think, doesn't work if the sprite isn't already visible. Otherwise, yes, they should be the same.

  2. Key-pressed and key-released are a pain in the neck; you have to remember the state of all the keys. I guess if you're trying to teach them how to program n-key rollover then they need all that, but if Snap! takes care of that for them, they can focus on the interesting part, which is what they want to happen in response to the key.

  3. If you make your own FOREVER using recursion, then that's right, there's no redisplay. You can fix that by putting WAIT 0 SECS before the recursive call; that will yield and allow redisplay (and other scripts) without actually waiting a fixed time. But I'm not sure that's what you mean to ask. Are you asking whether a block can change the value of a variable in its caller? No, because it's the value of the input that is given to the block, not the expression that provided that value.

Sigh.

  1. Scripts with keystroke events are by default thread safe. They will not stop and restart in the middle as long as they're running. This is important, so kids can make games that "jump" or "shoot" on pressing a key while making sure that the character doesn't stop in mid-air but actually returns to the baseline. Other events, such as messages or mouse-events are not thread-safe by default (but there is a setting).

  2. What Brian said.

  3. If you make a control structure using recursion the "action" script (the part that's inside the C-shaped input slot) gets reified when the block is evaluated. The ensuing recursive calls simply pass the already reified script along. That's the reason why changing something inside the C-shaped input slot of a recursive custom control structure while it is already running doesn't affect the - already reified - version of that script. Again, there is a - hidden - setting that lets you turn on "live scripting support", and that will propagate changes (because instead of letting ringification make a new script it only creates a reference to the "physical" blocks inside the C-slot), but that "liveness" comes with surprising side-effects that I wouldn't recommend.

I'm sighing, because such questions, clever observations as they are, imply that in order to program something exciting and meaningful you must need to understands the innards of how Snap works, and I think that the contrary is often true. But that's a different discussion.

Did this help?

This procedure with global variables "stop", "msg" works exactly as expected.

lambda
called this way also...
untitled script pic (6)

And this works even better (with unevaluated input)
untitled script pic (7) untitled script pic (8)

Maybe the unevaluated input should be evaluated by default inside custom block.

If it's evaluated by default, it wouldn't be unevaluated, would it?

No, unevaluated at a time of call but evaluated each time it is referenced in expression. Otherwise there is no need for this kind of parameters. Ringified input is just enough and acts exactly the same way.

So i'm literally expecting this behavior
untitled script pic (10)

I'm guessing what you want is normal order evaluation. But then the rule has to be that the expression is evaluated when used in a primitive. If used as input to a custom block it should stay unevaluated. And yes, when evaluated it has to be memoized.

The reason we have unevaluated input types is that they were the resolution to a huge all-night Skype fight about reporter IF, which at that time was a custom block in the BYOB Tools library. It looked like this:
preloaded libraries script pic
... except this was BYOB, not Snap!, so it really looked like this:
BYOB001
Back then our design for procedure-type inputs was terrible (my fault so I'm allowed to say so): When you dragged an expression over one of those slots it either was or wasn't ringified depending on exactly how far from the center of the slot you let go of the input, so it was both cognitively demanding and requiring good motor skills.

Of course the last two inputs had to be delayed (by thunking) so that base cases in recursive reporters would work. The fight was between the developers (Jens, me) and the teachers (Josh Paley, Dan Garcia). The teachers thought that reporter IF was really offputting to students, and that those two input slots should just look like Any-type slots and the normal-orderness should be implicit. Jens and I didn't want this one block to have an idiosyncratic evaluation rule that we'd have to explain. After -- what was it, five hours? -- of yelling at each other we finally gave in and agreed to make reporter IF a special form. We then all went to sleep (separately).

When we woke up, Jens and I had had the same idea in the middle of the night: Instead of making a special case for reporter IF, we'd make the unevaluated input feature available to all custom blocks! We were very excited about this because it meant reporter IF wasn't a one-off kludge, and because it was something we could teach kids about, the fact that there are situations in which you don't want applicative order evaluation.

So, you're quite right that procedure-type inputs satisfy the need (apart from the small syntactic detail that you can't type a constant value into a procedure-type slot), but what unevaluated input types do for us is transfer some cognitive difficulty from the user of a project to its author.

This sort of discussion, by the way, demonstrates why I worship SICP.

I was just about to send this a bit after this post, I'll add it here and include some replies below.

Here is what I was working on, maybe someone sees something I can't:

Option 1: Key events don't "reset"
Option 2: The logic gets complicated to make option 1 work. Making a custom repeat block for students might abstract the complexity but when changes are made they don't propagate.
Option 3: Use "launch"

Thank you all! This is very helpful.

I'll start with the most important comment... Jens sigh:

I want to make clear that these challenges can about from me trying to create a microworld for the students. Not while students were exploring themselves. This is why I love Sanp!, because it is a wonderful teaching tool and learning tool. It provides the opportunity to create great microworlds, while always being an accessible environment for students to explore. The BJC curriculum demonstrates this, but when I see students of extremely different skill levels working together effectively I feel this.

I thought there would be a reason. I'll be honest it was the Click Alanzo activity that duped me on this.

This makes me question if I am teaching events poorly, here is how I encourage students to achieve smooth movement (it creates a great opportunity to introduce higher-order functions). Please help me if I'm leading my student astray.

I wasn't using recursion for my custom loop, that would have been better... I take it from what Jens said is that it wouldn't matter.

I'm trying to make environments for students with as few global variables as possible, partly because there would be less for them to mess up and partly to give them a clean slate to work on. As you can see from my examples above I don't think this would help solve my problem.

My last effort may be to build my custom blocks out of Javascript.