Hacker News new | past | comments | ask | show | jobs | submit login
What makes a good REPL? (2017) (vvvvalvalval.github.io)
90 points by behnamoh on Sept 7, 2022 | hide | past | favorite | 45 comments




Thanks! Merged list of prev threads:

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)


I would add Clojure to that list as well (though perhaps this is old hat to other lispers): https://youtu.be/gIoadGfm5T8


Well if we're creating a list then I would also add Factor, which provides a full graphical REPL with code browsing, help/docs system, step-thru & interactive debugger, full data/state inspection and much more.


A REPL doesn't let you write fewer tests. You let yourself write fewer tests because of the mistaken idea that manual testing replaces a coded test that anyone can run again.

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.


I get it now, the screenshot shows it all. I have gotten good with debugging php, but I can see that leaning into repl as a development environment has a lot of benefits. Looks like you can experiment with code, keep the returned data, and reuse what you come up with.

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.


Ultimately, a good REPL enables you to test assumptions and behaviours before writing a single line of code that rests on them. It can be a life-saver in dynamically-typed languages with complex operator semantics and large libraries. How can that operation fail? How does it work on boundary conditions? You can test these behaviours instantly in isolation without ever "guessing" in your code.


IMO exploration of complex semantics and/or libraries is quite often a bit futile exercise without appropriate boilerplate/scaffolding.

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.


Ok I know this is a bit of a controversial opinion. But I think the best repl is a Jupiter notebook. And this is also how you should use it. Why?

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.


Jupiter notebook is the rediscovery of how Lisp Machines REPL used to work. :)

"Symbolics Lisp Machine demo Jan 2013"

https://www.youtube.com/watch?v=o4-YnLpLgtk


That is fascinating.


The REPL as such is on its base a relatively primitive thing: it reads an expression from a stream, evaluates the expression, while doing that it prints any side effects and then prints the result.

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.


I use org-babel to do much the same thing for non-Lisp languages.


You are 100% right!

...

It is a controversial opinion!


Something I've been thinking a lot about for Rust is what can and should a REPL experience be for a compiled language (ie what are reasonable compromises).

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


My personal experience is that it would be great if REPL can provide some quick references for APIs, etc.


> (A good REPL) gives you access to your whole project code. You should be able to call any piece of code written in your project of its dependencies. As an execution platform, the REPL should reproduce the conditions of running code in production as much as possible.

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.


The docs in the Elixir REPL are such a pleasure to use. Tab completing a function will show a list of possible matches, and then you can type `h function_name` to see the doc for that function.

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.


> the truth is that not all REPLs are created equal

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.


True, the CL REPL is more useful than the Clojure REPL, but CL has a 20-30 year head start in development. Plus, Clojure was developed as a hosted language, and runs on .NET, Javascript, JVM, and even Dart (in-progress).

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.


Speed. Whether it's hot reloading, auto-completion, history searching etc. as has been discussed in the thread, it's really all about doing things faster with less input and better feedback.


Ipython is the best REPL (for python), really I love it.

https://en.wikipedia.org/wiki/IPython


I like IPython but: I always lose my IPython session and have to start over again. I find copying and pasting to and from an editor to be clumsy. I sometimes have to keep "%load"-ing the same file over and over again to test my changes.

I do want to be able to write my Python code with the help of a REPL.


IPython is probably the most rounded out, but if you want to see some functions it does not have, you can try BPython[1].

[1] https://www.bpython-interpreter.org/


it's my favorite REPL ever. super easy to use, full of features (like, always storing the last variable on a number with %), you can easily browse both documentation with ? (as in list?) or the source code (when available) with ?? (as in requests.get??).

the only thing i wanted was better integration with my editor of choice (nvim).


Being able to reload a module without restarting.

So not node.js, or deno.


If you are using clojure, you can do hot-reload in nodejs

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


I haven't used deno so don't know how that works.

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 do it in Node, but it requires

1. Something to track the dependency graph 2. A way of determining if a module has side effects (which really requires ES modules)


REPLs also make it much easier for kids to learn how to code. That's part of the reason why BASIC and Logo were so popular in the 1980s.

A couple of modern Logo interpreters with REPLs are: https://lynxcoding.org https://turtlespaces.org


I've been using the Hy REPL[0] whenever I've wanted to drop into a python REPL. The lack of whitespace formatting with Hy is great, and it still has access to all of python's libraries.

[0] - https://docs.hylang.org/en/stable/


With TDD you can work without a REPL :) If you really want a REPL, use something like TypeScript.

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.


I think the elisp repl is a good example, can reload on the fly and see result on the fly, also can define load path directly in repl, not like jshell etc have to set class path before entering repl, which is not so user friendly


Being able to reset state, without restarting the whole environment.


> What makes a good REPL?

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)


7. live object exploring (in Ruby pry, ls something returns a human-oriented list of methods, grouped by their owner module, contants, ivars. also cd something changes context, dramatically reducing typing)


Maybe not to the same degree but `see` for python: https://pypi.org/project/see/


Good auto-completion and highlighting.


Highlighting in the REPL is not needed, because your editor does code highlighting already and as Val argues in this blogpost, a good REPL is one you don't interact directly with but via your code editor.


I don't think REPL can be good by themselves. They only make sense as part of a larger IDE.


Vim bindings


Built in package management and documentation are features from Julia's repl that I love.


anything that lets you reload your environment/session so you don't get surprised when you start the repl next time


auto-completion.


Tab completion. mic drop




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: