What makes a good REPL? (2017)
vvvvalvalval.github.io
vvvvalvalval.github.io
https://mikelevins.github.io/posts/2020-12-18-repl-driven/
https://hyperthings.garden/posts/2021-06-20/hell-is-other-re...
They say Common Lisp (and Smalltalk) provide the "best" REPL experience.
On Repl-Driven Programming (2020) - https://news.ycombinator.com/item?id=31277149 - May 2022 (52 comments)
Hell Is Other REPLs - https://news.ycombinator.com/item?id=28345617 - Aug 2021 (234 comments)
On Repl-Driven Programming - https://news.ycombinator.com/item?id=25620256 - Jan 2021 (206 comments)
What makes a good REPL? (2017) - https://news.ycombinator.com/item?id=24588453 - Sept 2020 (27 comments)
What makes a good REPL? - https://news.ycombinator.com/item?id=15113170 - Aug 2017 (170 comments)
Any testing that had been done in the REPL goes out the window as soon as someone needs to change the code, and verify that things haven't broken.
A REPL can get you faster to a testable state. Say you're following TDD and so you need a failing test which passes in oreder to justify a code change. You might not exactly know what that test is, if you're exploring the problem itself and possible solutions. You use the REPL to iterate quickly on things. Then when you settle on the code change you want, you can write the test, and verify that it fails without the change.
Php has psy shell. When it is loaded for a Drupal/symfony site, you can run api calls against the database. This is where things get tricky.
I can imagine better tooling for psy shell that could protect the underlying data to experiment with code before executing it. It would be great to develop system updates this way if we could work on a copy of the data until we’re happy with the output, then run it for real.
I use psy shell to load services and see what their methods do. The environment is not persistent, but maybe I can export my work to a file. Would love to keep results around for testing or running other functions on.
Which means ultimately, a good REPL is an advanced debugger with code sideloading and reloading/monkeypatching. Running in isolation (in context of the REPL, not the attached-to program) would be awesome, but not trivial (if possible at all) in many cases.
To illustrate, suppose you have some network service (an API in todays talk) and want to play with some form of middleware or new endpoints. You need functional boilerplate to encode, sign, send a request and receive, decode, parse a response. You want to load those parts of the program and play around.
1. You actually have infinite repls where you can start a new one at any time and you don't have to scroll up to see past progress.
2. Excellent highlighting and autocompletion.
3. You can easily access the documentation of any method.
4. Vast set of extensions.
"Symbolics Lisp Machine demo Jan 2013"
...
It is a controversial opinion!
On top of that one can image various user interfaces.
* sophisticated text based repls with integrated repl debuggers and things like structure editors: example Interlisp.
* graphical REPLs which use a graphics capable stream
* presentation-based REPLs like the one from Symbolics Dynamic Windows or CLIM (the Common Lisp interface manager)
* rich structure browser REPLs like the one from Apply Dylan
* REPLs inside a text editor UI
* REPLs inside an IDE
Then there is also the Notebook user interface, which was mostly developed around interactive mathematics software with visualization features. Mathematica made it popular (there were a few earlier systems with similar ideas).
It adds a notebook-based graphical user interface with 2d and 3d graphics. It also usually makes it kind of persistent -> one can store and reopen saved Notebooks.
No wonder that it is popular in areas where data visualization and maths is important. I haven't seen it used outside of that area that much, though.
There seem to be two repls that haven't gotten much traction:
- https://github.com/google/evcxr/blob/main/evcxr_repl/README....
- https://github.com/sigmaSd/IRust
There have been little and big nits that have held me back from wanting to push these further, including
- Bad defaults (having to opt-in to panic handling)
- Command syntax feeling out of place and likely not beginner friendly
- Limits on variable preservation
- Lack of introspection (at least irust as `:type`)
So far I've been punting on wanting to improve this area by instead focusing on polishing up a rust script solution in the hopes of getting it merged: https://github.com/epage/cargo-script-mvs
Then, some languages (like Clojure) have global functions like `doc` or `apropos` that helps you write code.
=> (doc map)
-------------------------
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
Returns a lazy sequence consisting of the result of applying f to the
set of first items of each coll, followed by applying f to the set
of second items in each coll, until any one of the colls is
exhausted. Any remaining items in other colls are ignored. Function
f should accept number-of-colls arguments.
=> (apropos #".+?reduce")
-------------------------
(clojure.core/areduce clojure.core/ensure-reduced clojure.core/unreduced ...)
So when you write Clojure code with a REPL, you hardly need anything else but a REPL + text editor that can connect to said REPL.It's incredibly useful, partially because the standard library is well organized. For example, maybe you need some string manipulation function, but you're not sure what it's called. You'd type `h String.` and then hit tab. Now all the functions of that module are listed. Ah, String.graphemes looks promising - so you finish your line `h String.Graphemes` and skim the doc. Now, to make sure you understand, you might type `String.graphemes("foo")` and then see the result is what you want.
I almost never have to Google for an answer when writing Elixir (at least for simple stuff) because the REPL is so robust as a doc lookup tool.
My only wish is that the vscode extension had some features around sending buffer code to the REPL like SLIME or other Lispy editor plugins. You can reload code, but it's a little more manual than I'd like.
Indeed.
Second to Smalltalk (where the entire environment is your REPL), the best REPL is a Common Lisp REPL. Even the most primitive of Common Lisp REPLs is more useful than a Clojure REPL. This is because the Common Lisp is designed with interactive development in mind.
In Common Lisp, an error doesn't print out a stack trace and leave you puzzling to parse its meaning – it drops you into the debugger where you can inspect the entire system (including local variables on the stack where you are), invoke whatever restarts apply, modify code and continue on.
Since exceptions are quite deeply integrated into those platforms (as opposed to conditions), it has "bled through" to the Clojure APIs, and, in turn, REPL.
Folks have written a CL-style condition/restart library for Clojure (https://github.com/IGJoshua/farolero) too. https://www.youtube.com/watch?v=zp0OEDcAro0 video too.
the only thing i wanted was better integration with my editor of choice (nvim).
I do want to be able to write my Python code with the help of a REPL.
So not node.js, or deno.
With node you can definitely reload a module without restarting the REPL, you just have to make sure to reassign your references to the new module. The ecosystem generally haven't considered things like that in the past though, so requires quite a bit of setup to get working well in your own apps.
You can also install npm deps and switch npm lib version without restart your repl
https://shadow-cljs.github.io/docs/UsersGuide.html#node-repl
1. Something to track the dependency graph 2. A way of determining if a module has side effects (which really requires ES modules)
A couple of modern Logo interpreters with REPLs are: https://lynxcoding.org https://turtlespaces.org
Lisp and Smalltalk look neat in screencasts and have been hyped to the stars for decades, but for getting things done in the modern world, nothing beats a good, statically typed, object-oriented language in an IDE like Jetbrains or Visual Studio (Code). In addition to the benefits of static type checking, in an IDE you can type a variable name and a dot, and get a list of valid methods, exploring what's possible with a given object much faster than even a Lisp machine or Smalltalk environment would avail you. And in a modern IDE, running any test you've written is just a click away.
Lisp and Smalltalk were groundbreaking in their day, but modern languages and environments build on what they provided.
1. copy-paste of code with spaces must work
2. decent history handling (arrows to go up and down, Ctrl+R to search, it could be better with a fish-shell-like history handling)
3. syntax highlighting of returned values
4. reusage of results (in Ruby irb, _ points to the last returned value)
5. source code reloading
6. source code exploring (in Ruby pry, something.source returns the source of the code)