# Notes on Instant Broadcasts ## Introduction Hi, I'm the creator of the feature request: "Better sprite communication: "Broadcast and wait" should run instantaneously inside no-refresh custom blocks", which this pull request by open source contributor Sanae6 addresses. I've been programming with Scratch for over ten years and have contributed [many pull requests which were merged over the course of Scratch 3.0's development](https://github.com/search?q=author%3Atowerofnix+org%3Ascratchfoundation++is%3Amerged&type=pullrequests&s=created&o=asc), always taking care to ensure and maintain compatibility with old Scratch projects. I am passionate about teaching programming with Scratch and I want to ensure it has the best tools available to lower the floor so that programming is approachable for anyone, and to raise the ceiling so that students can learn and practice "real world" programming habits and experiences inside Scratch. I have created six Scratch projects which test the behavior introduced in this pull request, aiming to see if it is as powerful and predictable as intended, and doesn't introduce any new problematic behavior. In a few words, yes, it is powerful and predictable, and no, it does not introduce problematic behavior. Because this pull requests offers so much for teachers and learners who want to experiment with OOP in Scratch and other common programming patterns that make use of instantaneous communications between different sprites, I would deeply appreciate if it, along with my notes, could be brought to a team conversation discussing the possibility of merging this and making these new capabilities official and available for everyone. Thank you for your time and consideration. ## Summary of Observations In summary, this pull request changes the behavior of the "broadcast and wait" block. In current Scratch, it causes all corresponding "when I receive" blocks in the same sprite as well as other sprites to be completed all the way, and only then returns control to the blocks that come after "broadcast and wait". Due to a quirk in the Scratch runtime, if a Scratcher ever puts "broadcast and wait" inside a custom block which has been "run without screen refresh", the entire Scratch editor will lock up, which is a very negative experience. In addition to avoiding this surprising and shocking "editor lock-up" behavior, this pull request offers new behavior which is useful to learners and teachers alike. It makes "broadcast and wait" inside "run without screen refresh" run all of its receiving scripts to completion, just like when outside a custom block, but all instantaneously - just like "run without screen refresh" is supposed to. This replaces a currently existing negative experience with a wealth of learning possibilities. I would recommend everyone interested in improving the Scratch experience for learners to read the sections describing my first two projects, **Basic Warp Broadcasts** and **Speedy Broadcast Salad!**. These respectively demonstrate the behavior of "warp" broadcasts and interacitvely show off real-world use cases for them. They demonstrate that the new behavior in this pull request works as it's supposed to in a predictable way, and explain why it would be a valuable addition for students, teachers, and enthusiastic learners of programming. The remaining four projects approach the pull request in a more critical lens, giving it "harder" behavior to ensure nothing is newly broken or problematic. **Fast Broadcast and Wait OOP Demo** is a rework of an existing project which shows that while some of the behavior added in this PR can technically be "worked around" in current Scratch, it's extremely convoluted and not friendly to new learners at all. The updated version, while less interesting of a demo than Speedy Broadcast Salad, is much easier to walk through and understand. The projects **Recursion Bomb** and **Delay Timing** both attempt to "lock up" the Scratch editor, attempting to see if a defense mechanism existing in current Scratch continues to apply correctly and predictably (it does) without limiting the capabilities of Scratch projects that require a greater amount of computational work (it doesn't). The final project, **Timing When I Start As a Clone**, observes an interaction between cloning blocks and "warp" broadcasts. A disclosure: Although I'm experienced working with the internals of the Scratch editor and the `scratch-vm` codebase in particular, I did not consult the code of this pull request before creating these projects and performing these observations. This was so that I wouldn't have my judgment clouded by familiarity with the code. I did run the code locally, creating and testing all these projects with the pull request in full effect. Thus, these notes are not a review of the proposed code changes themselves, but an observation of their behavior, ensuring that nothing is broken and all behaves as expected. An engineer on the Scratch Team should still perform a quality pass across the code changes, but as an observer I can confidently say that the pull request does what it is supposed to and does not introduce any problematic behavior to the areas of the Scratch runtime it affects. ## Project Descriptions and Observations ### Basic Warp Broadcasts This project demonstrates the basics of "warp" broadcasts. A custom block, "my cool script" broadcasts two broadcasts in one order or another depending on its input. The "when I receive" scripts add a word to a variable (banana or orange) and animate drawing a line on the screen (starting from the current position and moving right or up). The project runs the custom block once with "message1" then "message2", and again with "message2" then "message1". This shows the broadcasts behaving like normal, making the variable "apple banana orange" then "apple orange banana", and animating two opposing right angles. Then the project runs another custom block. This one is marked "run without screen refresh", and simply performs the custom block described first instantaneously. The project repeats the same steps as before with this new custom block. It results in the same variable results and right angles, but this time there is no animation for the lines: they're drawn instantaneously, and only the finished angle is made visible. The goal of this project is to show off the basic expected behavior of "warp" broadcasts. In particular, it demonstrates how "run without screen refresh" (warp mode) is inherited the same way across custom blocks and broadcasts. The second custom block activates warp mode; the first custom block inherits it, so triggers its broadcasts (message1 and message2) in warp mode also; each of these receivers changes a variable then sends a further broadcast to perform the actual line animation, these because these receivers are in warp mode, they in turn broadcast in warp mode; then the final receivers (right and up) perform the "repeat 10" animation in warp mode. The consistent behavior across custom blocks and broadcasts makes it easier to teach and understand the "run without screen refresh" concept. It also makes it intuitive to use, because you only have to learn the behavior once and don't have to keep track that broadcasts behave differently from custom blocks. It's logical for broadcasts and custom blocks to behave similarly because they have very similar functions. Both cause another script to activate, returning control to the "parent" script when the "child" script has finished running all of its blocks. In current and previous versions of Scratch, users don't get to take this for granted. Putting a "broadcast and wait" block inside a custom block causes the entire Scratch editor or player (including, for viewers, the rest of the Scratch project page) to lock up and become un-interactive. Scratch handles user input only twice per second and everything else freezes: you have to click the stop sign and it takes time for the editor to respond. This is obviously a very challenging behavior for the Scratch editor to exhibit in response to any user action, putting the user off of experimenting with things they don't understand (they may not be able to figure out what went wrong!). There's room for improvement here, and the proposed behavior makes broadcasts and custom blocks, which already have similar results, handle "run without screen refresh" gracefully and in a powerful way too. ### Speedy Broadcast Salad! This is an interactive demo for a practical use of "warp" broadcasting. I won't walk through every block in this project because it's something you should interact with yourself to get the full picture, but in summary: The user chooses whether to run the project with "speedy" or regular broadcasts, then is instructed to click on several of a variety of characters (clones), each carrying its own secret ingredient. Once several are chosen, the main sprite uses broadcasts to collect each clone's ingredient and makes a salad out of them to share with the user. This project shows off "warp" broadcasts in two ways. First, it broadcasts a "prepare clones" message in either warp mode or not. The receiver (in another sprite) creates 10 clones of itself along the top edge of the stage, then hides itself. If the user chose to use "speedy" broadcasts, these all show up immediately; otherwise, they each appear one at a time. There's also one frame where you can see the final sprite "too far" and cut off by the edge of the screen, and it disappears on the next frame. When a clone is clicked (to select its ingredient), it sends a message to the main sprite, who receives only the clone's index, not its ingredient. When the user has finished selecting ingredients, the main sprite takes each of the items in its list of indexes and sends a broadcast to request the ingredient corresponding from the clone who corresponds to that index, adding the returned ingredient to another list of gathered ingredients (which is used for the salad at the end). While doing this, both lists are visible. If the user selected normal broadcasts, they can see items get pulled out of the index list and added to the ingredient list one at a time; using "speedy" broadcasts, all the items disappear from the index list and appear in the ingredient list at once. The rest of the project is just for fun, but also includes using non-warp broadcasts in useful ways, such as sending a message to a button which only returns control to the main script once the button has been clicked, and using another broadcast without "and wait" to make the salad animate appearing and then do something else while that animation is running. The goal of this project is to comprehensively demonstrate how broadcasts work and show a practical use case for "warp" broadcasting. The most important part is how the clones communicate and the main sprite communicate with each other, and each use "for this sprite only" variables or lists to make certain data private, using messages for communication. Clones send a message to tell the main sprite their index has been selected, which gets added to a private list: the clones can't tell what is in the ingredient list so far. (Each clone keeps track of it itself has been selected, and won't send a message to add itself twice.) When gathering the ingredients, the main sprite sends one message for each selected index, never revealing its full list of indexes, and again retaining each returned ingredient in its own list of ingredients. Using an agreed-upon common language (broadcasts and global variables) to access and interact with privately held data (local variables and lists) is a very common practice in many programming languages, especially object oriented programming (OOP), and broadcasts work together with "for this sprite only" data and clones to make a similar and educational analogue in Scratch. However, in current Scratch, its "real world" utility is limited, because a single "broadcast and wait" generally takes a whole frame to complete. This can be manageable if there are only a few objects, but in all sorts of practical uses for OOP - especially games, one of the most common kinds of projects on Scratch - there are often hundreds of objects who may each receive multiple messages within one single frame! Due purely to a technical limitation, these projects cannot make use of common OOP practices in Scratch, and a great opportunity for learning and real-world practice is lost. Merging this pull request would make that practice possible. **The remaining examples are more technical, and exist either to further test the behavior of "warp" broadcasts or to determine if the pull request introduces any new problems (such as the editor freezing up or unpredictable behavior). In summary, from my testing, it does not: all behavior is predictable and doesn't introduce any new ways to lock up the editor. As best I can tell, this is a completely safe feature addition.** ### Fast Broadcast and Wait OOP Demo This project is a remix of [one I created two years ago](https://scratch.mit.edu/projects/538141012/) when attempting to figure out if "fast OOP" was feasible in existing Scratch, even if I had to use hacks or complicated workarounds to make it work. I worked with other users on the Scratch discussion forums to identify ways to make "broadcast and wait" not wait a full frame, then created a project which demonstrated some basic hidden data techniques and controlling multiple clones every frame from a main sprite using broadcasts. I don't consider this to be as good as a demo as Speedy Broadcast Salad, but have created an updated version with true "warp" broadcasts for comparison. Compare the code in the old version and the new one to see why "warp" broadcasts are such an appealing possible future! (I'm not aware of any other projects which made use of the solution we found to make "fast broadcasts" work, which is quite understandable for how convoluted it was. It also wasn't without other serious flaws. I explored the idea more in [this project](https://scratch.mit.edu/projects/596883630/) - read its comments for a description of a "screen tearing" issue that this approach was prone to.) ### Recursion Bomb This project attempts to lock up the Scratch editor by sending a "warp" broadcast which endlessly broadcasts itself again. Current Scratch has a built-in defense against this, in which "run without screen refresh" is essentially revoked, and the web browser is allowed to evaluate any user events that have been sent (such as clicking the stop sign). The goal of this project is to see if this pull request bypasses that defense. It does not: the defense is in full effect. It appears to affect broadcast recursion in a slightly awkward way. The original thread, which initially sent the recursive broadcast, regains control after only a thirtieth of a second. The recursive broadcast, however, continues recursing, now a "runaway" (since the script who sent a "broadcast and wait" isn't keeping track of it anymore). This recursion continues for the remainder of 500 milliseconds (14/30ths of a second), after which warp mode is fully revoked from the "runaway" recursive broadcast, and full control is returned to the user - the broadcast continues recursing but only once per tick/frame, instead of as many times as it can fit into a thirtieth of a second. Because this returns full control after half a second instead of only processing user input twice every second, this is a better experience for the user. It still catches that something has gone wrong (after all an endlessly recursive broadcast that's supposed to finish in one frame is a problem), but shortly returns full control to the user instead of making the editor largely unresponsive until interrupted. ### Delay Timing The "Recursion Bomb" project caused concern for work that just takes a while. The goal of this project is to identify what happens when the receiver of a "warp" broadcast takes a long time to finish. This uses a slider variable to experiment with how long an imaginary workload will take to finish (using "days since 2000" to just wait until the specified time passes, avoiding an awkwardness of the "timer" block's interactions with "run without screen refresh" that was retained for compatibility with early Scratch 2.0 projects). Thankfully, long work behaves as expected. Control is not returned to the original thread until the receiver finishes its work, including when nested under another receiver. Every 500 milliseconds, other threads (scripts) get the opportunity to continue evaluating, and user interaction is also processed (e.g. hovering or clicking the stop sign). This means projects which perform a great amount of work, or which are performant on one device but lag on another, won't unexpectedly fail as a result of the original thread continuing despite the receiver thread not yet having finished its work. ### Timing When I Start As a Clone This project uses a variety of broadcasts to identify how newly created clones interact with broadcasts, including with "warp" broadcasts. The key takeaway is that "create a clone of" only queues corresponding "when I start as a clone" scripts to be evaluated on the next tick/frame. Until that next tick comes to pass, all values such as "for this sprite only" variables, shown/hidden, and position are inherited from the clone's parent. This means "warp" broadcasts, which are began and completed within the same tick as the rest of the script they're broadcasted from, will be evaluated before "when I start as a clone" if broadcasted within the same tick that the clone was created (or within the next tick by a sprite who is earlier in the evaluation queue, which is controlled by visual layer). This is primarily of concern for project creators who usually set a variable such as "Am I a clone?" or "Clone ID" within the "when I start as a clone" script. It can't be taken for granted as the true first thing to evaluate for a clone when "warp" broadcasts are involved, so projects should take care to update "Am I a clone?" or "Clone ID" within the parent before creating the clone (and restore immediately after). Note that this behavior cannot be avoided. One approach would be to make "create a clone of myself" always immediately run corresponding "when I start as a clone" scripts, but this isn't workable because many projects depend on the existing timing (even if the person who created that project isn't aware). Alternatively, if we were to change introduce immediate "when I start as a clone" exclusively when the "create a clone of" block is positioned in a warp context, it would still be a change of existing behavior. This is because "when I start as a clone" can mutate other global state, not just values contained inside the clone itself, and those changes can be observed by other sprites or scripts earlier in the execution order than "when I start as a clone". This is an unavoidable awkwardness, but I would strongly disagree that it outweighs the overall benefits of "warp" broadcasts, including when paired with clones. I would expect project creators to share awareness that it's better to set initial values to be inherited rather than set under "when I start as a clone" when using "warp" broadcasts - this is a niche behavior but Scratchers are already aware of details to do with script timing, see educational community projects like [Why is my sprite lagging?](https://scratch.mit.edu/projects/105607329/) by TheLogFather, [Sprite Depth Sorting](https://scratch.mit.edu/projects/307388424/) by griffpatch_tutor, and an older project [Script execution order](https://scratch.mit.edu/projects/18490761/) by TheLogFather. In a theoretical world we could introduce a new "create clone of ... and wait" block, which follows the same rules introduced for "broadcast and wait". There's merit to this idea, but it's a limited use case block, and should be focused on at another time.