8 ms·
> When you have a running program you can compile functions, redefine classes, etc. all while the program is running. You are changing the internal state of the
by Hirrolot 3y ago
> When you have a running program you can compile functions, redefine classes, etc. all while the program is running. You are changing the internal state of the image.
This can surely be convenient in certain cases, however most of the times I find myself playing around with unit tests rather than with a single running process. Unit tests are small and fast so I don't even notice any inconvenience with the traditional compilation approach.
- jgoodhcg 3y agoI work with clojure and test driven development is not nearly as productive as repl driven development imo.
- marcosdumay 3y agoI'll have to agree here, with the caveat that this applies to functional code. For side-effect heavy code, a repl is not nearly as productive as good tests and a debugger. (What is interesting is that people tend not to test or check manually their code's side effects, so a repl is the best option for almost all the debugging that people actually do.)
- jgoodhcg 3y agoI worked in Kotlin and Java for awhile and the closest thing I had to a repl was stopping the debugger and running arbitrary single lines of code in the context I paused. It was awful compared to the clojure repl.
- ravi-delia 3y agoThere's a place for both even with a REPL I think. Sometimes when I'm tracking a bug down or writing a new function against an old one, I find that I'm writing little one-off functions or worse, replicating a function body line by line in a let block to simulate arguments. Once I opened up a project and realized I wanted one of them, but it was lost when the REPL closed. I literally got as far as opening another file to stow these little utilities before I realized I had reinvented bargain-bin testing. My dream is still to come up with some ergonomic way of blending the two. I want to have tests written, but swap out the thing they test live in the REPL. Or register new one-off tests from the REPL for things I don't think will be useful once things are set in stone. I've heard one of the several billion testing frameworks for common lisp does something like this, but I haven't checked it out yet.
- jgoodhcg 3y agoI almost always do my repl work in a source code file. That way I never lose it when the repl closes and I can copy it into a test when I know what’s going on.
- ravi-delia 3y ago[see cousin comment for my admission of stupidity]
- freilanzer 3y ago> Once I opened up a project and realized I wanted one of them, but it was lost when the REPL closed. You don't type directly in the REPL most of the time. Send lines and functions to it instead.
- ravi-delia 3y agoOhhh, I wondered why people were so hyped about that! In my head I rounded it off to not wanting to recompile the whole file- I should have realized how dumb that was. This actually makes a lot of sense. When I helped a friend set up Calva, a part of me was really just assuming it was misconfigured- but no, it's designed to facilitate this kind of editing. Though, I must ask, is it really that much better? I do keep functions around if I think I'll have a use for them again- the vast vast majority really are one-offs. Plus, most of my REPL usage is iterating on an expression. Obviously it's handy to edit it in place, but it's nice having multiple versions, even multiple trees, without having to relocate a cursor or undo unrelated changes.
- thorondor83 3y ago> Though, I must ask, is it really that much better? Yes, it is. > Obviously it's handy to edit it in place, but it's nice having multiple versions, even multiple trees, without having to relocate a cursor or undo unrelated changes. You can do both.
- bloaf 3y agoI think that is the reason jupyter is as popular as it is.
- agumonkey 3y agoI'm often wondering how to couple both. Explore freely, extract more invariants and constraints as types/tests. Iterate.
- jgoodhcg 3y agoSaving repl output is a great way to make tests. It’s often the stuff that is confusing and likely to change that you exercise in that space so if you take what you find from there and make a test out of it someone will likely benefit later.
- fnordsensei 3y agoMy main problem is with the “driven” part of “test driven”. I’m fine with aiming for pervasive coverage etc., but I disagree that tests are this amazing software design tool that the test-driven ethos seems to put forth. There’s something off in the cart vs. horse equation with that. I also work in a REPL. For me, design usually starts well before code. Then the REPL will take me towards defining behavior via understanding and exploring particulars around a solution or set of alternative solutions. Then as some final step, I will assert that it does what it should do, and guard against possible future changes violating some assumption.
- geophile 3y agoDepends on what you mean be effective. TDD is great if you want to be sure you don’t break things in the future. Repl seems better for getting the next thing working right now.
- jgoodhcg 3y agoThe repl is great for understanding something quickly and easily. It works for big new parts of the code base and small things that you just need to be reminded about. The nice thing is, if you save your repl output, you can really easily create tests from it.
- coldtea 3y ago>Unit tests are small and fast so I don't even notice any inconvenience with the traditional compilation approach. Depends on the programming language, how much state they need to build up, and so on. And they're still slower than just running the actual live code anyway.
- mrkeen 3y agoPossibly, but the unit tests are reproducible, committable code. They're like Dockerfiles for your REPL session.
- User23 3y agoOne never notices the inconvenience of not having something one is unaware of. This is the biggest challenge for answering “why Lisp?” It’s different enough from the programming that most people are used to that it rises to the level of a radical novelty, with all the explanatory difficulties that entails. In fact, it’s a defining characteristic of the radical novelty that it can only be understood experientially. And even then experience is merely necessary, but certainly not sufficient.
- ravi-delia 3y agoIt's possible that you have experienced an enlightenment that I have yet to, but ultimately I like lisp because parenthesis are pretty, I hate remembering syntax, keywords/symbols are nicer than immutable strings, and typing out commas makes me sad (not that you'd know it from the way I abuse them in this comment). I mean, lots of languages have REPLs now- people get that they're really useful! This isn't secret knowledge, the pros and cons are on display. Macros are nice (though of course Ruby has them too), but I'm always surprised by how far people get with method call chaining (hell they have monads over in JS land now). The experience of writing lisp is very similar to that of writing Ruby, or even Javascript- really any dynamically typed language with good enough lambda support. It's by no means as strange as an array or concatenate language. It would surprise me very much if the reason you and I like lisp, or other people don't like lisp, was anything other than taste!
- User23 3y agoNothing you say is in any way incorrect and I agree with it. However, for me, the experience of writing Lisp is very different from that of writing Ruby, or Perl, despite the latter languages having a great many Lispy features. In fact I jokingly call Perl a Lisp-6ish, because of how typeglobs let you mess with the symbol table directly and it has separate namespaces for SCALAR, ARRAY, HASH, CODE (I think that's the subroutine namespace), and a few others if I recall correctly. It's been a bit since I wrote any XS which is pretty much the best way to grok Perl internals. And that difference comes down to interactivity. I totally agree that REPLs are great and can bring a measure of interactivity to other languages. Except I barely ever use the REPL when I'm writing Lisp. I just evaluate the current form directly. Haven't you ever wondered why DEFPARAMETER and DEFVAR both exist? Having both makes no sense in a world where the Common Lisp REPL as equivalent to, say, irb. I'd say that notebooks are where non Lisp languages are coming closest to a kind of Lispy/Smalltalky interactive programming environment. And yes you can do some very very clever things with the JS console in a browser that are in tune with the Lisp way. And that's no surprise since JavaScript was originally a Lisp DSL and that very much shaped its philosophy. Interestingly enough the Lispiest non Lisp dev experience I've professionally had is writing java 8 using Eclipse on the JVM treating the unit test runner as a kind of C-x C-e. It's no wonder Clojure was such a good fit for the JVM.
- ravi-delia 3y agoI've definitely come around to unit tests, but I think that whether they're good in all circumstances is a matter of taste. Obviously you want to have good test coverage by the time the codebase is starting to solidify- I assume there are people that would argue against that but they would be wrong. Writing tests at more intermediary stages is not as much a matter of best practice, but I see know the appeal. At some point I started writing one-off functions to rerun the same code over and over in the REPL- that's when I realized it was time to start writing tests even if the API wasn't finalized. But full TDD is a matter of taste. There are people that like to have a really good idea of what they're getting into, and it seems like TDD works well for them. I myself have trouble. When I try to write tests first, I wind up paralyzed by making decisions without knowing the costs and benefits. That's where the REPL comes in handy for me- figuring out what shape I want my data to be, double checking edge cases faster than I could reference the documentation, and playing with new building blocks.
- dreamcompiler 3y agoI find the repl invaluable for writing unit tests. I think about what I want to test, try it out in the repl, refine it for better generality, and then basically copy/paste it into a file full of unit tests.
- Hirrolot 3y agoGood point, gotta try it.
- JenrHywy 3y agoYou can get a very similar experience with hot-reloading. In C# my current test-writing workflow is: 1. write the basic test scaffolding 2. debug, stepping until I get to a point in the test that needs to change 3. modify the test code (and save, which hot-reloads) 4. move the execution point to before my change 5. GOTO 2. There are some changes that can't be hot-reloaded, but I've been surprised and how flexible it is.
- vindarel 3y agoBest of both worlds: write unit tests with an interactive debugger o/ Tell the test runner to not catch errors and let them pass through up to the debugger. Have a test fail, get the debugger, go to the buggy line (without quitting the debugger), fix the bug, compile the function with a keystroke (yes, one function), come back to the debugger, restart not the full operation, but the function call, the debugger frame where the error happened, and see the test succeed. You ran the test exactly once and fixed everything in the process, very quickly. This is exactly what we do everyday with the debugger, with trivial or complex code, with unit tests or regular code. An example: https://www.youtube.com/watch?v=jBBS4FeY7XM https://www.youtube.com/watch?v=jBBS4FeY7XM not with unit tests, it's an example on how to restart a precise frame, how to avoid re-running everything.