Read, Eval, Print: A First Look

With some mental gymnastics, the read, eval, print pattern drives most of our interactions with computers. A couple more contortions, and it sort of describes how we interact with each other in day to day life.

Don't get me wrong: I'm not trying to make some deep statement about life or people or society. My point is that this is how we often start off thinking about programming. Tell the computer what to do, let it do it, and then have it spit out results for the world to see. From the computer's perspective, it reads the instructions you give, evaluates them to produce a result, and then prints them out for you to read.

This is easiest to see in any of the numerous languages for which there exists an interactive interpreter, like Python. But I'm not here to talk to you about Python.

Okay, that's a lie. But the spotlight isn't on Python.

The Worst REPL

Today, I'm going to introduce what I rather unimaginatively call The Worst REPL, or REPL for short. REPL isn't really a general purpose programming language like Python. In fact, it's intended to be used much more like a POSIX shell. The difference, however, is that unlike a shell, which lends itself to executing executables stored on the filesystem, REPL is much more adept at executing Python functions.

A terrible analogy that I came up with 15 seconds ago is that REPL is to Python as a shell is to the operating system. This is a wildly inaccurate analogy with more holes in it than a sponge, but hopefully it holds water about as well.

Explain Yourself

Many who are comfortable working inside of a terminal emulator will agree that there exist tasks that are more suited to a terminal environment than a graphical environment. REPL grew out of solving one such problem.

I, as one member of a three person team, was working on a project that involved client applications communicating with a remote server. In any case, it eventually came time to test our server, and we were sunk. We had tested individual parts and we'd done some integration testing as well, but we needed to test the whole package from the client's perspective too.

Here was the problem: the GUI that we had could display what we needed just fine, it just wasn't yet capable of driving interaction with the remote server.

Forget testing, we didn't have a way for anyone to use the client even if everything other than the GUI worked flawlessly.

Enter REPL's Ancestor

From the beginning we had been entertaining the idea of having some scripting support, and that was reflected in our design enough for an early draft of REPL to emerge. I won't go into too much detail about this ancestor to REPL, but I will say the following: It was interesting enough and powerful enough that it spawned REPL, but also designed so horribly that I threw out almost everything when I started work on REPL.

Motivation

In that terrible hack of an interactive application shell I saw some things that worked well, as well as many shortcomings that I wanted to fix. So when I set out to create REPL, I had the fuzzy goal of making it "better," whatever that meant.

REPL isn't good for much on its own. In fact, I'll argue that if it is good for anything on its own, then I've probably done something wrong design-wise.

See, REPL's whole shtick is that it's embeddable into other applications as a scriptable driver for testing. At it's core, what REPL does is very, very simple: it forwards text arguments from the keyboard to functions written in Python. This allows users or developers to run Python code without worrying about too much syntax, and scripting support enables automation.

What struck me was that because execution was driven by a person hammering away on a keyboard, functions exposed through REPL were forced to serialize/deserialize any data that they exposed to the user. Since RPEL's precursor was embedded in an application whose purpose was largely to make API calls over a text based protocol, this forced serialization was immensely valuable because it made us think about API boundaries.

So to me, one of REPL's most fundamental uses is to force developers to think harder about whatever API they plan to inflict on themselves and on their users.

What Now?

REPL has a simple goal from my perspective, but it's vague, not terribly inspiring, and worst of all, not particularly useful - REPL won't make any design suggestions. Over time, REPL subtly changed directions and started to feel more and more like a shell (like Bash, for example). So while REPL has always been, and will always be, an embeddable shell for testing, it is now possible to write applications centered around REPL instead of the other way around.

Next time, I'll talk about what you need to know in order to plug your own functions into REPL, as well as what you'd need to know in order to build an application using REPL