5 ms·
Variations (to various degrees) are available in plenty of environments. Most powerful one today by combination is actually JS inside Chrome, you naturally hav
by whizzter 5y ago
Variations (to various degrees) are available in plenty of environments.
Most powerful one today by combination is actually JS inside Chrome, you naturally have the REPL that can do things.
But REPL's are good for the first prototyping whilst later on you might have modules (CL might make things inspectable?) that try to hide things (think JS/TS modules), Chrome however is pretty damn good at runtime detecting more or less incremental updates so you can just rewrite code and re-save the source files and Chrome will replace the function bodies in-situ without any state rebuilding or reloading being necessary.
Of more conventional languages, MSVC has had C/C++ Edit-Continue (as long as you didn't change type/function signatures) since ca 1998, it's a descendant of this that MS was hyping last year with Hot-Reloading for C# with body replacement (on top of the interactive shell("REPL") that has been in Visual Studio for years).
Especially the conventional ones might not be as flexible as the Lisp ones(but handle many practical cases fairly well) but all dynamic "scripting" languages like JS/Python/Lua,etc has been able to do most repl-y things fairly well from day 1.
- activitypea 5y agoThe Chrome console is only useful if your code doesn't get bundled, which is rare
- deleted 5y ago[deleted]
- hajile 5y agoThose REPLs aren't even remotely comparable. You can TEST with them, but you never DEVELOP with them. If they were the same, you'd load up a repl of your entire codebase. Now you'd dynamically update the part you're working on, test it live against your current environment, and finally save it to move to another thing. When errors happen, you just drop into the debugger to find the issue. If you missed a call site or two, you'll probably catch it here. Because it's instantaneous, it's not painful. I'll have a REPL open pretty much all the time when messing around with CL. In JS (my day job), this wouldn't work at present if for no other reason than directly replacing a function is impossible. You'd create a second instance of a function, but all the old references from other places in the code would remain stuck with the old version. JS falls back to "hot reloading" which is literally "restart the whole JIT" which means that you have to warm the JIT up again and (more importantly) that all your state disappears. You make a change then wait a while for everything to recompile and run. Then you have to write/execute a bunch of code to get your state back to where it was. When the error is thrown, you now have to look through the things for that call site you missed, save, and reload everything all over again. Rinse and repeat. This heavily disincentivizes interactive and incremental development in favor of massive changes then trying everything out at once.
- aeonik 5y agoI wonder how Clojure(script) deals with this. Do you know if Clojurescript restarts the entire JIT as well? Is it the same in Clojure with Java?
- mikelevins 5y agoClojure and ClojureScript don't have the comprehensive support for livecoding that Common Lisp and Smalltalk do. As an example, consider what happens if Common Lisp's UPDATE-INSTANCE-FOR-REDEFINED-CLASS, mentioned in my comment above, is called without a method definition for the redefined class in question. Lisp drops you into a breakloop by calling BREAK. BREAK is another feature of Common Lisp defined by the language standard (http://clhs.lisp.se/Body/f_break.htm#break http://clhs.lisp.se/Body/f_break.htm#break). It puts you in a repl that has the full language and runtime available, but also exists inside the dynamic environment of the control path where BREAK was called. In this example, that means that we can see the lexical environment of the call to UPDATE-INSTANCE-FOR-REDEFINED-CLASS, along with everything that was on the stack when it was called. We can see the instance that needs to be redefined and all the definitions that are currently in effect. Using the features provided by the breakloop, we can interactively define the missing method on UPDATE-INSTANCE-FOR-REDEFINED-CLASS to properly reinitialize the instance in question, then activate a RESTART (another standard feature of the language) that resumes execution of the function, but now in a dynamic environment that includes the new method and any other changes we made in the breakloop. The original control path that landed us in the breakloop can now complete successfully, referencing a properly reinitialized instance. The method on UPDATE-INSTANCE-FOR-REDEFINED-CLASS is defined now, so future references to previously-defined instances of the redefined class will be transparently reinitialized and behave as if they always had the new definition. Clojure and ClojureScript don't have the runtime support to do any of this. If you redefine a class that has existing instances, and if those instances aren't dropped on the floor when your new definition is hot reloaded, then the old instances don't reflect the new class definition, and so code that relies on it is wrong. When a wrong access occurs, you are dropped--not into an interactive breakloop--but into a noninteractive printed stack trace. The debugging features of modern browsers give you some parts of what a Lisp (or Smalltalk) system does--for example, some tools can watch the dynamic state of variables and enable you to edit them. There are tools available for ClojureScript that give you access to some of these features. Even in the Clojurescript ecosystem, however, the full suite of livecoding tools offered by Common Lisp and Smalltalk (and mandated by the Common Lisp standard) is not available.
- mikelevins 5y agoWhat Lisp and Smalltalk have that still sets them apart is that the language runtime is designed to provide comprehensive support for livecoding. Take, for example, Common Lisp's UPDATE-INSTANCE-FOR-REDEFINED-CLASS (http://clhs.lisp.se/Body/f_upda_1.htm http://clhs.lisp.se/Body/f_upda_1.htm). If you redefine a class in a running program, Lisp notices and the next time control touches an existing instance of the class, UPDATE-INSTANCE-FOR-REDEFINED-CLASS is automatically called to reinitialize the instance to reflect the new definition. That's not all there is to it, of course. For example, how does Lisp know how to reinitialize the instances for the new definition? The Common Lisp standard also defines a complete suite of features to answer that question. Smalltalk provides equivalent features. Lots of languages have repls. Some of them support hot reloading. These are not the same kind of thing as automatically noticing that a definition has changed, and that implies that any time you touch a previously-created instance of that definition the runtime needs to automatically catch it and provide facilities (interactive when needed) to dynamically fix up the data to conform to the new definition. Why would any language define such features? To support a specific style of programming, one in which the program is already running, it just doesn't have all the features you want it to have--so you tell it how to add them, while it runs, and test each new feature immediately, as soon as you've told the program how to do it. Very few languages support the comprehensive whole-system approach to livecoding that Common Lisp and Smalltalk do. These are not new features, though; they've been around for decades.
- LandR 5y agoI've tried some of those, and nothing comes to close to Clojure / LISP repl. Just hitting a shortcut and getting the code executed using everything loaded into the REPL and getting inline results is great. It helps that Clojure only has expressions and no statements as well, so every form can be run and it will return something. Here's what I mean, this is me doing 2021-Day2 AoC puzzle part 1. WHen this pops up => foo Next to a line, it's because I've hit CTRL+Enter on that line to evaluate the form. https://www.youtube.com/watch?v=5HHLT2_a1tI https://www.youtube.com/watch?v=5HHLT2_a1tI (You'll need to bump to 1080 resolution otherwise its probably unreadable) My day job is C# and JS, I can't get anywhere close to this interactivity with my code. As the complexity of the code grows this becomes even more powerful.