22 ms·
Hell Is Other REPLs
- PaulHoule 5y agoIt’s still nice to have persistent data structures on your fingertips.
- Y_Y 5y agoIt would be nice to get an example of how this wonderful REPL does all the cool things mentioned. In fact Haskell has a decent REPL, and you can (if you really want to) explicitly allow IO outside the IO Monad, or skip the type checker, though I find them more of a moral compass than an impressive dictat. I don't know if you can crash straight to the debugger like in common lisp though.
- CraigJPerry 5y agoA cool example: https://youtu.be/3HxVMGaiZbc?t=1783 https://youtu.be/3HxVMGaiZbc?t=1783 But better to just block 5 mins in your calendar and try it: https://github.com/PEZ/rn-rf-shadow https://github.com/PEZ/rn-rf-shadow Don't play with this if you like hot-reload or hot-refresh features in react or jrebel or whatever. You will forever see these other approaches as lame in comparison... speaking from someone who was previously very happily ignorant, living my best life on the JRebel side of the fence.
- throwaway73847 5y agoDon't let the 2005 date fool you. https://yewtu.be/watch?v=_B_4vhsmRRI https://yewtu.be/watch?v=_B_4vhsmRRI
- zetalyrae 5y agoNicolas Hafner[0], a prolific Common Lisp open-source developer, has been streaming the development of his adventure platformer Kandria[1] on YouTube: https://www.youtube.com/watch?v=DjjT7Fjh0Kk&list=PLkDl6Irujx9NUeqnEkRsFZ6bLS24B-6lT https://www.youtube.com/watch?v=DjjT7Fjh0Kk&list=PLkDl6Irujx... It's pretty cool to see music, graphics, and game behaviour change live in response to code entered into the REPL. [0]: https://shinmera.com/ https://shinmera.com/ [1]: https://github.com/Shinmera/kandria https://github.com/Shinmera/kandria
- Tarean 5y agoYou can run your program in the repl and :set -fbreak-on-error . You can get stack traces with access to variables via :set trace, but because of optimizations and lazy evaluation they are similarly jumbled as async code debugging. Haskell has some nice advantages like `:r` for reloading, similarly you can reload a dynamically linked binary and the old version is only unlinked after all references to it are gone. There is a significant difference to dynamic languages, though, because having different versions in memory leading to incompatible types would be a lot more common with a partial reloading workflow.
- bjoli 5y agoNow, this is the clojure repl which is not as nice, but I usually show people this: https://vimeo.com/230220635 https://vimeo.com/230220635 That does stay on the happy path, though, and CL has a much better REPL experience with regards to debugging.
- skohan 5y ago> These "big idea languages" tend to assert a kind of "programming ideology" over reality, and tend to, in my opinion, distance you from the thing you are trying to do, often, they claim, "for your own good" ... "You want to give HOW many objects a mutable reference to this value?" complains the Rust compiler. "Are you insane? You are a Rustacean, you don't do that kind of thing!" I agree with the spirit of this line of thought: in general I favor pragmatism over zealotry, and I think it should be up to the programmer to determine how a tool should be used, not the tool itself. However when we talk about something like the safety constraints imposed by Rust, it's more about citizenship than it is about the compiler being overly opinionated. By baking those constraints into the language, I can have confidence when I use third party code that it reaches at least some standard in terms of memory safety and thread safety. Much in the same way as a strict type system, those constraints free me up to not have to think about certain types of issues. If I am writing code which only I will consume, I'm also free to use escape hatches to sidestep these constraints when I know they're not relevant. I've written tens of thousands of lines of Rust by now, and I'm still not convinced the Rust model is the right one in terms of achieving its goals, but I think the approach is "reality based" with respect to avoiding some of the problems which can occur while developing software in collaboration with others.
- chousuke 5y agoIn my view it's very pragmatic to leave dealing with ownership to the compiler. It's something that you have to deal with in any language (even if you have a GC) if you want to write correct code, but it's not something most programmers truly prioritize most of the time. Even those who do think about ownership can't get it right 100% of the time because they're human and get tired. Keeping track of any kind of state is a constant drain on mental resources. Therefore, having the compiler deal with ownership correctly most of the time and maybe get in my way a bit some of the time when it's actually wrong (most of the time it isn't) is a tradeoff I'm happy to make.
- codeflo 5y agoI agree. The important thing for the other cases is to be pragmatic and use the escape hatches. Use a Mutex even though it’s not necessary and accept the runtime cost, or use an unsafe pointer, but get the job done. I’ve seen the phenomenon in both Haskell and Rust now where people would introduce way to much complexity for a relatively simple problem to conform to some sort of ideology.
- ekidd 5y ago> The Rust or Haskell compilers, for example, insist on policing whatever private understanding you might have about the meaning of your code. The thing about "private understandings" is that they're just another way of saying "we expect ceaseless, flawless vigilance" (as one writer put it), not to mention "flawless communication and training." Languages which impose weird restrictions tend to do so because it allows them to offer (nearly) ironclad guarantees about something else. There are certain programming idioms that work brilliantly in Haskell. Those same idioms would be utterly miserable in the presence of unrestricted mutation. Or to take the author's other example, Rust forbids shared mutable state, and it keeps careful track of ownership. But I can freely use native CPU threads without worrying about anything worse than a deadlock, and I can bang directly on raw bytes without worrying about anything worse than a controlled runtime failure. And this remains true even if team communication occasionally fails or if someone makes a mistake. Sometimes I want to rule out entire classes of potentially dangerous mistakes, and not just have a "private understanding" that nobody will ever make certain mistakes. As always, it's a matter of using the right tool for the job. If you need to write a high-performance, heavily-threaded network server that parses malicious binary data, Rust is a great tool because of those restrictions. If you need to do highly exploratory programming and invent new idioms to talk about your problem domain, Common Lisp is awesome. And if you need to build libraries where everything has a rigid mathematical structure, Haskell is a great tool. In my experience, Commony Lisp is a deeply opinionated language, and its most dramatic opinion is that "your code and your data should have identical representations and structures." And for the right problem, that restriction is extremely powerful.
- tialaramex 5y ago> If you need to write a high-performance, heavily-threaded network server that parses malicious binary data, Rust is a great tool because of those restrictions. If dealing with Untrusted File Formats perhaps you should use a tool purpose-built for Wrangling them Safely, WUFFS. You won't find a Hello, World example for WUFFS because Hello World prints out text to your console, which is exactly the sort of nefarious stuff bad guys might try to do and so WUFFS doesn't even provide any mechanism you could use to do that even if you wanted to. But it does Wrangle Untrusted File Formats Safely, shrinking your remaining problem space. For example WUFFS would be appropriate for taking files your users claim are JPEG "photographs" they uploaded for their "profile picture" and turning each one into either a 64x64 pixel RGB array or an error without any risk that they seize control of your profile picture program and do goodness knows what else instead. Although Rust's memory safety means you can achieve confidence a "photograph" doesn't corrupt memory it doesn't require the rigour WUFFS brings to file parsing, so a Rust program could end up confused about unforeseen state while parsing the file. For example in Rust you can write a function that might mistakenly overflow a 32-bit integer and, in production it will just silently wrap. In WUFFS that function won't compile until you either decide explicitly what should happen (e.g. wrapping, saturation) for each overflow, or you trap all the cases where it could overflow as an error. This is very annoying of course, but we're parsing Untrusted File Formats and if we leave anything to chance that will be exploited.
- wyager 5y ago> There is something vaguely totalitarian about these big idea languages. The Rust or Haskell compilers, for example, insist on policing whatever private understanding you might have about the meaning of your code. They are like the neighbor's kids in a totalitarian regime This statement doesn’t even slightly ring true for me. These compilers are more like infallible personal assistants who keep track of all the crap that I don’t want to. The Haskell compiler in particular has never suggested I stop doing something that didn’t turn out to be a bad idea under more careful consideration. The rust compiler is more restrictive (mostly due to lack of ability to express some types, like quantified or higher kinded types), but still is fundamentally working on my behalf.
- amelius 5y ago> (...) a single "revolutionary" concept or idea. Some examples include safety in Rust (...) I think these languages are focusing too much on a few ideas while ignoring the rest. For example if I'm writing a Rust program which launches missiles, then I can still accidentally launch these missiles in safe code. A GC'd language would still provide good memory safety guarantees while allowing me to focus more on the problem at hand (not distracting me with type errors), and thus it could be safer overall.
- kazoomonger 5y agoI'll admit that I like Rust, but this seems like an odd take to me. "Not distracting me with type errors" seems directly at odds with "safer overall", especially for a missile launching system. That sounds like a recipe for "Whoops, there goes New York, but at least the code looked nice".
- amelius 5y agoThe catch here is that not all type errors are errors. I'm not arguing here against a typesystem, just against overly strict typesystems.
- chakkepolja 5y agoRust typesystem has its place in many soft realtime / system programming domains. Problem is people trying to push it as one true solution. But that's a human problem.
- kazoomonger 5y agoI would interested in seeing an example of what sort of type errors you mean. IME, the Rust compiler does a great job of catching actual mistakes in the type system, such as with Send/Sync. It also pretty easily lets you tell the compiler "no, I know what I'm doing" and say "unsafe impl Send for Foo {}" to do it anyways.
- amelius 5y ago
- deleted 5y ago[deleted]
- tempodox 5y agoFor those who like to cross a REPL with strong static typing and don't want to go as far as Haskell, OCaml has a REPL and a tool (ocamlmktop) that builds a REPL variant of your software as a binary executable. Not quite as highly integrated as CommonLisp + SLIME, but still very useful.
- eatonphil 5y agoFor Standard ML, SML/NJ and Poly/ML also have a very useful REPL.
- mdm12 5y agoAnother option for ML-variant fans is F#, which has a REPL as well (built into many tools such as Rider or VS, or as a standalone 'fsi' executable).
- dunefox 5y agoI'm using F# + Rider at the moment as my language of choice for implementing interpreters and compilers and I have to say, I'm very pleased so far.
- dharmaturtle 5y agoI've been using VS Code Notebooks with F# - it's fantastic. Basically Jupyter Notebooks for VS Code. Demo: https://youtu.be/_QnbV6CAWXc?t=1298 https://youtu.be/_QnbV6CAWXc?t=1298
- yawaramin 5y agoAlso 'dune utop' which loads your library directly in the REPL, which is quite nice for iterative development.
- zetalyrae 5y agoWhen I was younger I used to write a lot of Common Lisp. A lot. And I also had this idea that Haskell/OCaml/Scheme were strict, ivory tower totalitarian languages, while Common Lisp was this incredibly powerful, expressive, liberating tool. For building organisms, not pyramids, like Sussman said. And the S-expressions were aesthetically appealing to me. But at the time I was working mostly on smaller commercial projects and solo open source projects. Maybe it's cognitive decline from no longer being a teenager, or the experience of working on larger, O(100,000) line codebases with large teams, but nowadays I find a high degree of dynamism just exhausting. I don't want more expressive power, I want fewer nightmares. A common problem I faced with Common Lisp is I'd write some module, then go on to write another module that depended upon the previous one, and get an exception through from the first module. Usually a type error. And I'd have to go back, context-switch, fix that, and climb back up to the other level. With ML/OCaml/Haskell that is far less common. Being able to look at a module and say, "this is done and it's correct", is a very powerful thing. Confidence, rather than safety, is the primary benefit of static typing for me. And I find that I no longer use the REPL. I've been working on a compiler in OCaml and for some reason Dune won't run utop (lol) so I've just not been REPL'ing and it's not been a problem. The code typechecks. Things work on the first run. If I change something, I get notified what needs updating. The problem with interactive development is that it's like unit testing: it can prove the presence of bugs but not their absence. Type systems can eliminate large classes of bugs ahead of time. Just so this is not entirely negative or depressing: there's something beautiful about how maximalist Common Lisp is. It's a big, messy language with every programming paradigm (and you can invent new ones) and different naming conventions in the core language itself. I was learning new things about Common Lisp years into using it productively. And I compared the experience to moving to a huge stately home, that has a room for the piano, a vast attic, a wine cellar, all manner of things, and then trying to move back to a shoebox apartment. Where do I fit the piano? CLOS, the MOP, the Lovecraftian beauty of LOOP and FORMAT: it's like a wild garden next to the (comparative) spartan minimalism of practically everything else. And it's beautiful.
- tomcam 5y agoHelpful real-world perspective, thanks. What is Dune in this context?
- pjc50 5y agoThis is remarkably similar to the advocacy made by lots of C/C++ programmers that the language is more useful because it lets you make mistakes, which is all well and good until someone buffer overflows your server and leaks the personal data of a million people / your cryptocurrency keys / whatever. The opinion of Rust and Haskell is precisely that making mistakes is bad, regardless of your "provocative" opinion that it might be good, and that the language should be a https://en.wikipedia.org/wiki/Poka-yoke https://en.wikipedia.org/wiki/Poka-yoke against certain categories of mistakes that have been found to cost the industry billions of dollars in failure. (What do the Clojure-for-web-services people do? Presumably that doesn't drop web requests to an interactive debugger, or does it? Or is that irrelevant because this is only concerned with Common Lisp?) This kind of advocacy seems to be endemic in LISP and FORTH: a tool produces great results when used by one or two idiosyncratic "genius" developers working in near-isolation on problems of their choice. It tends not to work nearly so well beyond that.
- disconcision 5y ago> What do the Clojure-for-web-services people do Not precisely what you're asking but I have, very occasionally, REPLed into remote clojure servers and rewritten running code live to fix time-critical bugs in production. But I'll admit i'm unsure whether this is an argument for or against Xtremely interactive development. Darklang does offer something they call trace-based development where unhandled requests basically do initiate an interactive process to write handling code. I'm under the impression though that this is not intended for production time. In general I'm loath to make any generalization about what kind of mistakes are good or bad and when. Luckily we have a language landscape which lets people make up their own minds.
- Matthias1 5y agoDarklang's traces are not the same thing as a REPL. The user gets sent a normal 400 error, and the request trace is saved so that later, the developer can "replay" the request (on the live server, with full context). While Dark does support the general idea of doing live code in production, it's not a Lisp dialect and is very much a functional language.
- zmmmmm 5y agoThe problem with REPL-driven development is that when taken too far it makes you capable of creating programs that simply cannot be understood by someone without the "lived experience" of the path taken to arrive the solution in the REPL. The very property that makes it liberating - that you can instantly try things out and see mistakes - allows you to elevate up a level or two in complexity of what you can do. But the future readers of your code don't have this advantage. While you can apply discipline and use it to work to find the simplest, clearest solution, there is nothing that forces that and you can just as easily arrive at something that looks and works like magic to someone coming to it fresh.
- CraigJPerry 5y agoI don’t know. I can write incomprehensible code in any language. It is to some extent the default. I have to work hard so as not to be the poor future reader (myself) in 6 months thinking “where do i even begin…?” I find the repl encourages me to iterate quickly and when i set out to solve a problem, one of my goals is to express the solution in a nice way. The repl just reduces the cost of me trying different ways to achieve that. Whether i leave behind horrible or nice code isn’t really a factor of the repl, it’s a factor of whether i started with an intention to write understandable code. I usually do and the repl’s instant feedback and state retention makes that vastly easier. Sometimes i don’t set out with that intention though, i frequently have to process lots of text and regexp is just the easiest way for me usually - even though i accept it’s utterly impenetrable to many once you go beyond 10-20 chars or so in an expression. No repl involved in producing fairly impenetrable code.
- codetrotter 5y agoI’ve been reading the book ANSI Common Lisp by pg, and decided to work through some of the exercises that piqued my interest. Similar to what you are talking about here, I worked on one of the problems for a while. Not in a REPL, but in a similar manner. And I arrived at a solution that is not advanced or anything, but which I was quite satisfied with. It occurred to me then that my solution to the problem I was working on really only made sense because I had worked through the problem. For this reason I left a printout of two of my hash tables in the code. Because when you see what data they actually have in them it becomes quite obvious what the code is doing. Whereas without those two printouts you’d have to “simulate” in your brain what the code is doing. And so for that reason I left the printouts in my code. But this also ties into a more general problem in software development which is that even though our tools are becoming really really good and our computers really really fast there is still a long ways to go in terms of how deeply and how completely we can really see what’s going on. I was thinking about this recently when I was at the dentist to pull a tooth. It was not a fun experience but even so I saw that the dentist had both the skill and the tools for making the operation. And in particular the tools he had at his disposal allowed him to understand and to operate on my teeth. And that got me thinking once again about the lack of visibility that we have when we develop software.
- atombender 5y agoTheir complaint about Haskell is based on a common misconception. You can do everything in Haskell that you can in a non-pure language, including in-place mutation (e.g. IORef, Data.Vector.Generic.Mutable, etc.), strict functions, manual memory allocation, and so on.
- masklinn 5y ago> Their complaint about Haskell is based on a common misconception Misconception is way too kind a word. And it's quite ironic (though not necessarily unsurprising) seeing the article's namecalling of bad faith as it engages in paragaph after paragraph of bad faith and being plain wrong.
- brabel 5y agoI found the article quite interesting and funny (in a good way) and I have trouble understanding why anyone would think it's written in bad faith. He's not attacking you personally for being a Haskeller, he's just making light fun of the fact that Haskell requires monads to do IO and won't let you do it any other way, how is that bad faith?
- herbstein 5y agoThe fact that monads aren't technically required to perform IO at all but rather is an abstraction that meshes nicely with the Haskell way of doing things. If you don't want to use monads for IO you're certainly going to meet resistance in terms of library support.
- pyrale 5y ago> I have trouble understanding why anyone would think it's written in bad faith. Well, for one, it's hard to start a good-faith discussion about a tool by calling it totalitarian in the introduction paragraph.
- philosopher1234 5y ago
- continuational 5y ago> The language seems designed to encourage you to be you and to shape the language to suit your individual style, problem domains, or interests. This is cool for the solo programmer. Teams and organizations need some amount of standardization if they want their programmers to be able to maintain each others code. At that point, none of the coolness of Lisp remains, and you're better off using a less dynamic language that imposes more of a standard style.
- masklinn 5y ago> This is cool for the solo programmer. Who doesn't come back to their program after 6 months of doing something else.
- masklinn 5y agoNot sure why i’m getting downvoted. When I come back to a project 6 months after I last touched I might as well have never heard of it for all I remember.
- lispm 5y agoIt's not necessarily so. It works also for groups. Example: at a time when 'object orientation' was still kind of new (early 80s) lots of Lisp-using groups were developing OO-extensions for Lisp: Flavors, LOOPs, CommonObjects, ObjectLisp, ... These language extensions were used in groups at TI, Xerox, HP, Symbolics and others. For example Symbolics wrote much of their operating system and their applications using Flavors (-> several groups of people used it as a standard language extension -> incl. their customers). With the Common Lisp standardization, a subgroup was given the task to decide on a standard object-oriented extension or to develop their own. After several years of work, a core group with a large group of supporters and implementors then defined a standard language extension to integrate object-object-oriented programming in Common Lisp - the Common Lisp Object System, which is now widely used in Lisp.
- deleted 5y ago[deleted]
- ilrwbwrkhv 5y agoPure prototypal JavaScript is honestly one of these non authoritarian languages. At its core it's just: var obj = {}; obj.a = 10; obj.a; // returns 10 And with browser dev tools you can debug very efficiently. I would agree that the interactivity of the REPL is not at the same level as CLisp.
- peterkelly 5y ago> "True interactive development is also about programming in such a way that your program never crashes. Instead, whenever an unhandled condition is raised, the program starts an interactive debugger." That's great until someone else tries to use your program. I'll take the compile-time safety checks, thanks.
- dunefox 5y agoAs we know no bugs are present in statically typed programs.
- IshKebab 5y agoNobody claimed that, but there definitely are fewer. 15% fewer according to the only study I've seen that objectively measured it.
- dunefox 5y agoLink? I'm not certain that there's a way to objectively measure that on a scale that matters.
- IshKebab 5y agohttps://ieeexplore.ieee.org/abstract/document/7985711 https://ieeexplore.ieee.org/abstract/document/7985711 Basically they took random JavaScript bugs and annotated them with Flow and Typescript type hints and then checked whether the bug was detected. Pretty clever methodology really.
- bitmapper 5y agoAnd then when things like dependent types get involved, I'm betting that the amount of bugs greatly decreases, even more than that.
- chrismorgan 5y ago> These "big idea languages" tend to assert a kind of "programming ideology" over reality, and tend to, in my opinion, distance you from the thing you are trying to do, often, they claim, "for your own good". Another angle on this for a language like Rust is that Rust is designed the way it is because it’s favouring reality over programming ideology, distancing you from the thing you’re trying to do when it’s something that doesn’t map to the reality of how computers work very well—and yes, that reality does end up leading to ideology, but Rust is the way it is because of reality more than because of ideology. But then Lisp! Why, Lisp is the epitome of programming ideology over reality! Ask me to name a “big idea language” under the provided definition and the first language (well, family of languages) that springs to my mind is Lisp. It’s not just unopinionated, it’s aggressively unopinionated, which is an opinion, an ideology (to say nothing of the doctrine of S-expressions), and one that flies in the face of how computers actually work; so that you pay at least a performance price to use such languages, and often other prices too, like with threading, as ekidd’s comment mentions. There’s a reason Lisp machines died.
- whartung 5y agoI guess I never "got it". What CL development I've done, it was pretty much "reload it and rerun it" in terms of a development cycle. Mind, these were not large programs. But there was enough global, shared state that needed to be reset that, most of the time, a simple tweak to a function wasn't enough to right whatever wrong was involved. And the reloads weren't arduous anyway. Sure, for "little work", "local work", tweaking a routine, doing simple tests and such in the listener. It was fine. Very quick turn around. But when fixing something that was larger in scope? Reload it, rerun it. I also never "got" the restart and condition systems in CL. Part of this is simply my background, today mostly being in Java where production debugging is doing archaeological digs on deep stack traces. I get restarts in interactive systems. But my systems were not interactive. They were server based systems, processing zillions of requests. I never saw the utility of a restart on a headless system. I could not imagine a connection stuck in a restart just waiting for me to fix it, debug it, correct it, continue it, or abort it. In contrast to just logging the torrid details of the failure and path to it and using the information in a post mortem. Do folks get 3am phone calls to open up a server and dig through restarts? That never made any sense to me. On paper, it sounds great, I just never saw any realistic way it would ever apply in any of the work that I did. Are there times it would have been nice to log in to a server, tweak a piece of code, and let it continue on? Changing the tires of a car on the road? Sure. Occasionally. Mind, that could just be habitual. Since to me it was a novelty, and one unavailable to me, perhaps I simply don't miss it. Yea, it makes sense when hacking deep space probes. But a generic remote web service type of application in production? To me, not so much. The idea of hot patching a server is amazing and frightening at the same time. How was the patch tested, do you commit it to VC first, before cut and pasting the DEFUN in to the listener, etc. The same applies to Smalltalk. The idea of sending out an application that faults and drops the user in to a restart and debugger. What can they do with that? Call me up and talk them through it? I'd much rather them send me the log file with a post mortem I could use. I'm sure ST has ways of capturing stack traces in log files, but, casually, nobody talks about it. So, I'd love to hear stories about what I'm missing. What applications folks were doing that were leveraging these aspects of the CL experience. How they manifest on system with any transaction volume (you know, a few trx per second). How one uses restarts in a web shopping cart in production. Make no mistake, in Java, with the applications servers, turn arounds can be pretty long. But, similarly, with code structure, units tests, etc. turn around can be very fast. Make a tweak to the code base, repeatedly run an isolated unit test until it works, then run the larger suite to see what else you broke. That can be quite fast. Not "interactive", but...fast. "Close enough".
- taeric 5y agoI have been musing with the thought that so many IDE environments are mainly about integrating other tools for you to make your program. Common Lisp does seem to be about integrating your program into your environment in a way that isn't that common anymore. (I know there are other "image" based languages. They seem to have fallen by the roadside, though. Common Lisp, mostly, included.)
- skybrian 5y agoI’m interested in how people using different languages manage this style of “developing in the debugger” and then (eventually) checking in finished code. Two systems I’m familiar with: * In Flutter, you write code in the normal way, in an editor or IDE. If you want to change code while the program is running, you edit code in the normal way and hit a key to reload it. This works when stopped at a breakpoint. But the changes you can make using hot reloading seem somewhat limited; you couldn’t do a major refactoring. * In an Observable notebook, you edit a cell and then any other cells that depend on it automatically run, like a spreadsheet. You don’t normally use a debugger, though the browser’s debugger does work. In some cases when you’re using advanced features, you might need to reload the page, but usually you don’t. How do people work using Common Lisp? In other languages? In particular, do you write code in one place (using the repl) and copy-paste it to another place?
- tgbugs 5y agoThe workflow for slime/sly and swank/slynk described at the end of the article is standard if you are in the Emacs world. Sometimes I work in an Org file, sometimes in a lisp file directly. In both cases I will C-x C-e (eval-last-sexp) or run blocks, or the whole file (depending on Org vs lisp file). It is copy and paste on steroids (same for slime-eval-defun were you can be working deep inside some large function and update the whole without changing your view). There are some examples of developing in the debugger in [0] around 55 minutes (linked). This video also has great examples of other crazy interactive development workflows and is worth watching in its entirety if you are interested in this kind of thing. 0. https://youtu.be/bl8jQ2wRh6k?t=3299 https://youtu.be/bl8jQ2wRh6k?t=3299
- skybrian 5y agoHmm. The article doesn't really describe what it's like but I skimmed the SLIME manual. So you basically point at the code you want to run, and this isn't necessarily how you would run it in production. It looks like SLIME mode requires you to install an interpreter hook in the startup code for the process that you want to debug, so you can run commands that way? This seems like it would make the most sense for event-driven code. Evaluating a script is another kind of event. Many systems have a way to execute commands. I'd guess this style of development encourages people to structure their systems as essentially command interpreters, even if the commands normally come from a UI. The interesting bit will be deciding how the data structures that persist between commands are implemented. For example in server-side web apps, the shared state is often a database, so state is external to the process being debugged. The architecture limits what you can do directly, but you can try out SQL queries.
- platz 5y agoThis person doesnt understand what Bad Faith actually means. Many people including GP are now using this term as a simple perjorative just to describe things that they don't like or disagree with. Something similar has occured with the term 'gaslighting'. They also linked to the more questionable entry on wikipedia rather than the more authoritative one. Compare https://en.wikipedia.org/wiki/Bad_faith https://en.wikipedia.org/wiki/Bad_faith vs https://en.wikipedia.org/wiki/Bad_faith_(existentialism) https://en.wikipedia.org/wiki/Bad_faith_(existentialism)
- Rich_Morin 5y agoThe article closes with a discussion of "true interactive development". I was particularly interested in this and wondered how IEx (Elixir's REPL) compares to Common Lisp's. So, I started this thread on the Elixir Forum: https://elixirforum.com/t/hell-is-other-repls-how-does-iex-compare/41991 https://elixirforum.com/t/hell-is-other-repls-how-does-iex-c...
- denvaar 5y agoA few things I like about IEx: - Supports tab completion, shortcut keys like ctrl-a/ctrl-e and probably more that I don't ever use. - Top notch support for unicode and supports color (IO.inspect with [color: true]) - EZ access to docs (Just type h in front of what you want to know about) - You can recompile your project without leaving the repl (keeping whatever state you have) - You can access the history of what has been returned using the v function - Remote shell support (type `h IEx`) to learn more. --- One thing I don't like: If you get mixed up and forget how many braces or parenthesis you need to close, you get stuck. I usually have to quit iex to get out. There may be a better solution to this that I'm just not aware of
- sfusato 5y agoThere may be a better solution to this that I'm just not aware of When that happens, I simply enter 'iex> end' which would return a SyntaxError, and start over but without having to restart iex.
- vindarel 5y agoI tried Alchemist-mode for about 1 hour and compiled these remarks: https://gist.github.com/vindarel/59db5d57391f35e86288f2c6bf7dcd59 https://gist.github.com/vindarel/59db5d57391f35e86288f2c6bf7... - it seems some core lisp/Slime features are not there: compile one function independently, get type warnings and errors, goto source definition working OOB, no function signature (?), find who calls a function or macro, who sets a variable, and then no interactive debugger, no stepper, no inspector… ?
- hyperion2010 5y agoThis is a wonderful exploration further into the original spirit of that comment and very much reflects the experience that I have had as well. The only other runtime I have found that has a similar absence of pain is Emacs (though Emacs has its own separate warts unrelated to friction at the repl). I think there is a deeper disconnect between having something that looks like a repl and a real repl which is that for decades Emacs didn't even have a command line style repl, because the repl was everywhere, hidden behind C-x C-e or M-:. A point of confusion I think is that repl in the lisp world has come to imply much more than that somewhere there is some code that looks like (loop (print (eval (read)))). That level of sophistication of the repl concept was archaic well before common lisp, but the term continued to be used and evolved to signify a runtime that could support interactive development. For many of the other languages the issue isn't with the form of the interface (almost any language can have a prompt, come up with printed representations that can round trip through their printed representation, etc.) it is that their underlying runtime can't support the kind of redefinition that is needed to avoid the creeping insanity that can arise when code becomes subtly out of sync with data e.g. in Python classes and instances. Computers are faster now, so the workaround is "restart the runtime" and users hardly notice. Therefore no one bothered to implement what common lisp has. Given how long a cold boot took back in the 70s and 80s, avoiding the restart at all cost was a top engineering priority. Lisps evolved in a significantly different and harsher selective environment than many of the runtimes that came after, and as a result had to solve certain fundamental problems that are practically invisible for users today. In the time since I wrote the referenced comment on reddit I have also discovered the amazing power of save-lisp-or-die. At the time it hadn't quite clicked for me. I'm guessing that the author has had a similar experience given the title of the series so I'm looking forward to reading more in the future! In the mean time I also learned a bit of docker, and what I find amusing/sad about it is that slad is basically docker without all the fuss. Sure it can't bring a whole unix system with it, but it is a couple of orders of magnitude smaller and significantly less complex.
- deleted 5y ago[deleted]
- yawaramin 5y agoIronically, the 'bad faith' argument in this post is an example of a bad faith argument. > These "big idea languages" tend to assert a kind of "programming ideology" over reality, and tend to, in my opinion, distance you from the thing you are trying to do, often, they claim, "for your own good". Except they don't pull these programming rules out of thin air, they're actually widely acknowledged as the best practices in the domains they're targeting. It's like complaining that SQL database engines don't let you hand-write custom query plans in your queries, 'for your own good'. Well yes–that's exactly the point! They've been finely tuned over decades of research to know how to do it better than humans. > They are like the neighbor's kids in a totalitarian regime who will report you to the secret police when they think you're not quite as doctrinaire as you ought to be. Wow! Comparing a technological tool to a fascist regime, because that's totally accurate and appropriate! /s > Haskell compiler might be heard to say, "What are you doing? You are a Haskeller and should know better!" ... complains the Rust compiler. "Are you insane? You are a Rustacean, you don't do that kind of thing!" Yes, of course, compilers are exactly shrill, screaming drill sergeants trying to break you down and indoctrinate you. By contrast, doesn't Common Lisp seem so mild-mannered and gentle? Of course you'd never want to use anything else! Now I know it would be a little extreme to call this argument 'gaslighting', but I honestly can't think of a better word. > Encouraging you to avoid something, however, is quite different from banning it outright. Yeah, which is why Rust and Haskell actually don't ban it outright, and in fact why almost every language has 'escape hatches' that allow programmers to do whatever they want, on their own recognizance. > When you are programming interactively, you are not so much writing code as sculpting and structuring live computer memory. Great, but once I'm done with that, I need to actually lock in the shape of the sculpture so that it can be deployed with confidence. > True interactive development is also about programming in such a way that your program never crashes. Instead, whenever an unhandled condition is raised, the program starts an interactive debugger. Great if you're planning to keep a watchful eye on the program constantly. Not very helpful if the program is supposed to run unattended. > Hell is Other REPLs. Clever, but even other REPLs allow you to do the crucial bit–i.e. interactively explore an API. And after that, the best languages even allow you to lock in your findings and deploy with confidence!
- marciol 5y agoRuby pry brings a lot of those conveniences that I think really hard to live without. There is a presentation[1] when Conrad Irwin shows what is possible. [1]: https://youtu.be/D9j_Mf91M0I?t=1238 https://youtu.be/D9j_Mf91M0I?t=1238
- Syzygies 5y agoThank you. I kept asking myself why I was reading a debate in 2021 about a language that defaults to (GET OFF MY LAWN) all caps. Learning about Ruby pry made it all worth it.
- Ericson2314 5y agoThese posts complaining about programming languages shackles also seem to concieve of programming as a highly individualistic endeavor. I don't that that's a coincidence. I think type systems and other restrictions are really good precisely because they help me better trust and collaborate with others.
- Ericson2314 5y agoFor the style of programming described in this post, skip all this common lisp smalltalk nostalgia. The real epitome is Kernel with its fexprs http://web.cs.wpi.edu/~jshutt/kernel.html http://web.cs.wpi.edu/~jshutt/kernel.html, and also the creator's philosophical insight in https://fexpr.blogspot.com/2016/08/interpreted-programming-languages.html https://fexpr.blogspot.com/2016/08/interpreted-programming-l... It's not my cup of tea, but I respect him for doing something different and taking this thread out of the haze and to its conclusion.
- LAC-Tech 5y agoIs there any way I can get this awesome common lisp repl experience without emacs? I'm sorry emacs fans, I've tried multiple times, vanilla, with distributions... it just doesn't work for me.
- borodust 5y agoHave a look at SLIMA for Atom[0]. [0]: https://github.com/neil-lindquist/SLIMA https://github.com/neil-lindquist/SLIMA
- thewakalix 5y agoI've never understood the purpose of significantly modifying a program in memory. Won't you just have to redo all your changes, this time to the source program, once you've settled on a design? [0] As long as you have fast, incremental compilation, doing it in memory first seems like a waste of time. It mostly seems useful for small, disposable changes, to explore while debugging or whatnot. (I suppose hacking on a process as it runs in production, or some other scenario where "halt, compile, restart" is impossible, is also a good reason, but personally I'd prefer saving process state across restarts, like XMonad does.) [0] Of course, that doesn't apply if you're building the program entirely in memory, such as Smalltalk with its image-based programming environment.
- keymone 5y agoAnything that is possible (allowed by compiler/interpreter/runtime) will eventually make it into your codebase. For this reason alone I will always prefer languages with strong principle and big idea to languages that are multi-paradigm and agnostic. (Not saying that’s my only preference ofc)
- thewakalix 5y agoA type error isn't some kind of punishment, it's a discussion with the compiler. Type errors are good -- they mean that there's a discrepancy with your idea of the program that you're writing, and the way that you've actually written it, and a good typechecker will help you track down that discrepancy. So when GHC says "you're doing side effects outside of IO", it's not trying to harsh your vibe. It's explaining to you the inconsistency between your program and the "type" (description) that you've written for it. You might not want to have to explain yourself to the compiler, and that's fine -- go write in an untyped language instead. But it's hardly authoritarian to offer a different way of programming. (Keep in mind that typechecking meets many of the same needs that debugging does. For someone who already tries to typecheck in their head to ensure that their programs are correct, having an explicit, external typechecker can be a relief. That might not be you, but it's at least some people; when I program in Lisp I'm always running into problems that a typechecker would have solved at compile time, and I find that frustrating. To each their own.)
- spdegabrielle 5y ago“Real programmers fix bugs in production”.