The Joy of REPL

Back in the old days i was a macho C++ programmer, one of those sneering at Java or any other language but C, willing to manage my memory and pointers and mystified by the complexity of the template syntax (it was difficult and cumbersome, ergo it had to be good). Everyone has a past.

Things began to change when i decided to add Guile extensibility to GNU MDK. I was using the project as an excuse to learn everything one has to learn to write free software, from parsers with flex and bison, to documentation generators like texinfo and doxygen or localisation via gettext. Next thing was scriptability, and those days Scheme was still the way to extend your GNU programs (last time i checked, GNOME was full of XML, a windows-like registry and, oh my, C#… no Scheme (or good taste) to be seen).

So, when i first encountered Scheme i was high on static type checking, object oriented programming in its narrow C++ flavour, and all that jazz. I didn’t understand immediately what was so cool about having an interpreter, and defining functions without the compiler checking their signature at every single call made me feel uneasy. I was told that i still had strong type checking in Lisp, but that it is deferred to run time, instead of at the apparently safer compile phase. I didn’t get it. Thanks god, SICP was so fun that i kept on learning, and i kept wondering for a while what was so great about interpreters and dynamic typing.

Problem was, i was writing C programs in Scheme. In a compiled language (a la C) and, to some degree, in any statically typed one, your code is dead. You write pages and pages of inert code. You compile it. Still dead. Only when you launch that binary does it come to life, only that it lives elsewhere, beyond your reach. Admittedly, i’m exaggerating: you can reach it in a convoluted way via a debugger. But still. A debugger is an awkward beast, and it will only work with the whole lot: all your program compiled, linked and whatnot.

Enter a dynamic language. Enter its REPL. When you have a, say, Lisp interpreter at your disposal you don’t write your code first and load it later (that’s what i was doing at first). You enter your code piecewise, function by function, variable by variable at that innocent looking prompt. You develop incrementally, and, at every single moment, your objects and functions are alive: you can access them, inspect them, modify them. Your code becomes an organic creature, plastic. Its almost not programming, but experimenting.

Maybe you’re raising a skeptical eyebrow. Maybe you have one of those modern visual-something debugger that lets you modify your compiled code on the fly and continue running your code using the new definitions and you think that’s what i’m talking about… Well, no, sorry, that’s only part of what i’m talking about. To begin with, you continue executing your program. I can do whatever i want. But that’s not all. We are talking about a dynamically typed language. That means that me and my little REPL have much more leeway to modify the living code, and thus much more margin to grow up and evolve the code.

At the end of the day, dynamically typed languages give me freedom. Programming is a creative process and greatly benefits from that freedom. At first, abandoning the safety net provided by static typing was a little bit scary, but as i grew up as a programmer i felt more and more confident, and gradually the initially uneasy feeling morphed into joy. The joy of REPL.

Richard P. Gabriel has made a far better job in beautifully conveying what i’m trying to express in his excellent introduction to David Lamkins’ book Successful Lisp, entitled The Art of Lisp and Writing. Unfortunately, i haven’t found it online — you can read the first few pages in amazon.com’s “look inside this book” section for this book. And also in his essay Do Programmers Need Seat Belts?. Paul Graham has famously argued in favour of bottom-up development in many of his essays, and specially in Programming Bottom-Up:

It’s worth emphasizing that bottom-up design doesn’t mean just writing the same program in a different order. When you work bottom-up, you usually end up with a different program. Instead of a single, monolithic program, you will get a larger language with more abstract operators, and a smaller program written in it. Instead of a lintel, you’ll get an arch.

Finally, please note that i’m well aware that the static vs. dynamic typing debate is still open, and that decent type systems like those in Haskell and ML have, arguably, much to offer in the way to solid software engineering. Type theory has also a powerful and beautiful mathematical foundation. The above is just my gut feeling and current position on these issues, and i don’t pretend to have backed it with solid technical argumentation. Nor was it my goal. I’m more interested here in programming as a creative activity than as engineering.

Tags: , , ,

16 Responses to “The Joy of REPL”

  1. chris betts Says:

    Dead on. I have used Lisp (mostly autolisp and Visual Lisp) and Scheme for a long time (20 years), but I have only been writing “Lisp Programs” for maybe the past five years (since that light bulb came on and I embraced a functional programming “style”). Just like you said, I was using Lisp, but I was actually writing C or Basic programs. I understand the “right tool for the right job” argument, and I think it is valid, but I really believe creating code in Lisp is more rewarding). I’m sure most Lisp programmers have shared my experience of; creating a couple input/output functions, a few housekeeping functions, tackling a function or two to do the heaving lifting, and “all of a sudden” realizing that the fairly complex program your were considering a couple hours ago is done, there’s nothing left to do. I never get that “feeling” with any other programming language.

  2. Thomas DeBenning Says:

    On the mark! I come from a similar tradition as the author of the blog. I also had similar opinions and have recently come to the exact same conclusions. I have rediscovered the joy of programming that I had lost while swimming in the sea of boredom that is java. I came to lisp and scheme through Ruby. I didn’t stay long in Ruby because after reading more about it and its likeness to Lisp/Scheme I decided to explore them as well. Soon I dropped developing in Ruby. I know that IRB exists for Ruby and there is a interactive environment for Python. These languages though now seem like half measures on where I want to go and be expressive in what I do. I also believe that I am going to be more productive with REPL and Lisp ultimately.

  3. KBK Says:

    Of course everything you said also applies to Python.

    The problem with dynamically typed languages is you don’t discover the type mismatches until runtime. So if your coverage is poor when testing (i.e. you don’t test every possible pathway through the code) you may error out at runtime some day. Not good for spacecraft. Detailed unit testing is important for production code. Of course, C/C++ are weakly typed, so you can also write code which will crash at runtime because you made a type error via casts, pointers to void, etc.

    I heartily agree with you on the rest :-)

  4. pt Says:

    Your code becomes an organic creature, plastic. Its almost not programming, but experimenting.

    Yes, I can totally relate. I do exactly the same kind of development, errr.. experimenting when I’m using Ruby’s irb (interactive ruby shell). It’s a great way to develop code.

  5. whatevernot Says:

    Dumb question – you are happily programming in the environment, and the lights go out. Have you lost your state?

    How do you save “source” code?

    I’m interested from the angle of irb, as I like ruby. I still think in the mode of writing the source in an editor, checking it in, etc.

    I can’t seem to imagine this environment in terms of day to day work, esp with a development group.

    Can I get some insight from the pros?

    Cheers,

    parki…

  6. Ergin Says:

    The online version of David Lamkins book “Successful Lisp” can be found at: http://www.psg.com/~dlamkins/sl/cover.html

  7. PWBDecker Says:

    I’ve heard this story so many places, discovering joy of programming dynamically, incrementally, through an interpreter, using strong dynamic implicit typing, first class functions, mapping, etc. Unfortunately it doesn’t work both ways. When I was in high school and only knew toy languages like turing and basic, and I wanted to learn something with a little more capability, I skipped straight over the static languages and taught myself Common Lisp, because I was into AI and heard it was applicable. Well I did discover the joy of using lisp, after I rewrote a program to invert matrices from turing (where you couldn’t pass arrays of variable size as parameters) in lisp, it went from 4 pages to 20 lines of code and could invert matrices of any size without modifying the code (becuase it was recursive of course). Well yes I discovered the joy of lisp programming, and of course none of my static programming friends would believe me, and at the time I was a total paul graham convert, writing everything in lisp style. I would only use recursion, no iteration, functional abstraction for everything. But this leads to incredibly inefficient code.

    The hard part came later when I had to make the long journey BACK to statically typed languages as I tried and tried to learn C/C++, it took me years to get over the memory management. Pointers aren’t so complicated, but learning all about the stack, heap, deallocation, why I couldn’t pass one array around but another I could. I still can’t stand to program that way. A C++ programmer friend of mine calls dynamic typing ‘lazy programming’ as thought it were something to be ashamed of. I prefer to think of it as powerful programming, since I no longer have to worry about accidentally causing memory leaks or buffer overruns etc. The fact is computer hardware is ridiculously fast now, but code is still incredibly inefficient beucase you have someone trying to write a little pdf to html convertor but accidentally overwriting some buffers or something and bringing the whole system down when it should’ve only been a few functions in a dynamic language. I’m hoping for a shift back to all managed code like microsofts singularity or more like the smalltalk/lisp machine days of yore.

    Anyways another point I wanted to make was that I started on Common Lisp, learned the joys of auto memory management, typing, checking, etc, then finally taught myself C/C++, manual coding, etc, and I now live somewhere in the middle, with Python. Yes I love programming in Lisp, but there’s plenty of things you just can’t easily do in it. Python offers many of the same dynamic features of Lisp, and although it misses alot of the cooler things like lexical scoping (I’ve always missed Let, lisps greatest feature), macros, blocks (yes lisp has blocks, common lisp has pretty much every programming technique includeded in it like coroutines), but it’s made up for by the ease of use of its runtime and libraries, and you can find a python shell almost anywhere. Not to mention the plethora of awesome libraries like pygame and pyopengl. In fact my biggest gripe with python is the lack of efficient compilation, which has begun to come to light with psyco and pyrex, but what I really wish for is a compiler engine similar to common lisp where you can set flags for how much debug info, type safety, bounds checking, memory foot print, etc you want your code to produce, and if you shut off all the things you don’t need (say once you have checked your algorithms thoroughly) then you can get incredibly efficient machine code that begins to rival C++ without having to write 10x as much code just beucase you wanted to map a function over a list.

  8. Faried Nawaz Says:

    whatevernot — it depends on the environment. If you use emacs as your editor, for example, you’ll probably have a buffer or two open with your code, and an “inferior process” buffer that communicates with a python or lisp or ruby process. You type in a function or whatever in your code buffer, and hit a keystroke to evaluate it in the external python process. You let emacs handle the file autosaving/etc, or you remember to save periodically.

    Most lisp and some scheme environments also let you save the entire system’s state. So, when you come back to work on Monday morning, all the code you typed in to the system on Friday’s already in there — you don’t have to reload any files or anything.

  9. programming musings » Blog Archive » Persistent Joy Says:

    [...] In the comments section of The Joy of REPL, a reader is posing an interesting question: how do i make my joy persistent? Or, in her words, Dumb question – you are happily programming in the environment, and the lights go out. Have you lost your state? How do you save “source” code? I’m interested from the angle of irb, as I like ruby. I still think in the mode of writing the source in an editor, checking it in, etc. I can’t seem to imagine this environment in terms of day to day work, esp with a development group. [...]

  10. chewie Says:

    PWBDecker wrote, “I would only use recursion, no iteration, functional abstraction for everything. But this leads to incredibly inefficient code.”

    This is where Dynamic Programming comes in to the picture. Inefficient code is not solved by strong typing, but by better algorithms. A Dynamic Programming algorithm uses recursion to find solutions, but saves those solutions for later recall. See http://en.wikipedia.org/wiki/Dynamic_programming for more details.

  11. KBK Says:

    Steele proved decades ago that if a recursive algorithm was ‘tail recursive’ (i.e. the last thing done in the code was to recurse) then the cost of that algorithm in both time and space was equivalent to a looping version. The compiler can transform the recursive algorithm into a looping version where the loop variables are patched in each pass. Modern lisps and schemes have ‘proper tail recursion’, that is, byte or native code compilers which handle this transformation.

  12. - d - Says:

    Top 3 reasons

    Here’s a list of features of Scheme that won’t impress you, if you’ve been using Ruby/Python:

    “Scheme has a REPL.” (nevertheless, go read all about it).
    “Scheme is dynamically-typed.”
    “Scheme has a garbage collector.”

    What compels pe…

  13. programming musings » Blog Archive » The Art of Lisp & Writing Says:

    [...] I wasn’t aware of The Art of Lisp & Writing, by Richard P. Gabriel, being online. I like this essay so much that it justifies its own entry. As i mentioned in The Joy of REPL, this was written as the foreword to Successful Lisp, a pretty nice book on Common Lisp, but Richard’s thoughts apply to any Lisp and many other programming languages. [...]

  14. Stephen Bradley Says:

    Richard P. Gabriel’s essay:

    http://www.dreamsongs.com/ArtOfLisp.html

  15. Roman Taycher Says:

    Two points.
    First a mention for Smalltalk in which you can both code in the debugger and evaluate anything at will (and if an excpetion gets called it asks if you want to open a debugger) and inspect the resulting objects.

    Also statically typed languages can have repls (although most if not all of these are not nearly as useful (or have as full support of the language as lisp repls). c-sharp(mono version although MS says they will have one in the next version), scala and haskell have repls, there is even a c/c++ repl(called cint).

  16. withoutasppon Says:

    I still have yet to use a serious application written in any of these tard languages


Leave a Reply

Fill in your details below or click an icon to log in:

Gravatar
WordPress.com Logo

Please log in to WordPress.com to post a comment to your blog.

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 26 other followers