For Each <item> in LIST block

As I was going over the new LIST blocks in SNAP! 5, I noticed the behavior I described below. I might be doing something unintended, but I thought the blocks use shown is pretty simple and straightforward.

List_Text

List_Math

Please fill out these questions for all feature requests and bug reports.

  1. What browsers show this problem?
    CHROME Version 75.0.3770.100 (Official Build) (64-bit)
  2. Please share an example project (if possible).
    See block captures.
  3. Describes the steps to reproduce this issue.
    Separate the LIST creation block from the FOR loop.
    Run the LIST creation, followed by the FOR loop.
    For text combines:
    1st run produces a change in element one only:"No:1", "2","3"... etc., the rest stay the same. The loop seems to be running without any change of <item>.
    I click on the FOR block to stop it, and then click again to run it again.
    2nd run produces the rest of the changes: "No:1","No:2","No:3",...etc
    For math block use:
    1st run changes only the first element to "2", the rest stay the same. The loop seems to be running without any change of <item>.
    I click on the FOR block to stop it, and then click again to run it again.
    2nd run produces an endless loop of ever incrementing list elements.
  4. What does Snap! currently do?
    See above.
  5. What should Snap! do instead?
    I was expecting each element to be changed per the text / math op coded on the first run of the loop.

Awesome bug! Working on it...

Turns out that NUMBERS reports a linked list, REPLACE converts it to a dynamic array, and FOR EACH had a bug if the list changes internal format midway through. This is why it worked the second time; although the first time didn't work, it did convert TEST to a dynamic array.

I fixed the code; I'm not sure when Jens will install it. Thanks for finding this!

P.S. Mixing functional and imperative coding styles for a single list is discouraged, but it's just supposed to be slow, not to fail altogether. FOR EACH is a funny intermediate case, because it's imperative, but clearly has a lot of shared DNA with the higher order functions.

To be honest, I was extremely hesitant submitting this as a bug. Such a simple code test for such a simple function not working, sounded like I was utilizing something in a wrong way. Thanks for relieving me from the burden.
Yeah ! I found a bug!!!
:slight_smile:

Hi Turgut,

the fix is already in the development version (Redirecting to Snap!) and will be part of the next minor release probably sometime within the next week. Thank you!

I guess I'm not as kind as Brian when it comes to qualifying whether this behavior should be supported or not. The point is that your sample code mutates the list as it is being enumerated by FOR EACH. That is something I would consider a user error, even if it is "easy" to write. If, on the other hand, you had used the yellow FOR block in the "control" category to iterate over the indices of the list that would have worked perfectly fine.

Anyway, I agree with Brian that FOR EACH is somewhat of a hybrid construct, half functional and half imperative, so it's certainly a good idea to make it so it works both ways.

Again, thank you so much for dabbling with the new version and reporting this bug!

Still wondering why this work and doesn't work.

Hi, welcome to the forum!

I'm not sure exactly what doesn't work, since you left out the code inside the FOR EACH. If you mean to put exactly the same IF/ELSE inside, then the problem is about you using the word "item" to mean two different things. In the FOR block, what you're calling "item" is what we would call "index": a small positive integer saying where in the list an item appears. But the "item" in FOR EACH ITEM is the actual item value, not its position in the list. So you'd have to say IF ITEM > 5. (But it still wouldn't work because for REPLACE ITEM you need the index, not the item itself.)

As Jens said earlier in this thread, if you're going to mutate the list, use FOR rather than FOR EACH. We have FOR EACH in part because we try to encourage ways of working with lists that don't require mutation.

P.S. @jens: We should think about changing the upvar to ITEM VALUE, to discourage this misunderstanding.

Naw, just because one single person misunderstands something lets absolutely not confuse all the others!

This has come up before. Not constantly, but more than once. But whatever, just an idea.

Well, you used to argue strongly against my former naming scheme derived from Smalltalk, which was "each item". Now all our materials are using "item" and there's no way I'm going to change it again.

Hmm I wish you'd felt that way about combine. :~/

Now now Dads! Stop bickering in front of us children please!

Thanks for the explanation. Most list are based on index numbers, for me and I think others it would be more concise to use the index number of a list instead of the actual list value. How could I make up if a this block is constructed around the index or the actual value.

English is not my first language, when I read this in the help menu about the replace block I think of "item" as the actual value and not the index number.l

In languages - you can either use a standard for loop = 1 to len(list) and then use loop as a lookup index for each item in the list

In more recent ones (like Snap! or Python ) they make it easier by just supplying the item directly without having to do the lookup manually

But sometimes you still need to use the index lookup method

snap inherited the list blocks from scratch, and they don't want people who came from scratch to be confused.

Thanks, all the comments were helpful. Feels good, after all those years..I am still a novice.

Right, if what you're going to do inside the loop is a REPLACE ITEM, then just use a FOR loop, not a FOR EACH loop.

But that example is much better done functionally:


MAP doesn't modify the input list DATA at all; it creates a new list. Here I've put that list in a variable, but you don't have to do that; you can use it as the input to further processing. In the first input to MAP, the two empty input slots will be filled with an item (not its number!) from DATA, for each item of the list. The looping has become implicit; the emphasis is on the result you want, not how to get there. (For example, maybe you're running this program on a multi-processor system, and the computation for several list items could be happening in parallel!)

This worked for me. :slight_smile: