
Programming at the REPL (2018) - tosh
https://clojure.org/guides/repl/guidelines_for_repl_aided_development
======
piercebot
The REPL is still something that I haven't quite mastered, but what I enjoy
doing right now is working in files and using a REPL connection to evaluate
expressions within the file. It feels like a happy medium between "do
everything at an (ephemeral) REPL prompt" and "do everything in a file, save,
and reevaluate the file."

My weapon of choice right now is vim-iced[0], which is a batteries-included
VIM plugin that, in addition to providing a REPL and keybindings to evaluate
expressions under the cursor, also allows me to auto-format my files on save.

[0]: [https://github.com/liquidz/vim-iced](https://github.com/liquidz/vim-
iced)

~~~
reddit_clone
Yep. Thats what I do too.

For emacs users, 'eval-region' and 'eval-expression' are your friends.

~~~
Jtsummers
And if you have language support in org, use an org file.

    
    
      #+BEGIN_SRC lisp
        (+ 1 2)
      #+END_SRC
    
      #+RESULTS:
      : 3
    

(type C-c C-c inside the source block)

If you use noweb it'll also include referenced blocks in the evaluated unit:

    
    
      #+NAME: foo
      #+BEGIN_SRC lisp
        (defun foo (n) (+ 1 n))
      #+END_SRC
    
      #+BEGIN_SRC lisp :noweb yes
        <<foo>>
        (foo 2)
      #+END_SRC
    
      #+RESULTS:
      : 3
    

This lets you have many versions of code in one file (if that's a sensible
thing for you, very useful when exploring a new library or concept though),
and in the end you can aggregate it all into one source file for sharing with
others:

    
    
      #+BEGIN_SRC lisp :tangle foo.lisp
        <<foo>>
        <<bar>>
      #+END_SRC
    

(type C-c C-v C-t to create the file)

I've mainly used this (for interactive development) with Common Lisp, but it
should work for most other languages that offer similar interactivity.

------
verytrivial
I had my mind lightly blown watching someone using Squeak Smalltalk to
interactively prototype something or other.

They purposefully called a method which did NOT exist, used the debugger to
partially unwind the #doesNotUnderstand stack, implemented the method, which
then returned the expected result as if the method had existed all along.
Benefits of super late binding I guess.

~~~
veddox
Sounds cool, but what exactly is the advantage of doing it like that?

~~~
Jtsummers
There are a couple reasons and ways to use that approach.

Unlike batch compiled languages, Smalltalk and Common Lisp (and some others)
will throw an exception/signal an error/whatever that indicates that a
function doesn't exist. This means that you can insert these calls and, unless
they actually occur, the rest of your program runs just fine. In most batch
compiled languages you'd at least need to insert a dummy method/function (in
C# you'll see _NotImplementedException_ being thrown in these).

When you encounter the exception, in languages that support it, you can write
the code at that time and then let the system resume, or tell the debugger to
return a value. Maybe you don't know how to implement that function, but you
know the kind of thing it should return and, for some reason, you don't want
to leave function floating out there that just returns a dummy value
permanently ( _(defun random () 4))_ ).

If you use a language like Smalltalk, there's also a tendency to write very
short methods. You could use this approach to create your program in a more
top-down fashion (versus bottom-up) by doing something like this (I don't know
Smalltalk so this is lisp):

    
    
      (defun main() (factorial 10))
    

Debugger is brought up because _factorial_ doesn't exist.

    
    
      (defun factorial (n)
        (fact-aux n 1)) ;; not really needed in Common Lisp, but just to illustrate
    

