REPL-Driven Development (2017)
github.com
github.com
For example, if you're editing a method called "fooBar", you can just type (in the same input field) "self new fooBar" ("self" is bound to the class being browsed) or, if it's a class method, "self fooBar", highlight it, and then type the appropriate shortcut (like Cmd+d in Pharo) to evaluate it.
This is useful for documentation. You can have a method begin with a comment that shows examples, which a person browsing can highlight and evaluate, and also experiment with.
This objection is subtle. The "P" in REPL of course does not simply mean to emit some printed representation of the result of the last evaluation, but to emit a specific representation that a corresponding operation, (read), can comprehend.
In that sense, no non-Lisp, including Pharo, has a true "P" and a true REPL. (Though many objects in Pharo do have such printed representations).
> Running code from a text buffer in an editor is one way to interact (many Lisp tools do that),
Like Emacs and SLIME. But having used both, I prefer the Smalltalk browser-based IDE approach. The browser makes code navigation much easier, and it saves you from having to type out a lot of class and method creation boilerplate code like the kind you end up writing when using Emacs and CLOS. Maybe LispWorks (which I've never used) is that kind of IDE, but for CL?
> I would be surprised, if Smalltalk did not have that somewhere, too. The REPL has a visible I/O history and is not conflated with other text input fields (like a function being edited).
Repeatedly print-evaluating (Cmd+P in Pharo) code in a workspace/playground is actually the closest I think most Smalltalks come. A command prompt-style REPL isn't as useful in a fully graphical environment. You could easily create one if you wanted, though, and text-based Smalltalks like Gnu and Amber have one.
However, the inspector in Pharo can function as a nice graphical REPL. You can enter code in an inspector pane, evaluate it with Cmd+G, and the result will appear in a new inspector pane to the right of the current, and you can cycle back and forth through evaluation panes.
On the Symbolics Lisp Machine they then added a facility where READ can read arbitrary things, since each thing you PRINT has a printed representation/view, which stays connected with the original object. Thus you can enter non-text things or non-printable things in a REPL.
> Maybe LispWorks (which I've never used) is that kind of IDE, but for CL?
Not really, it is not browser based in the sense of Smalltalk. It has browsers for things like classes, but you do no in-place editing.
Apple Dylan or Interlisp-D were that way. Interlisp-D is a similar managed source system like Smalltalk, but with Lisp representations and structure editing.
> However, the inspector in Pharo can function as a nice graphical REPL. You can enter code in an inspector pane, evaluate it with Cmd+G, and the result will appear in a new inspector pane to the right of the current, and you can cycle back and forth through evaluation panes.
LispWorks has something where you have a REPL and an inspector in a window. Each evaluation result in the REPL goes into the inspector and you can cycle between inspected values back and forth.
One can also link windows in LispWorks, for example a REPL with an inspector.
One can choose to evaluate, or evaluate and print.
The 'L' is the whole Smalltalk environment, as anything that changes the environment is kept in memory or saved along the image on exit.
A Lisp like REPL is available as Transcript windows.
A transcript window is usually a text output window, more like a console output. I'd say the Workspace window is slightly similar to a REPL. But it still does not work like the usual Lisp REPL, where you type to the tool usually textually at the bottom and get the result displayed there. With Smalltalk I usually type to an editor Workspace window and REPL I/O does not need to have a sequential order.
Still, it looks pretty much to the Lisp Machine demos I know of.
I've lately been working in Python, and even with IPython/Juptyer the workflow isn't quite as magical as Clojure's.
It’s also kind of weird that a lot of other languages do not have this
Sadly, it's only at $31 per month
Also the cider environment is kind of brittle with seemingly lots of components, all of whose versions needs up to align for the magic to work.
And another issue with clojure and leiningen is the almost impossiblity of using local jars as dependencies, without setting up local maven repositories. Too much work for what I was doing for fun.
Often times I run a long-ish/effectful function (web request, network request, etc.) and wonder what the value was somewhere in the function, but unfortunately I didn't have the foresight to do a (def -my-value value) ahead of time.
With gumshoe, it's all automatically captured, so I can pop the values into my repl and play with them to understand what happened.
A few examples:
user> (deft add-ten [num]
(+ num 10))
#'user/add-ten
user> (add-ten 2)
12
user> -add-ten-num
2*
user> (deft destructure-example [{:keys [a b] :as args}]
a)
#'user/destructure-example
user> -destructure-example-a
1
user> -destructure-example-b
nil
user> -destructure-example-args
{:a 1, :c 2}
Anyway, it's quite surprising how often this saves my bacon. And it pairs very nicely with cider indeed!That said I find IPython supports everything you’d want to do in Python save multithreaded profiling for which Yuppi is useful.
Did/do people really develop applications interactively in VS other than in F# Interactive? I've been using VS a long time for VB6 and C#, only in edit/compile/execute-debug mode.
Visual Studio has been around since 1997 (which is pretty cool!). Emacs has been around since 1976, although I don't know how far back it got a decent Lisp development environment. Early 80s, maybe?
Interlisp development environment: early 70s.
Interlisp-D: Early 80s.
MIT Lisp Machine + Zmacs: end 70s.
Macintosh Common Lisp, LispWorks, Allegro CL, and many others ...: mid-end 80s.
GNU Emacs based Lisp development: end 80s.
--
[0] - https://xkcd.com/297/
But there are a lot of kinks with REPL:s that the talk doesn't detail. Most of them have to do with code reloading and all the corner cases that can lead you into. For example, suppose you have started a thread which calls the function "foo" from within a while loop. Then you recompile "foo." Now, what should happen with the thread? Should it switch to the new foo or keep calling the old one? What if you remove the foo function from the module in which it was defined? What if you have a class and you change its definition. What happens with old instances? What if you recompile the REPL? Recompile the compiler?
Solving issues like the above is really, really hard. Especially if the solution has to be both efficient and also work as the user would expect.
I think REPLs might be why I've never really got excited about IDEs. When you're working in a REPL you can answer questions about your code instantly without needing smart autocomplete or context-sensitive help.
REPLs are nice, don't get me wrong, but they are by nature single entrance, single exit. You are basically riding shotgun on a single unit test. You get a great view along the way, but the problem solving doesn't scale, nor can it handle situations where you need to consider multiple paths through the code. Writing a good test suite, and knowing just where and how to place debug trace statements are two of my best problem solving skills.
That lets you work line-for-line through your code, inspect and analyze each step as needed, edit parameters as wanted, restart and do clean runs through calculations using custom and third party libraries, and also interactively execute any tests/specs you have defined. It's a very tight feedback loop that doesn't compromise any of the long term artifacts you might want in a serious app.
In conjunction with .Nets extension mechanisms and some F# language features the setup lets you fire up a basic script, replace/extend anything from your object graph with new code, write accordant tests, and execute any or all parts of the test as desired in an interactive REPL-like session for problem solving and debugging: all in the same file :)
This flows really nicely with the single pass compiler, keeping things nice and clean so they integrate into the main app once exploratory development is done. Semi-serious typing, functional composition, and dynamic exploration -- it ain't bad.
A REPL makes writing both code and tests easier.
Where a REPL starts to fail, I find integration tests start to shine and vice versa.
The Common Lisp REPL automatically binds the last expression evaluated to the variable "+". It also automatically binds the value returned from the evaluation of the last expression to the variable "*".
I write code and develop interactively at the REPL with the package under development loaded/running. When the value I expect gets returned from the function or form I'm developing at the REPL, i just evaluate the "test" function (or a variant thereof if extra specificity or features are wanted such as names, doc-strings or tags, etc.), and the forms and expected values are packaged into a test and added to the projects' test repository.
Pretty much all the benefits of TDD, without writing tests up-front or wanting to do red/green (i did allow for the option, but i practically never do in practice), because they're an almost costless artifact of just developing now...
I have my IDE setup with some scripts to copy a database from production. Set some breakpoints and press the play button and I am debugging.
With A REPL first I need to do a load of import statements. Then populate my objects. Then get started with the actual debugging. I personally don't find it anywhere near as efficient as an IDE that has been setup. Plus with the IDE I can stop at a certain point in the code, have numerous variables populated then run "evaluate" in PyCharm, which gives most of the benefits of a REPL as far as I can tell.
Admittedly the IDE does take a fair bit more effort to get to a state where it is set up to be useful, but dealing with the whole system as opposed to a small part of it is incredibly beneficial for development. Though I guess a lot depends on the type of problem you are solving.
No, you absolutely do not. You just need to click around until your code hits the point in the code (or, ideally, run an integration test that gets you to that point) where you want the ability to run methods, inspect objects, etc.
Just make sure you've shoved an import IPython ; IPython.embed() in there and you're good to go. No additional imports necessary.
I agree that having your environment set up with production data (or as close an approximation as you can get) is a good idea, but I'd rather script that with a test framework where it can be used for regression testing rather than bodge it together using an IDE.
This is generally a lot less effort than populating objects in the REPL to reproduce the same set of conditions.
For me, it's way way easier the other way around.
Or did you think that once they're there it would still be a lot of effort to use them to populate objects?
But you are welcome to do what works for you. Maybe you work on something more suited to your approach. My approach works better for what I do.
That said, a high level 'unit test' (e.g. one that manufactures a request and checks its response) is often realistic enough and works pretty well with IPython.embed().
Can't you just run those scripts as the first thing in your REPL session?
Having an IDE setup is pretty essential to my job, so I am going to need that for debugging certain errors anyway. Once that is setup, I rarely see the need to start scripting things for a REPL as a debugger feels far more useful to me.
That being said, why do you find iPython so much better than Jupyter? I write probably 80% of my python code in Jupyter and cannot imagine coding without it.
But it's also just not a nice workflow. Projects are not linear. I tend to work on a function and get it working in the REPL. Then build up the program by combining together higher level functions. How am I suppose to test functions in Jupyter? Write the test then keep evaluating it and then delete it later?
I use it to make very pretty PDFs for bosses who want executive summaries, and I've started investigating using it to give lab talks so we can hack on the data together if i have to.
I don't think it's a particularly useful development tool.
I can't think of any good ide (dating back to vb6 20 years ago) that doesn't have one.
But, as I said above, it's not explicitly labeled as such.
> But I could imagine if you were coming from Common Lisp, or something like that, and saying "that seems like a wart." And it is a wart that we lovingly embrace, for the mighty power of having access to the whole JVM ecosystem.
There's Armed Bear Common Lisp[0], which is a Common Lisp on Java, which gives access to the whole JVM ecosystem. Dunno how it handles classloaders though.
I stopped at about 15. REPLs are incredibly useful.
I even find Jupyter notebooks get this a bit, when people eval cells out of order..