question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow custom blocks to be shaped like C blocks ("if", "repeat", etc)

See original GitHub issue

(This is a feature request. To my surprise, I couldn’t find an issue for this created yet! But maybe I missed one.)

Scratch custom blocks have always been a powerful way of simplifying code. They reduce the amount of duplicate code in a sprite by allowing you to reuse a procedure; text/number and boolean inputs complement this by letting you give specific values to the blocks in the procedure. They even allow for some neat and convenient programming tricks by way of recursion (that is, you can call a custom block from within the definition of that custom block) and “run without screen refresh” (an option that makes the custom block evaluate as quickly as possible, not allowing any other scripts to run at the same time).

Of course, Scratch custom blocks are based on the “procedures” (or “functions”) feature found in nearly all programming languages, which also feature inputs/parameters and recursion. However, procedures in many “professional” programming languages allow for a particularly unique idea absent from Scratch: creating custom control structures.


(Click me!) Blathering about text-based languages, so we can compare with Scratch :) (This section is an aside - you don't need to read it to understand the suggestion.)

Text-based programming languages are burdened by syntax, which makes creating and using custom control structures a rather daunting practice. For example, start by looking at the following JavaScript function, which prints the numbers from a given start to a given end, and see how it is called:

function printNumbers(start, end) {
    for (let i = start; i <= end; i++) {
        console.log(i);
    }
}

printNumbers(1, 10);

This is relatively simple function and is easy for anyone who knows of for loops (part of most introductory JS courses) to understand. Now suppose one wants to create a function which can “take behavior as an input”; that is, one where we do something else with the number instead of console.log-ing it, and what we do is specified by the code calling printNumbers instead of inside printNumbers itself. The actual code defining it isn’t really complicated, but the way we have to call printNumbers afterwords is sort of icky:

function useNumbers(start, end, func) {
    for (let i = start; i <= end; i++) {
        func(i);
    }
}

useNumbers(1, 10, function(number) {
    console.log(number * 2);
});

Take particular note that even though for and useNumbers are fundamentally similar in that they are both control structures, the built-in for loop uses “ordinary JS” syntax that most are familiar with, whereas the user-defined useNumbers function requires passing a first-class function. Treating a function as a value is already something new JavaScript programmers are unfamiliar with; passing one into a function and then calling it from inside that function is only more confusing. In Scratch design lingo, this is a “high ceiling, high floor” feature: while custom control structures are a powerful idea, they are difficult to get started with.

However, this brings us to custom control structures in Scratch…


Scratch is built around being “high ceiling, low floor”, meaning powerful but easy to get started with. And while custom control structures in other programming languages are typically a high-floor feature, Scratch has the advantage of being block-based, so syntax is essentially not an issue. For example, let’s look at a simple “show numbers from A to B” custom block:

define "show numbers from (A) to (B)": set Number to A; repeat until Number > B: say Number for 2 secs, change Number by 1

Now suppose we want to make a custom block which lets the user decide what gets done with the number, instead of just “say”-ing it. This is conceptual syntax, but I’ll use it to demonstrate:

define "use numbers from (A) to (B) (script)": set Number to A; repeat until Number > B: (the "script" block), change Number by 1

Indeed, writing this was as simple as replacing the “say (Number) for 1 secs” with a block-shaped input.

But how would this look in the block palette (where custom blocks show up)? Well, perhaps it’s not actually surprising:

A c-shaped custom block with the label "use numbers from () to ()"

Making use of it would be just as simple; you’d simply use the “Number” variable inside the script:

use numbers from (1) to (10): say (Number) * (Number)

Update December 14: Be sure to take a look at this additional section proposing custom block “outputs”, as well as the immediately-below comment with interesting examples of custom C-blocks!

PS, regarding implementation, this would be pretty easy to fit into the UI – just add another option below “run without screen refresh”, something along the lines of “C-shaped”. (Probably a better string than that, since it’s not particularly self-descriptive to someone who doesn’t already know the term. But “run without screen refresh” really isn’t that much better - perhaps both ought to have more details that show up by hovering over an adjacent “info” bubble!)

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:4
  • Comments:10 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
mrjacobbloomcommented, Nov 30, 2018

It’d be awesome if extensions could extend the custom block interface, so callbacks and custom reporters could be opted into by advanced users without adding potentially confusing new features for everyone else, and so (depending on the extension approval/import process or whatever) power-users could just write the extension to add these kinds of advanced features as they need them

2reactions
towerofnixcommented, Nov 30, 2018

@joker314 I did think about E-shape blocks (etc) while writing this suggestion, but I decided not to include them because they “raise the floor” a lot (so, high-floor instead of low-floor).

PS, neat sketchup. I was thinking of a different syntax though. I don’t think your screenshot is very intuitive; instead, I suggest something like this:

define "while  { stack } "

As you can see, the “while” block is an actual C-shape, which is how it will display in the block palette. This matches how the “placeholder block” in current custom blocks match how the block will actually display in the block palette.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Define a custom block in your own shape! - Discuss Scratch
(But its in a C shape) wich is like what its trying to mean in its shape when you make it look like...
Read more >
Scratch Custom Blocks Tutorial - YouTube
In today's Scratch tutorial, I show how to use custom blocks !Thanks for watching! Please hit the like button and subscribe for future ......
Read more >
Scratch Custom Blocks: A Beginner's Guide - YouTube
In this simple tutorial suitable for Scratch beginners, technology educator Andrew Tomec will help you unlock the power of "My Blocks ", ...
Read more >
Scratch Custom Blocks | Curnow.biz
This works for B/b and C/c, etc. So a method to convert upper case to lower case could loop over all the characters...
Read more >
Custom Blocks with Branches - Help with Snap!
Is there a way to create a custom block that is shaped like a branch block (such as the default If block)? If...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found