Again the debugger is brought up so we define the next function:

    
    
      (defun fact-aux (n acc)
        (if (<= n 0) acc (fact-aux (1- n) (* n acc)))
    

If you already have a design in mind (sketched out on paper perhaps), you
could use something like this pretty effectively. Not sure I would though.

------
mbil
I don't have much to add to this discussion except to say that after years of
repl-driven development in Clojure I've switched to Ruby as my primary
language, and the iteration cycle is just really slow. I feel like I've traded
in my fighter jet for a commuter car.

~~~
jimbokun
How would you contrast developing with the Clojure REPL compared to irb? I've
found irb to be pretty useful for some quick and dirty tasks, albeit not the
same level as Clojure (or most Lisps, really).

~~~
mbil
My experience with IRB has been so-so. I've found it fine for experimenting
with small functions as I develop them, poking at interfaces, etc. But it's
really nowhere near the experience I had with Clojure and a repl-integrated
programming environment. I've only been using Ruby on Rails for a little under
a year, so I have some more learning to do, but I'm not hopeful about the
productivity story.

Repl-driven development in Clojure with Emacs and CIDER [0]:

You develop a namespace or two at a time and you're looking at a handful of
files in your editor. You can move between function definitions, modify them,
and re-evaluate them as easily as moving the cursor and pressing a key. The
whole editor becomes a playground: every piece of code you see can be changed
and evaluated as fast as you can think. You can execute a web request from
cURL or the browser, and your Clojure repl is hooked into the running program.
So you can capture real inputs, store them in temporary vars, play them back,
change them on the fly, etc.

The IRB is just very linear in comparison.

[0]: [https://cider.mx/](https://cider.mx/)

------
modernerd
Clojure[Script] is worth learning just to experience a REPL-driven development
environment.

Some editors and IDEs support it better than others, though, notably Emacs and
Atom. Cursive (for IntelliJ) is pretty good, and Calva (for VS Code) is
promising, but they lag behind in polish and features when I tried them. For
example, I don’t think Cursive has inline output next to the expression you’re
evaluating like Proto-repl for Atom does, and once you’ve tried that you don’t
want to live without it.

I don’t write much Clojure these days but miss the REPL-driven experience. I
recently discovered Quokka and Wallaby for JavaScript/TypeScript:

[https://quokkajs.com/](https://quokkajs.com/)

[https://wallabyjs.com/](https://wallabyjs.com/)

They offer a great experience that beats console.logging your way to success
or step-through debugging by far.

Just highlight the expression you’re interested in and get inline output (in
the paid version of Quokka) right in your editor, including evolution of
values in for loops and the values of data retrieved from fetch requests. It
has greatly shortened the feedback loop for me and both plugins were much
easier to set up and configure than Clojure’s REPL integrations.

------
lukashrb
I always wonder why repl driven development is not as popular as it (in my
opinion) deserves to be? Am I missing something here?

~~~
jonahbenton
There is a non-virtuous (vicious not the right term) cycle at play.

Many problems are only solvable with compiled languages, for performance,
correctness, or other non-functional considerations. Many people are first
taught on compiled languages, and bring those approaches to dynamic languages.
The popular dynamic languages, in their standard/common toolchains, do not
have robust repl support (looking at you Python and Javascript). The absence
of a robust repl workflow means people who are exposed to it in those
languages aren't really impressed by it. Really too bad.

~~~
volker48
I do repl driven development just fine with ipython and autoreload setup. What
features do you feel are lacking?

~~~
jonahbenton
Yes, when I work in python, I do that too. It certainly works ok.

The place I would start from a critique perspective is around lifecycle.
Python has encouraged carelessness and overwork at module load and init time,
and there aren't common protocols (that I have seen) that involve standing up
a graph of objects across an application after a single module reload. So when
you reload a single module and the names in the module now point to different
data and code elements, all the downstream dependencies on those names have to
change as well, and Python doesn't have patterns for organizing and managing
at that level.

This also impacts runtime introspection, which is a key benefit of a repl
oriented language. One implication is that there is not at all a pattern of
"repling into" a running python application to poke around and see what is
going on. To most python programmers this is a foreign concept.

Related others involve code style, and implicit vs explicit ways of referring
to and moving data around, which also impacts runtime whole system
introspection.

Python has all the pieces to have a very nice repl-first programming model,
but lacks patterns for key parts of that- explicitly standing up the graph of
live objects, and using a repl to interact with a live system with live
objects.

Hope that makes sense.

------
cameronperot
I do a lot of scientific computing, mostly in Julia, and having a REPL at my
disposal is extremely useful. There's a great VIM plugin [1] that enables you
to send code from the editor to a terminal to be executed, e.g. a tmux session
which has a REPL open. It can be coupled with other nice plugins such as vim-
ipython-cell [2] and vim-julia-cell [3].

[1] [https://github.com/jpalardy/vim-slime](https://github.com/jpalardy/vim-
slime)

[2] [https://github.com/hanschen/vim-ipython-
cell](https://github.com/hanschen/vim-ipython-cell)

[3] [https://github.com/mroavi/vim-julia-cell](https://github.com/mroavi/vim-
julia-cell)

------
jimbokun
A REPL can also be excellent for operations work and ad-hoc tasks. I use it a
lot when I need to extract some data from a REST API. Can create a toolbox of
methods over time for making calls, and add new ones in an ad-hoc fashion,
then use those to script larger tasks. Exploration, analysis, minor ETL tasks,
debugging state of deployed systems, etc. etc. can all be enchanced by a REPL.

~~~
oweqruiowe
yea I'm an idiot and need to get my hands dirty with response types so I'm
often just building up lots of top level `(def body ..)` variables that will
eventually be moved into a single function.

But just messing around in my editor connected to a repl lets me really
breakdown a task while I'm figuring it out.

------
derision
I started learning Clojure yesterday,I've gone through the docs here and have
a grasp of the language. Does anyone have some good resources for further
learning? Maybe some high quality tutorials? I'm mostly interesting in web /
apis

~~~
goostavos
I don't think there's a single best Clojure book, so I'll recommend several
(all available on Safari if you have that). For general language, syntax,
idioms:

* The Joy of Clojure (whirlwind tour of the language and Clojure philosophy.) * Brave Clojure (A very wordy, hand-holdy approach. I really like this one for dense topics like core.async which can take time to wrap your head around) * Programming Clojure - just an all around solid reference. Once you've got a command of the language, this becomes more valuable imo .

Now, there's a large gap between knowing Clojure's syntax and writing
effective programs in the language. Clojure is not Python, or Haskell, or
Java, and, as such, you don't build programs in the same way. So, as a final
recommendation, I'd suggest the book Clojure Applied. This book deals with
going from "I know the language" to "I know how to build things in the
language"

For the web, get ready to beat your head against a wall for hours and hours on
end ^_^. Lisp's "small pieces" philosophy is both a blessing and a curse.
Outside of a framework called Luminus, and a few leiningen templates, the way
to do things in Clojure land is by stitching a bunch of ad-hoc libraries
together by hand, which means a lot of evaluation of not-too-popular github
repos.

Once you've got everything dialed in though, it's an absolute joy to use.

~~~
invalidOrTaken
For the newbie Clojurist trying to do web stuff I'd highly recommend Luminus.
I don't agree w/every choice the framework makes, but those are minor details
compared to the choice paralysis one tends to suffer without some experience.

Clojure is too good to miss out on because of stuff like that.

------
entha_saava
Can someone knowledgeable explain how are lisp REPLs different from Python /
Ruby REPLs? What is the differentiating point of REPL driven development?

Is it that you interactively test your functions and add them to source file
once they work? Or is it that with editor integration, you can load functions
to REPL as they are defined? Am I missing something obvious?

~~~
mikelevins
I've answered similar questions several times over the past few years, but I
don't mind repeating myself. It offers me a glimmer of hope that my preferred
way of working may not fade away, after all.

Consider the standard Common Lisp generic function UPDATE-INSTANCE-FOR-
REDEFINED-CLASS
([http://clhs.lisp.se/Body/f_upda_1.htm](http://clhs.lisp.se/Body/f_upda_1.htm)).
It reinitializes an object when Lisp detects that the object's class
definition has changed.

Ask yourself this: who would call such a function? Why would anyone ever
invent it? Not only did someone invent it, a committee of some of the world's
smartest and most experienced Lisp programmers wrote it into the ANSI standard
for the language. What were they up to?

UPDATE-INSTANCE-FOR-REDEFINED-CLASS is not a weird anomaly; it's part of a
carefully-considered set of features and protocols designed to support a
specific style of programming. The Lisp runtime calls it for you automatically
when it touches an object whose class definition has changed.

If you've defined a method specialized for it, then Lisp executes that method
to rebuild the touched instance as if it had originally been instantiated from
the class's new definition, and then your program goes its merry way. If you
didn't specialize UPDATE-INSTANCE-FOR-REDEFINED-CLASS for this case, then the
Lisp drops you into a breakloop.

A breakloop is an interactive repl with full access to all of the runtime's
memory and all of the language's features, including visibility into the whole
call stack that landed you in the breakloop. You can wander up and down the
call stack, inspect anything in the runtime, edit bindings, redefine types and
functions, and resume execution either at the point of control where the
breakloop started, or at any other point for which the breakloop exposes a
restart.

UPDATE-INSTANCE-FOR-REDEFINED-CLASS is not the weird fever dream of a confused
eccentric. It's part of a purposeful system design intended to support a style
of programming in which you build a program by interacting with a live runtime
and teach it, interaction-by-interaction, how to be the program you want,
while it runs.

It's a particular example of a general approach to programming best
exemplified by these old systems. That general approach is the answer to your
question: "Can someone knowledgeable explain how are lisp REPLs different from
Python / Ruby REPLs? What is the differentiating point of REPL driven
development?"

The differentiating point is that the entire language and system is
thoughtfully designed from the ground up with the assumption that you're going
to be changing your work in progress while it runs, and that you should be
able to change absolutely anything about it as it runs and have a reasonable
expectation that it will continue to work while you do it.

I like to call this style of programming "programming as teaching", and
distinguish it from the much more widespread "programming as carpentry", in
which the programmer is, metaphorically speaking, at a workbench banging
together artifacts and assembling them to see how they turn out.

To be clear, I do not claim that the teaching approach is objectively better
than the carpentry approach. I claim only that I, personally, am happier and
measurably more productive using the teaching approach. I know that some other
programmers report the same thing, and I suspect that if the teaching style of
programming were more widely known, then there would be more programmers who
prefer it.

There are several sibling comments that assert that any language can be made
to support repl-driven programming, or that offer various languages and
systems as examples of repl-driven programming. I'm sure that's all true, for
some relatively restricted version of repl-driven programming, but the gold
standard in repl-driven programming is programming as teaching in the style of
old-fashioned Lisp and Smalltalk systems. These old systems offer amenities
that the younger alternatives touted here do not match. I want more people to
be aware of what they're missing.

Starting in the 1980s, I grew accustomed to systems that could start from cold
in about a second, presenting to me a complete interactive development
environment with all tools preloaded and ready to work, with the whole dynamic
environment of my work in progress in the same state it was in the last time I
was working with it. Moreover, I was accustomed to being able to take a single
file from one machine to another to reproduce that same whole working
environment equally quickly and easily on the new machine.

I could save the entire dynamic state of the running system to an image file,
a serialized version of the running system's memory. I could later start up
the system with that image file and be exactly where I was when I saved the
image, right down to the positions and contents of all the open windows. I
could save an image showing some bug or some strange behavior and give it to a
colleague so that they could see it, too, and interact with the restored
dynamic state to debug it.

I enjoyed comprehensive whole-system reflection that enabled me to view and
edit absolutely everything in the running system while it ran. I could inspect
absolutely everything, including the development environment and all its
tools, interactively change any variable or field value, redefine any type or
function, and continue to work with the changed system without stopping and
restarting. (Obviously, if I made a bad change I might break the system, but
remember, I could kill it and get back to where I started in a second or so).

I could start some process running--perhaps a 3D animation in a game, or a
discrete-event simulation, or whatever--and change any values or definitions I
liked to see what changed in the running process, without stopping the process
to rebuild. For example, I could tell a rotating copper cube to become a glass
icosahedron and reasonably expect to see my changes immediately reflected in
the running program. This property is invaluable not only in games,
simulations, and any kind of work with a visual-design component, but also in
any kind of exploratory programming, where you're constructing data structures
and evaluating expressions interactively to test your ideas.

Similarly, I could build some speculative data structure to explore an idea,
and define some functions to operate on it. I could evaluate those expressions
to see their results or to change the example structure. I could inspect the
structure interactively and edit it in place if I think something different
would work better. If I think a problem is caused by some structure or value
in it, I could use the inspector to change it and see. If I thought one my my
functions was doing something I didn't expect, I could insert a call to break,
to activate a repl from inside the function call that would enable me to
inspect and edit the data structure, redefine the function, and continue from
there.

Anything the development system could do, I could do by typing an expression
into the repl. As an example, nowadays you can still rebuild the whole Clozure
Common Lisp environment from the ground up by typing (rebuild-ccl :full t).

The point is not that I would want to rebuld my Lisp from the repl all the
time. The point is that the repl doesn't impose any aribtrary boundaries on
what I can do. If the language and development environment can do it, I can do
it from the repl. This is one of the properties that distinguishes the whole-
system interactive design of these old tools from the more limited repls
offered by newer ones. In pretty much every repl I've used other than old-
style Lisps and Smalltalks I'm all the time stumbling over things you can't do
from the repl.

I mentioned breakloops above. Their absence in younger languages and tools
seem to me like some sort of sin, like we're tragically abandoning some of the
best lessons of the past. Few newer development systems have them, but they're
incredibly useful--at least if the language runtime is designed to properly
support interactive programming.

A breakloop is a repl with all of the same affordances of the normal repl, but
extended with all of the dynamic state of the control path that invoked the
breakloop. If an error or an intentional call to break triggers a breakloop
somewhere deep in a stack of recursive function calls, you get a repl that can
see every frame of that stack, and every variable and value lexically
accessible from it. You can browse all of that whole, change values, and
redefine functions and types. You can resume execution at your leisure, and
any changes you made in the breakloop will be visible in the resumed
computation just as if that's how things were originally.

Proper breakloops don't just improve error messages; they replace them
wholesale with an entire species of programming that lays the whole dynamic
state of the system out on the table for you to examine and modify while the
program continues to run.

Moreover, everything I just described about breakloops can also be automated.
These old systems provide not only interactive tools for rummaging through the
dynamic state of a suspended computation, but also APIs for handling them
under program control. For example, you can wrap an arbitrary function call in
condition handlers that will either drop you into a breakloop and enable you
to vivisect the program state, or consult the dynamic state and compute which
of several restarts to activate in order to transfer control to a path of your
choosing.

I'm banging up against HN's length limit, but the above, I hope, goes some way
toward answering to your question.

~~~
minerjoe
Very nice description of the power of the Common Lisp REPL.

Did you have the pleasure (?) of working on any of the lisp machines?

I got into Common Lisp in the early 90's and even then, with GCL and CMUCL, it
blew my mind at how much more productive I was compared to my years of C,C++
just due to the one fact that I was now freed from the edit, compile, run
cycle, let alone all the other benefits.

It's truly a joy. I don't have a full grasp of why others don't make the deep
dive. I suspect it just had too much a learning curve nowadays, with Emacs
being almost a requirement, and developers, like most humans, don't like to
slow down for a while while they learn before they speed up.

~~~
vindarel
FYI the Atom SLIMA package is very good: [https://lispcookbook.github.io/cl-
cookbook/editor-support.ht...](https://lispcookbook.github.io/cl-
cookbook/editor-support.html) Emacs is still the best, but not THE required
editor anymore.

~~~
minerjoe
Atom is OK, but many people bound to eventually be caught in it's local
maxima, such as needing to run in a terminal.

------
divs1210
The REPL has spoilt me. Working with languages without a powerful REPL, even
ones with a shell like JS/Python/Lua/Ruby feels like a regression comparable
to moving from zsh to windows cmd.

~~~
Angeo34
If you think zsh to cmd is a regression you should try out bash. It's vastly
superior to zsh in literally every regard. If you still aren't stratified use
fish.

Genuinely never got how people use zsh. It's the slowest and clunkiest shell
I've ever witnessed it's fucking slower than most electron gui software.

~~~
Natfan
Personally I've found zsh's features to massively outweigh it's "slowness"
(although I haven't really noticed zsh as "slow", per se)

`esc, esc` to prefix the line with `sudo`, better tab completion (both the
navigatable UI with arrow keys, along with the intelligent tab completion (I
type in "./llo" and it finds the file "./helloworld.sh")), combined with the
massive amounts of customization and modules you can install makes it a shell
killer. The only shell I've found that I like more is Windows' Powershell,
however that's mostly because I __love__ the Powershell language and syntax.

However I will admit that almost all of what I just complimented is part of
oh-my-zsh, which is a community add-on for zsh which makes the experience so
much nicer. In my time I've used bash, csh, pwsh and zsh and if I could, I'd
always use zsh for termanal interactivity and pwsh (Powershell on Linux) for
scripts.

------
siraben
Programming at the Haskell REPL is a great experience, whether it's if you're
exploring data, testing out a parser, or running an effectful computation with
a given state. On the other hand when a language is impure like Scheme or
Clojure I've often found myself needing to reload the REPL again and again to
get to a clean state.

~~~
thom
I think obviously it's much _easier_ to create a mess in Clojure this way, but
I think in most sane codebases the pure and impure stuff is quite neatly
demarcated. Generally people have learned to structure systems as some sort of
root data structure containing various components, which can be started,
stopped or reset at will. You have to put that in place yourself, but I've not
worked on a project where it's been an issue in many years.

For what it's worth, I have found dynamically loading new libraries at runtime
easier in Clojure than Haskell, which is another source of REPL friction for
me, although I rarely use the latter these days.

------
tgbugs
Here is a question that I have about Clojure and its REPL. I have tried 3
times over a period of a year or so to get it to behave like a common lisp
REPL and every single time I have hit a brick wall called project.clj and/or
deps.edn (which open a terrifying black hole to maven). My simplest use case
is to be able to call `(expt 2 10)` from a bare clojure install without
leaving the repl. As far as I can tell it is impossible to achieve this. I
finally gave up and wrote a gentoo ebuild to install the numeric tower just to
see if it was possible [0]. What I learned was that I have no idea how clojure
libraries interact with the JVM. `pomegranate` gets the closest but I'm still
fairly certain that you can't install that from a repl without resorting to
hackery [1]. I think I understand the tradeoff toward using project.clj and
deps.edn to create sane and static environments for a project, but the
friction is larger than nearly any other language that I have tried because
you are practically forced to create a project structure in order to do
anything.

0\. [https://github.com/tgbugs/tgbugs-overlay/blob/master/dev-
jav...](https://github.com/tgbugs/tgbugs-overlay/blob/master/dev-java/math-
numeric-tower/math-numeric-tower-0.0.4.ebuild) 1\. [https://github.com/clj-
commons/pomegranate](https://github.com/clj-commons/pomegranate)

~~~
lbj
Just install lein and do lein help new to see available templates. Or lein new
myproject to get the framework for your own project. Then Cd into that folder
and do lein run

------
siliconc0w
I'm a big fan of REPL programming and miss it a lot when I work with compiled
languages. There is definitely a 'right' and 'wrong' way to do it though. REPL
programming doesn't replace the need to write tests and it actually allow you
to write those tests faster as well as build more realistic faked versions of
upstream or downstream dependencies.

------
bonestormii_
Programming in the REPL is something I do all the time and generally enjoy,
but I sometimes feel like the actual design of the program then becomes too
focused around REPL usage. Too much abstraction can harm performance and waste
time. The REPL encourages this by making you think about the internals of your
program as an interface that will _actually get used_ , when in reality some
function may get called twice ever from within your own code, and isn't really
meant to be exposed. But because you are repeatedly invoking it manually via
the REPL, it feels like an interface worthy of considerable design.

Maybe it is, and maybe it isn't. I've just noticed this tendency in myself
when working in REPLs. Not every part of your program is an API.

------
EvanAnderson
I've enjoyed noodling around w/ Javascript in various simple REPLs. I love the
feedback, but it also feels a lot like using "ed" versus a visual editor. I
find myself writing code in a text editor, then pasting bits and pieces into
the REPL.

I'd love to have tooling that let me develop in a REPL, but also had a text
editor to let me edit objects / functions / etc in that manner, too.

~~~
adamkl
Well, with proper REPL integration, you never really type/copy/paste into the
REPL.

You write your code in a source file like normal, highlight what you want
evaluated, and have the REPL evaluate it.

Clojure has a great REPL because you are effectively working inside your own
codebase, as it runs. Its a strange idea to wrap your head around, but very
cool.

You can get something similar to this approach in JavaScript using Quokka[0].
It's not as complete as a Clojure REPL, but its still quite nice.

[0] [https://quokkajs.com/](https://quokkajs.com/)

~~~
EvanAnderson
I'll check that out. Thanks for the recommendation.

------
oweqruiowe
If anyone hasn't tried Clojurescript's browser REPL, it's super easy to use
now when using Shadow-CLJS for your project.

When you boot shadow up it'll create an nrepl server for you, you can just
connect to it and invoke `(shadow/nrepl-select :app)` and it'll latch on to
the running application `localhost:3000`. And it works really well, very
awesome.

------
keithasaurus
The clojure REPL is nice, don't get me wrong. But I think the reason people
rely on it more than in other languages is because of clojure's slow startup
time. If you could just make a change and run tests immediately, you'd see
much less REPL abuse.

~~~
Jtsummers
Common Lisp is not terribly slow to start, and people rely on its REPL when
programming in it. Even Python's REPL is quite popular, and it's not slow to
start either.

The REPL is relied on because it's useful for exploring parts of a system or
program. It's like being able to both dissect and vivisect the system without
having to go through all the normal issues of setting up a debugger and
instrumentation. The environment and program is just there.

~~~
3pt14159
I never really did much REPL programming until I started using pdbpp with a
bunch of aliases and customizations in pdbrc and pdbrc.py (the former does
aliasing[0] the latter does setup before boot) it makes iterating with a test
suite so much faster.

[0] For example:

    
    
        alias cc import pdb; pdb.disable()
        alias ppr pp response.json()

------
fmakunbound
Common Lisp REPLs and Smalltalk have ruined me for life as far as that goes.

~~~
tartoran
Can you expand on that?

~~~
minerjoe
Once you get over the learning curve, you really begin to see the productivity
gains in your day by day to the point that any language without those
capabilities fall short. Combine that with a world where most jobs seem to
place a higher priority on other things than programmer productivity such as
programmer fungibility, and your left with very few choices of places to work
that allow you to be at your most productive.

Say only Common Lisp had floating point arithmetic (or first class functions,
or...) , and most other languages only had integers. You'd probably feel a bit
hamstrun when tasked to do certain tasks in those languages.

------
riazrizvi
Am I missing something? This article seems very thin.

------
x87678r
Bob Martin was talking about this in May too. I think he decided to go back to
tdd. [http://blog.cleancoder.com/uncle-
bob/2020/05/27/ReplDrivenDe...](http://blog.cleancoder.com/uncle-
bob/2020/05/27/ReplDrivenDesign.html)

~~~
slifin
I knew his article would get misconstrued this way to clarify he almost
certainly will be using a REPL in Clojure (even running tests happens through
a REPL in Clojure) but I think what he's trying to convey there is that he's
not designing in the REPL but rather with TTD

Which honestly is fine but most people reading the article won't be in a REPL
based language like smalltalk or lisp so will just understand REPL bad TTD
good

~~~
smnplk
"rapid feedback is no substitute for software design and methodic problem-
solving." \-- clojure.org

they also mean TDD

