Not deleting clones

I create these blocks on the stage

script-1 script-2

If I click on the my block BEFORE clicking the green flag I get a list of just one sprite as I expected.

If I click on the my block AFTER clicking the green flag I get a list of TWO sprites as I expected.

If I click on the green flag again AFTER clicking the red stop button I get a list of TWO sprites. Again as I expected.

If I now click on the green flag again WITHOUT clicking the red stop button I get a list of THREE sprites. Is this the correct behaviour? Should clicking the green flag twice have the same effect as clicking the green flag, then the red button and finally the green flag?

Colin Bye

I am unable to reproduce this behavior.

First of all, if these scripts are on the stage, as you said, then nothing happens because you can't clone the stage.

So I'm assuming you meant to put the scripts on a sprite. In that case, before doing anything, MY OTHER SPRITES reports an empty list. Clicking on the green flag once makes one sprite. Clicking on the red stop sign kills all the clones. But clicking on the green flag multiple times in a row doubles the number of sprites each time, because the green-flag script is run by every clone, not only by the original sprite. (MY OTHER SPRITES reports all but one sprite, so you get 1, 3, 7, 15, etc.)

My script on the stage creates a clone of SPRITE not the stage.

But whatever, what you have done confirms what I see.

My question is whether this behaviour is desirable?

Is there some good reason for this behaviour?

I came across this problem when one of my sprites created 15 clones of itself. So after clicking the green flag there were 16 copies of the sprite. A second click on the green flag produced 256 copies. A third 4096 copies. A fourth click would have produced 64K copies, but at that point the rather aged laptop I was using hung!

It took me some time to work out what was happening. I realise that I can work round the problem by clicking the red button before I click the green flag, but it's a rather easy mistake to make.

Would it not be better to change snap (not the user's script) so that if you click the green flag twice without clicking the red button in between, snap "simulates" a click on the red button before actioning the second green flag click?

Colin Bye

Hmm. What would you do if you wanted to double the number of sprites? Maybe you're right and nobody wants that behavior, but for us, to make something impossible (as opposed to just difficult) for the sake of protecting the user from themself has to be really, really important.

I think we need distinguish between the programmer and the user of the program.

In the program I'm trying to create I know that there have to be 15 clones so I can add this init command block to the sprite

init_sprite

and then add this script to the stage

green_flag

This does seem to be overkill. Is there an easier way the program can detect that the user has clicked the green flag twice without clicking the red button in between? Is there some way for a program to delete clones?

I can conceive of problems where it would be much more difficult. In a program which creates lots of clones of different sprites depending on user input this is essentially a memory leak.

Oh, I see. You're making it harder than necessary by having the stage as an intermediary. You can just put a script on the sprite that says WHEN FLAG CLICKED, DELETE THIS CLONE. Then make sure MY CLONES is empty before making the new ones.

I wonder if I've been looking at this the wrong way.

Clones seem to be treated differently from all other aspects of the state of a snap program.

If you click the green flag without clicking the red button, the program's state seems to be preserved until the program modifies it - clones persist, variables retain their values, sprites their appearance, etc.

If you click the red button clones are deleted - but all the rest of the program's state is preserved.

Have I got that right?

If so, why are clones deleted when you click the red button?

Clones that are made by the program (as opposed to ones that you make in the GUI by choosing "clone" from a sprite's context menu) are temporary. This is to help with the typical game programming in which you want a wall of bricks, or a hail of bullets, etc. You make a fresh set each time the game starts. Partly, the reason you don't just make a bunch of permanent ones is efficiency: A regular sprite (including a permanent clone) has an icon in the sprite corral that has to be updated each display cycle, has its own scripting area and scripts, and so on. Temporary clones are more lightweight, so Snap! can support hundreds of them without slowing down horribly.

So, why kill them on stop rather than on green flag? For one thing, green flag isn't the only way to start a project. Maybe each sprite has a "when I am clicked" script. For another, clicking something isn't the usual way to get rid of the temporary clones; usually that happens programmatically, with the DELETE THIS CLONE block. Clicking the stop sign is something you do when your project is running away from you -- and in particular, if your project is in an infinite loop of creating clones.

I'm not, personally, a big game programmer, but when I do write one, I always start with
delete-me

the-game

(FWIW, Jens just pushed a change that deletes all clones on green flag)

A clone is temporary in the sense that it is constructed by the program. But so is the content of a list. So does clicking the stop sign delete list contents?

I suspect the correct solution is that clicking the stop sign should just stop the program running and ALL of the current state should be preserved - not everything except the clones.

There appears to be another difference between the way lists and clones are treated by snap.

If you save a program that creates a list, the list is saved. But clones are not saved.

I think what you mean by "in the sense that" is wrong. Lots of things (you mention lists as an example) are constructed by the program and yet not temporary. In each case it is a design decision what to delete and what to keep when the stop button is clicked. For example, speech balloons disappear when you click the stop sign, but variable watchers don't. Both of those are design decisions we inherited from Scratch, so I'd be guessing if I suggested reasons for them.

Temporary clones are also something we inherited from Scratch 2.0; permanent clones are inherited from BYOB 3.1, which we designed. Scratch created cloning with some reservation, because they were afraid of the "sorcerer's apprentice" scenario in which you get rapid exponential growth in the number of clones when each clone creates clones of its own. So it was important to them that it be easy to get rid of clones quickly and easily. They wanted to enable a particular style of work, in which the game begins by making clones.

The distinction between permanent and temporary is all about efficiency. My standard example of permanent cloning is the four ghosts in Pacman, each of which has its own strategy, but which are mostly the same. Because there are only four of them, there's no concern about efficiency, and because they have different behavior, it'd be hard to provide that if you had to recreate them each game. At the opposite extreme are the bullets fired out of a gun (or zappy laser beams or whatever), which you create dynamically, in great numbers, and all with identical behavior.

So, I don't think there's much point in us arguing about the theoretical correct behavior of what is basically an efficiency kludge.

By the way, funny you mention lists. Projects with huge lists are very slow to save and load, so we created the ability to mark a list-valued variable (from its context menu) as "ephemeral," which means that the value is deleted when the project is saved. The idea is that you save the underlying data as a huge text string, which is much quicker to save and load, and then when the project starts, it recreates the list from the string. So in a way lists are like clones! It's just that the trigger for deletion is saving, rather than stopping the code.