Skip to content
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

[RFC]: add support for eager evaluation of side-effect free code in the REPL #2073

Open
3 tasks done
kgryte opened this issue Mar 27, 2024 · 16 comments
Open
3 tasks done
Labels
difficulty: 4 Likely to be moderately difficult. Enhancement Issue or pull request for enhancing existing functionality. JavaScript Issue involves or relates to JavaScript. Needs Discussion Needs further discussion. priority: Normal Normal priority concern or feature request. REPL Issue or pull request specific to the project REPL. RFC Request for comments. Feature requests and proposed changes.

Comments

@kgryte
Copy link
Member

kgryte commented Mar 27, 2024

Description

This RFC proposes adding support for eager evaluation of side-effect free code in the REPL. E.g.,

In [1]: [ 'foo', 'bar', 'beep' ].sort()<|>
[ 'bar', 'beep', 'foo' ]

would trigger a preview below the input command, where <|> represents the cursor. Upon hitting ENTER, the command would execute with the result displayed after the output prompt, as normal.

This feature is now implemented in browser devtools, such as Chrome (see https://developer.chrome.com/blog/new-in-devtools-68/#eagerevaluation).

The tricky bit with implementing this is detecting side effects. And we'd likely want to avoid eagerly evaluating things like HTTP requests. Additionally, we'd like want to exclude things which are not idempotent (e.g., PRNGs, Date constructor, etc).

There is also the concern as to how to handle eager evaluation of computationally expensive commands or commands returning large outputs.

As this feature may not be desired by all users, we should presumably support an option for enabling/disabling this on REPL instantiation. And we should disable eager evaluation when not in TTY mode.

Related Issues

Questions

No.

Other

Resources:

Checklist

  • I have read and understood the Code of Conduct.
  • Searched for existing issues and pull requests.
  • The issue name begins with RFC:.
@kgryte kgryte added Enhancement Issue or pull request for enhancing existing functionality. RFC Request for comments. Feature requests and proposed changes. Needs Discussion Needs further discussion. REPL Issue or pull request specific to the project REPL. priority: Normal Normal priority concern or feature request. JavaScript Issue involves or relates to JavaScript. difficulty: 4 Likely to be moderately difficult. labels Mar 27, 2024
@MeastroZI
Copy link
Contributor

@kgryte,
Please check weather i am on right track or not :

we need to trigger the processLine method (similar to the one in Multiline Handler) on every key enter in the terminal. If no errors occur during line processing and compilation, the output should be displayed as a ghost line after execution using either runInContext or runInThisContext.

Is this the correct high-level idea?

@MeastroZI
Copy link
Contributor

MeastroZI commented Nov 30, 2024

Or we need method which tell us weather the command is complete or not . cases like

  1. weather enter keyword is complete keyword from the context or not
  2. command not end with ','
    and others

and on the bases of this method we can go forward to process line and show the ghost output

@Snehil-Shah
Copy link
Member

Snehil-Shah commented Nov 30, 2024

@MeastroZI as mentioned in the RFC, we should not be evaluating things which might trigger stuff like HTTP requests or any other stuff that can have side effects (ref). Hence, directly trying to execute the input is not the way.

@MeastroZI
Copy link
Contributor

MeastroZI commented Nov 30, 2024

@Snehil-Shah so we need to check that weather the input is pure have no side effect , then after that we have to go further ? ,

And what about the context should we have to use the other context ? so it not pollute the global one as a side effect ?

@MeastroZI
Copy link
Contributor

so we need to check that weather the input is pure have no side effect

And have to implement something similar to the constantinople or to use it ?

@Snehil-Shah
Copy link
Member

Snehil-Shah commented Nov 30, 2024

And what about the context should we have to use the other context ? so it not pollute the global one as a side effect ?

I think we would have to consider the global context. In devtools console, when you define a global variable, let's say a string. And in a later statement, you run a "pure" function on that string, it still eagerly evaluates. So, no, the context shouldn't be confined to that very input.

I would suggest playing around with the chrome devtools console to get an idea of expected behavior. You might even find patterns that can help you understand the underlying implementation.

@Snehil-Shah
Copy link
Member

And have to implement something similar to the constantinople or to use it ?

@MeastroZI We would want to avoid additional dependencies. Maybe it can act as a reference literature for our implementation? And yes, we should execute the expression only after we are sure it has no side effects.

@MeastroZI
Copy link
Contributor

MeastroZI commented Dec 3, 2024

I have researched a bit and play with the devtool and interested to go forward , i have one doubt that how can we find weather the function or method we have called from terminal is side effect free means , i have one way in my mind like this .

  • we will traverse from the AST nodes of the code

  • recursively traverse from the content of the function

  • have to maintain the object name context copy in which all the local identifiers nodes are mapped with there nodes ( AST node) so we can check the variable used under the function is global or local one . As if it working on local variable then it is not have any side effect .

  • this context copy can be nested because of closers property

  • now with this context copy we can safely define weather the function contain is side effect free or not .

@Snehil-Shah and @kgryte can u tell me am i on correct path or not

If not then i will greatly appreciate your guide

@Snehil-Shah
Copy link
Member

@MeastroZI Can you explain better with some examples?

Cases like mentioned in the OP and with global variables like:

[1]: var a = 'a string'

[2]: function modifyString(val) {
           // A pure operation
      }

[3]: modifyString(a)
      // Gives eager evaluated output 

@MeastroZI
Copy link
Contributor

MeastroZI commented Dec 3, 2024

@MeastroZI Can you explain better with some examples?

Cases like mentioned in the OP and with global variables like:

[1]: var a = 'a string'

[2]: function modifyString(val) {
           // A pure operation
      }

[3]: modifyString(a)
      // Gives eager evaluated output 

sure

  • this one is basic :
[1]: var a = 'a string'

[2]: function modifyString(val) {
           a = 'changes'
      }

[3]: modifyString(a)
      // nothing 
  • if we define local variable same name as a global one:

[1]: var a = 'a string'

[2]: function modifyString(val) {
          let a ; 
          a = 'another local string' ;
          return a ;
  
      }

[3]: modifyString(a)
// pure function
// another local string 

NOTE : in this case we require to maintain the local context as here we define the local variable and changing it

  • nested one
1]: var a = 'a string'

