source-academy / js-slang

Implementations of sublanguages of JavaScript, TypeScript, Scheme and Python
https://source-academy.github.io/source/
Apache License 2.0
67 stars 104 forks source link

Conceptual problem with declarations in REPL #256

Closed martin-henz closed 5 years ago

martin-henz commented 5 years ago

We explain function, const and let as constructs that adhere to lexical scoping: They introduce a name whose scope is the block in which these declarations are evaluated.

The REPL behaves in a peculiar way in this respect. Consider:

Screenshot 2019-06-24 at 9 12 30 PM

Here the declarations of a and b are not limited by a surrounding block. They appear on "top level". However, their declarations fail to have an effect on functions f and g, respectively.

I think this behaviour is good: It's in the spirit of lexical scoping that one should not be able to retroactively introduce a name in a program that is already evaluated.

Consider the following explanation model for this behaviour:

The PRELUDE is an imaginary program that declares primitive and predeclared names, such as math_pow, NaN, pair and map.

The RUN program is the program that the student enters in the editor on the left, and REPL Program 1, 2, ... are the programs entered in the REPL.

I'm arguing for the following explanation of execution in our interactive environment:

PRELUDE
{
    RUN-program
    {
       REPL-program 1
       {
           REPL-program 2
           {
               REPL-program 3
               *
           }
        }
    }
}

etc. Each program is surrounded by an implicit block, and the next program is inserted inside the previous block, at the end, indicated by *.

This is an explanation model that respects lexical scoping and is consistent with our intuitions. However, it does not explain the fact that we cannot re-declare names:

Screenshot 2019-06-24 at 9 36 11 PM

If there is a new implicit block for every program, it should be possible to re-declare names. So the current behaviour of our system does not seem to have a consistent explanation model.

I'm arguing to explicitly establish the model above, and to adapt the implementation to this model.

Advantages:

(Daryl is arguing for this model due to more implementation-specific reasons, but I think these are related to the conceptual simplicity and consistency of the proposal.)

Disadvantages:

Any views welcome!

TobiasWrigstad commented 5 years ago

So, the inconsistencies are wrt. let but not to var, right? This makes me feel the inconsistency is rather minimal.

In my mind, the model is elegant and nice. I would even argue the extra frame in the drawings is a plus -- as it is possible to graphically clearly explain why certain behaviours with respect to names occur.

martin-henz commented 5 years ago

So, the inconsistencies are wrt. let but not to var, right? This makes me feel the inconsistency is rather minimal.

In my mind, the model is elegant and nice. I would even argue the extra frame in the drawings is a plus -- as it is possible to graphically clearly explain why certain behaviours with respect to names occur.

We don't have var any longer in Source, so this issue is quite prominent. Yes, I agree that the environment model will be clearer as it separates predeclared names from user-declared names.

TobiasWrigstad commented 5 years ago

We don't have var any longer in Source, so this issue is quite prominent. Ah, yes ofc.

Are you worried that CS1101s students will write programs in the source academy REPL and then try to run them in say Node.js and see programs fail?

martin-henz commented 5 years ago

The (rather minor) worry would be that students point to a Source Academy session like this: REPL Program 1: const a = 1; REPL Program 2: const a = 2; and then say: This should not work, because it does not work in Chrome. After all, we claim that Source is a sub-language of JavaScript, so everything in Source should work in JavaScript.

I think we can argue that we take the liberty to fix a conceptual bug in the Chrome and Node.js REPL. (They probably cannot fix this due to the need to be backward compatible.)

TobiasWrigstad commented 5 years ago

Yes. REPLs are tricky that way. If they paste their entire REPL interaction as a single paste or as multiple different pastes, we have semantic differences in Source with this new model. I don't think that is the case of Chrome or Node.js. But OTOH -- is REPL interaction and running a source file identical actions? I agree with taking the liberty. If anything, the divergence is actually an improvement given that on a REPL, wanting to redefine constants is actually very common during debugging and exploratory programming.