-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
toLeopard: Translation for repeat blocks is incorrect #119
Comments
Yeah, good catch. There's a bit of a philosophical trouble over this, and it has to do with how much we translate (and thus detect) Scratch programming constructs into analogous JavaScript constructs, to the ends of trying to teach more of JavaScript the way you'd see it in the real world. For example Scratch doesn't have the basic A "simple" fix would be to try to determine if the value in the repeat block's input is static. This could be as simple as checking if it's a number or as complex as checking if it's a reporter expression which only depends on variables, lists, or other values that certainly won't be mutated over the course of the repeat block's evaluation. (Not impossible to guess at, but definitely not trivial.) // scratch: repeat (10) ...
for (let i = 0; i < 10; i++) { ... } // scratch: repeat ((4) + (6)) ...
// Could translate like this:
for (let i = 0; i < 4 + 6; i++) { ... }
// Or like this:
let times = 4 + 6;
for (let i = 0; i < times; i++) { ... } // scratch:
// set index to 1
// repeat length of my list:
// say item index of my list
// change index by 1
// Could translate like this:
for (this.index = 1; this.index < this.myList.length; this.index++) {
this.say(this.myList[this.index - 1]); // or whatever
}
// Or like this:
this.index = 1;
const times = this.myList.length;
for (let i = 0; i < times; i++) {
this.say(this.myList[this.index - 1]); // or whatever
this.index++;
} // scratch:
// repeat length of my list:
// add pick random 1 to 100 to my list
const times = this.myList.length;
for (let i = 0; i < times; i++) {
this.myList.push(random(1, 100)); // or whatever
} And then there's the boring way that we, unfortunately, have to fall back to sometimes, mostly when Scratch behavior is particularly unique and not able to be represented concisely. You can do something similar for the "repeat" loop: this.repeat(10, () => {
...
});
this.index = 1;
this.repeat(this.myList.length, () => {
this.say(this.myList[this.index - 1]); // or whatever
this.index++;
});
this.repeat(this.myList.length, () => {
this.myList.push(random(1, 100)); // or whatever
}); Despite having a certain kind of elegance, this is patently awful for actually teaching JavaScript. The trouble is that this here below really isn't much better. this.index = 1;
const times = this.myList.length;
for (let i = 0; i < times; i++) {
this.say(this.myList[this.index - 1]); // or whatever
this.index++;
} Static code analysis is a longer term potential direction of sb-edit (and Leopard, really) that we haven't taken a lot of time to dig into because it's a major project and everyone developing sb-edit has been busy with other projects. And without a good amount of infrastructure or utilities for performing that analysis, it's just impossible to greedily translate code to analogous JS without risking breaking programs. I've moved this issue over to sb-edit since that's what is in charge of actually converting Scratch projects. You're right in pointing out a bug: existing projects with reporters in the "if" block don't work. For now I think we're best off having a special-case for if the input is a number (not a block), which will behave like it currently does, and in all other cases we store the number of times in a temporary variable, as you suggest. On a practical note, for now, the this.index = 1;
for (let i = 0, times = this.myList.length; i < times; i++) {
this.say(this.myList[this.index - 1]);
this.index++;
} |
I think I understand Leopard's goal a bit better now :) I've also found another bug by accident, which is the modulo operator |
I think just checking if the repeat's input is a static number would be enough, as it is: a simple change, fixes an obscure bug, and looks neat and understandable to someone trying to learn JS. |
LeopardJS coverts Scratch's 'repeat n times' block in to a for loop, like this:
However, this translation is invalid when it comes to
n
being non-static, as while Scratch 3 only calculates it once and keeps the value, leopard will calculate it at each iteration of the loop.I encountered this issue when I was converting a project with looped through the length of a list minus a variable, and changed the variable inside the loop.
An easy fix would be to have a variable before the for loop:
The text was updated successfully, but these errors were encountered: