8 ms·
REPL Debugging: No Stacktrace Required (2017)
- shivekkhurana 7y agoREPL is a killer Clojure feature that nobody (outside the ecosystem) talks about. Probably it's hard to comprehend what developing in a REPL feels like, majorly because no other commercial language has a REPL as powerful as Clojure. I gave a talk[1] explaining the REPL and most people in the audience (including senior Java, C# and Python developers) had never seen something like that before. REPL is the reason why I (and perhaps other Clojure devs) endure the pain around Clojure tooling, demand, supply and ecosystem in general. [1] https://www.youtube.com/watch?v=Bs44qdAX5yo https://www.youtube.com/watch?v=Bs44qdAX5yo
- snorremd 7y agoEverytime I've singled out the REPL as why I like Clojure so much when explaining why Clojure so great to my friends they seem to mention that other languages have repls too. Like F# or JavaScript. When I counter that Clojure's REPL is connected to the running app instance they are developing I don't think they really understand. Perhaps this is one of those things that you just have to try out to grok.
- wtf_srsly 7y agoAs is javascript. Have you ever tried debugging an application with Chrome ? I frequently use the "pause on exception" feature of the debugger or also place breakpoints strategically and then use the console as REPL for further debugging.
- ss3000 7y agoI think the "_running_ app instance" is the key distinction here. Breakpoints require halting your system, so while you can inspect the system's state, you can't meaningfully alter it as you could with the kinds of Clojure REPL workflows talked about here. Another limitation is that you can't really inspect parts of your system outside the context of the currently running function where the breakpoint was triggered. I think debugging with state-preserving hot reloading in UI development is probably the closest analogue I've encountered to debugging workflows with a Clojure REPL, though it's still nowhere near as flexible.
- lispm 7y ago> Breakpoints require halting your system, so while you can inspect the system's state, you can't meaningfully alter it as you could with the kinds of Clojure REPL workflows talked about here. Fix and continue. Various language implementations provide that.
- kqr 7y agoOne difference is that you might then be debugging compiled, possibly even modified JS. The Lisp REPL deals in the original Lisp source code.
- S4M 7y ago> I gave a talk[1] explaining the REPL and most people in the audience (including senior Java, C# and Python developers) had never seen something like that before. I find that quite surprising, as I use the REPL a lot when coding in Python.
- mtreis86 7y ago> no other commercial language has a REPL as powerful as Clojure Except for other Lisps like CL
- lispm 7y agoSmalltalk.
- shivekkhurana 7y agoMy use of the word "commercial" is not apt. I meant to say "mainstream" languages.
- lispm 7y agoThat would exclude Clojure, too.
- yogthos 7y agoSeeing how Clojure is actively used at places like Apple, Amazon, Atlassian, and even Walmart where software development isn't even their primary business, I think it's pretty safe to call it mainstream.
- lispm 7y agoI would call languages like Java, Javascript, Python, C++, C# 'mainstream'. But not niche languages which have 1/100ths or less of open positions. Monster lists 68000 positions after a search for 'Java', and 180 for 'Clojure'.
- yogthos 7y agoI would call any language that's actively used in the industry with a large and active community mainstream. Restricting the term mainstream to a handful of most used languages is pretty silly in my opinion.
- jcadam 7y agoWhen I started learning/using Clojure, I didn't use the REPL much and kept on working in the traditional way: Write code, compile, test. Repeat until it works. It took some time to break my old habits and start using the REPL. It's unfortunately made me a bit lazier writing unit tests :), as I can hammer on a piece of code until I know it works - and small, deterministic functions tend to not break once you get them working. So much of my test code is integration tests. Nowadays, when I have to work in Java (or Scala, Javascript, Python, etc), I seriously miss the Clojure REPL. Though Clojure (and Lisp in general) has definitely affected the way I write code in other languages.
- Scarbutt 7y agoA good REPL is nice, but its hardly a killer feature or a big productivity boost. If Clojure didn't have a REPL it would have been completely dead by now cause its startup time is really bad. Clojure needs to have a REPL in order to survive (which is barely doing). Programmers are equally productive[0] (or way more because of their big ecosystems) in languages that have a fast code-run cycle. [0] https://groups.google.com/forum/#!topic/comp.lang.lisp/L5dZ-j6Id-s%5B76-100%5D https://groups.google.com/forum/#!topic/comp.lang.lisp/L5dZ-...
- deleted 7y ago[deleted]
- yogthos 7y agoREPL driven workflow allows me to put the application in a specific state, and then continue developing features against that state. If you have to restart the application each time you make a code change then you have to rebuild that state each time. This creates a much slower feedback loop, especially when you're working on large applications. Furthermore, the REPL is a fantastic tool for troubleshooting live systems in production, and in some cases even patching them with zero downtime. I don't know a single person who's worked with this workflow on a serious project and would want to go back to compile/run cycle afterwards. Meanwhile, Clojure leverages host ecosystem getting all the same benefits as any other language running on it.
- wglb 7y ago>Programmers are equally productive[0] (or way more because of their big ecosystems) in languages that have a fast code-run cycle. I would disagree with this. I feel much more productive in Lisp than, e.g. go or C or C++. In Smalltalk, the productivity was so great that I was dead tired after 8 hours, as it was all thinking and effectively zero compiling.
- dimitar 7y agoI was talking with a Data Scientist friend abiut what I love so much about Clojure and it was largely about the REPL. To him it sounded like nothing special - trying expressions in a prompt is hardly new or original and he does all the time in R. Which I thought is actually a really good selling point for Clojure - you get to do the really high-level data manipulation you do in R, Mathematica or even Python in a language that is compiled, good with concurrency, probably embraces your platform of choice and is also used for the frontend. What makes it different for me is two things: - the functional style mean that many things are much easier to track in a REPL - you don't need to use a stepping debugger to get to the troublesome value of i as often. - Structural editing using parinfer or similar is fun. Overall I'm not convinced that the Clojure REPL is that unique, but combined with the rest of the ecosystem it is pretty sweet.
- ss3000 7y agoI think the major difference between the Clojure REPL experience and most other language's REPLs that I've worked with is the fact that Clojure REPLs can connect to a running stateful system (or a situated program as Rich Hickey coined it), and allows you to explore and manipulate the system's state and behavior dynamically at runtime, which makes it an incredibly powerful tool for building and debugging such a system. Most REPLs I've used in other languages are strictly for evaluating individual commands in an isolated, stateless manner.
- barrkel 7y agoRuby's REPL, and particularly when enhanced with Pry (binding.pry), can function like this reasonably trivially. You can't connect to an existing system like attaching a debugger, but you can make a call to binding.pry or binding.pry_remote depending on a parameter. Usually Ruby is used with Rails, where in development mode modifying the source and repeating the request is just as easy.
- emidln 7y agoIn Python, twisted.conch provides an ssh transport and a repl implementation which is trivial to hook up in a live system. The ecosystem doesn't really support the use case though, so you end up building all tooling from scratch (tmux plus vimux helps a lot here). You also have to structure your code in a somewhat unnatural way for python, like using a dependency injection system to reload and trying to approximate clojure.core/in-ns.
- lispm 7y ago> At this point it is pretty clear that calling first on a number is not valid. A quick doc check will show that first is for collections I could just have the compiler explain the problem in the REPL, for example with SBCL: * (defun foo (n) (cond ((> n 40) (+ n 20)) ((> n 20) (- (first n) 20)) (t 0))) ; in: DEFUN FOO ; (FIRST N) ; ==> ; (CAR N) ; ; caught WARNING: ; Derived type of N is ; (VALUES ; (OR (DOUBLE-FLOAT (20.0d0) 40.0d0) (SINGLE-FLOAT (20.0) 40.0) ; (RATIONAL (20) 40)) ; &OPTIONAL), ; ; conflicting with its asserted type ; LIST. Then there is less need for manually searching for problematic expressions in the code. See http://sbcl.org http://sbcl.org
- bmn__ 7y agoDid you miss the premise near the beginning of the article? > I am going to throw away all the potentially useful information
- lispm 7y agoFrom the article: > read stacktraces and add instrumentation for tracing. In this blog post I am going to debug his example program without using such tooling, relying only on the rapid feedback loop provided by the REPL One does not need error reporting, stacktraces or add instrumentation, while running the code. SBCL gives the clue without any of that, before (!) the code runs. In the REPL. The incremental compiler makes some of that manually searching for type problems in the code unnecessary, while supporting REPL use.
- slifin 7y agoWhen talking about the Clojure REPL I think a lot of people forget that the language matters a lot Clojure focuses on being dynamic, to give an example if in PHP you wanted to attach an interface to a class without restarting the REPL I don't think you could In Clojure that's supported via a function call
- jedberg 7y agoFun REPL story: Reddit was originally written in LISP, so you could also manipulate the live running code with the REPL. Sometimes Steve would do that to add a new feature or change some broken code. The danger was that if you didn’t copy/paste the fix back to the saved source, the problem would return when the app restarted!
- lispm 7y agoYou would drive the REPL from the editor. Change the code in the editor and evaluate into the REPL. Still you need to try out if the error in a fresh build is still fixed after that.
- eadmund 7y agoIt'd be pretty simple — albeit so very much a bad idea — to run the REPL from a stream which saved everything typed in the REPL to a log read in at startup. A fancier version might allow log editing. A really fancy version might save everything to a log and offer commands to view expressions in the log & copy the desired ones to the startup file, or another file. Or one could just remember to move corrected source back to the right place. This is probably somewhere where a Smalltalk image-based browser would be preferable — it would/could unify the REPL and editing source.
- agumonkey 7y agowhat lisp did they use ? SBCL ? also I believe lisps have image patch storing facilities..
- fmakunbound 7y ago> Broken! HaHa! I think this is about equivalent to the error messages one already gets from a typical Clojure REPL session, so no loss of potentially useful information, after all.
- elcomet 7y agohow do you explore the running code in a repl, if it was modified while running ?