[2]: function modifyString(val) {
          let a ; 
           
           function modifyStringsecond() { 
                a = "changes from nested method";
            }
          modifyStringSecond() ;
          return a ;
  
      }

[3]: modifyString(a)
// pure function 
// change from nested method 

NOTE : in this case we need to context map need to be nested as there can be a variable define in execution context and have to check weather this variable is of local one or the global one ,

like in this case this same example is impure

1]: var a = 'a string'

[2]: function modifyString(val) {   
           function modifyStringsecond() { 
                a = "changes from nested method";
            }
          modifyStringSecond() ;
          return a ;
  
      }

[3]: modifyString(a)
// impure function 
// nothing

@MeastroZI
Copy link
Contributor

MeastroZI commented Dec 3, 2024

If i am in very wrong direction ! then please tell me , please don't just ignore me here. 😢

@Snehil-Shah
Copy link
Member

Snehil-Shah commented Dec 3, 2024

@MeastroZI you misunderstood my example

[1]: var a = "HELLO"

[2]: function modifyString(val) {
          return val.toLowerCase()
      }

[3]: modifyString(a)
      // Should eagerly evaluate to 'hello'

Plus also the examples in the RFC:

[1]: [ 1, 3, 2 ].sort()
      // Should eagerly evaluate

@MeastroZI
Copy link
Contributor

@MeastroZI you misunderstood my example

[1]: var a = "HELLO"

[2]: function modifyString(val) {
          return val.toLowercase()
      }

[3]: modifyString(a)
      // Should eagerly evaluate to 'hello'

No i underdtood it and Completly agree with that to , but my question is how we can algorithmically we can define weather the method is side effect free or not ? Please refer this for completely understand my question. https://stackoverflow.com/questions/10662477/is-there-a-way-to-determine-if-a-javascript-function-has-side-effects#

@MeastroZI
Copy link
Contributor

Specially if function is calling other funcrion and have nested call expression

@Snehil-Shah
Copy link
Member

Snehil-Shah commented Dec 3, 2024

@MeastroZI I don't know (haven't dived into this yet), I'll leave that for you to figure out.

@kgryte
Copy link
Member Author

kgryte commented Dec 3, 2024

As discussed during office hours today, the plan is to punt AST analysis for side effects to future work. Instead, at least for stdlib functions, the initial goal will be to add meta data to packages describing whether exposed APIs are pure. We can then build a REPL database of such functions, and for those functions, perform eager evaluation with result preview.

Before building such a database, the aim should be to implement the logic and UX for displaying result previews. As a test case, the implementation should assume that a single API (e.g., base.sin) is pure. Once we've figured out the UX, we can later extend support for result previews to other APIs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: 4 Likely to be moderately difficult. Enhancement Issue or pull request for enhancing existing functionality. JavaScript Issue involves or relates to JavaScript. Needs Discussion Needs further discussion. priority: Normal Normal priority concern or feature request. REPL Issue or pull request specific to the project REPL. RFC Request for comments. Feature requests and proposed changes.
Projects
None yet
Development

No branches or pull requests

3 participants