jmoenig / Snap

a visual programming language inspired by Scratch
http://snap.berkeley.edu
GNU Affero General Public License v3.0
1.49k stars 742 forks source link

Different outputs by watcher and say block #2208

Open SanderTacker opened 5 years ago

SanderTacker commented 5 years ago

Apparently, in the script attached, the input to 'binary' is internally interpreted as string, as you see on the output of the say block, but the watcher omits the leadings zeros. Shouldn't the output be identical? Otherwise the 'letter 1 of binary' returns inconsistent results: the watcher shows 1, but 'letter 1' returns 0.

binary string

jguille2 commented 5 years ago

Yes @SanderTacker, you are right... and this is pretty ugly (:smile: )

The problem is because watchers are rounding numbers (see code here).

But it has not an easy solution, because the real problem is that variables are no typed. And all vars are stored as strings. So, all the actions with numbers (like this rounding) are trying to convert strings to numbers... and then, all "convertible strings" are converted into numbers.

jguille2 commented 5 years ago

Maybe the only solution is to remove this "rounding"?

If somebody assign an operation (a division) and the result is ugly (many decimals), he can round the operation, right?

brianharvey commented 5 years ago

It's not really the rounding that's the problem, I think; it's the decision to treat a string of digits as a number. This specific problem would be solved by saying that a string of digits that starts with a zero digit isn't converted to number. More generally, try converting to number and then back to string, and if the result is different, don't convert to number in the watcher.

Better yet, just as that code tests for type Boolean, let it test for type number (the result of a numeric operator) vs. type string (the result of a string operator, or a character string just entered). I'm sure it would be a major project, though, to preserve that type information along with the value.

jguille2 commented 5 years ago

Yes @brianharvey , you are right!

I discarted using "typeof" because then, rounding would only act over operations

(set (a) to ( 1.123456789123)) will not be rounded!

and it's strange that numbers were rounding or not in different cases.

But really, you are right the rounding is done for operations (many times, the result of divisions), so maybe it's a fine solution.

Then

        if (newValue !== '' && !isNil(newValue)) {
            num = +newValue;
            if (typeof newValue !== 'boolean' && !isNaN(num)) {
                newValue = Math.round(newValue * 1000000000) / 1000000000;
            }
        }

can be reduced to

        if (typeof newValue === "number") {
            newValue = Math.round(newValue * 1000000000) / 1000000000;
        }

@jmoenig will see...

To show this clearly, the result will be: assigntowatchers watchers

Joan