[HN Gopher] It's 2023, so of course I'm learning Common Lisp
       ___________________________________________________________________
        
       It's 2023, so of course I'm learning Common Lisp
        
       Author : behnamoh
       Score  : 347 points
       Date   : 2023-07-27 00:21 UTC (22 hours ago)
        
 (HTM) web link (log.schemescape.com)
 (TXT) w3m dump (log.schemescape.com)
        
       | opportune wrote:
       | I see a lot of "coding" talk in the blog and comments from the
       | author here, but few mentions as to what kind of software they're
       | building or what use cases they're targeting.
       | 
       | My hot take is that the reason functional programming never took
       | off is that, while it certainly is fine for writing programs,
       | most software these days is not "program running locally on my
       | pc/server from the command line until it completes" and is
       | instead "program that starts, reacts to input from user, then
       | gets closed by the user" or "program that starts, then responds
       | to network or other automated I/O (to serve web pages, to monitor
       | something, to emit logs, etc) then stops when the other software
       | tells it to". This is a lot harder to do in a purely functional
       | style, or at least it is in most opinionated functional
       | programming implementations I've used, because you're no longer
       | "just" evaluating some expression but instead initializing state,
       | reacting to I/O, then updating state and/or performing further
       | I/O potentially while using parallelization to perform
       | monitoring/listen for other things/perform further I/O and state
       | updates.
       | 
       | Of course it's not impossible to do these things with Lisp but
       | from my couple of semesters of exposure of FP in undergrad and
       | use of FP features in C++ and Scala professionally to solve these
       | kinds of problems... it seems quite hard to get FP to work for
       | these applications, and that lack of suitability is what
       | discourages me from diving more fully into FP
        
         | lukego wrote:
         | I'm using Lisp for simulation. It's really wonderful being able
         | to poke and prod long-running computations while they run. I
         | missed this too much when I tried using Julia.
        
         | schemescape wrote:
         | > I see a lot of "coding" talk in the blog and comments from
         | the author here, but few mentions as to what kind of software
         | they're building or what use cases they're targeting.
         | 
         | Good point! This is all currently just a hobby. For Common Lisp
         | specifically, the only things I've produced are a (mediocre)
         | Battlesnake client and a (now defunct, as of yesterday)
         | multiplayer word scramble game. Neither of these really derives
         | much benefit from being created in Lisp, but I learned a lot
         | along the way (which was really the point).
         | 
         | Unrelated to Common Lisp, I've found myself often needing to
         | write code that generates code. This is an area where I suspect
         | Lisp will shine, although I haven't had a chance to give it a
         | try yet. Two examples from recent projects (which I tackled
         | before ever thinking about using Common Lisp) are:
         | 
         | * Generating code to validate a particular JSON Schema (used in
         | a static site generator)
         | 
         | * Generating JSX from Markdown (used for story content in a
         | programming game)
         | 
         | To say nothing of the innumerable C macros I've written in my
         | lifetime :)
        
           | opportune wrote:
           | Thanks for the answer! Your word scramble game in particular
           | seems like something that approximates my "maybe not a good
           | fit for FP" bucket. Do you plan on sharing it on GitHub or
           | describing the challenges you ran into?
           | 
           | Completely agree code generation is where I expect Lisp to
           | perform the best. Though, I looked it up and apparently
           | Markdown is not context-free so.. curious as to the
           | challenges that introduces as I figure FP could zap through
           | parsing a CFG but really struggle with state for something
           | not context free
        
             | schemescape wrote:
             | Note that Common Lisp doesn't require functional
             | programming. Mutation, side effects, etc. are fine. I just
             | write imperative code for the most part.
             | 
             | My code was quick and dirty, so I don't think anyone will
             | learn anything from it, but it's here:
             | https://github.com/jaredkrinke/thirteen-letters
        
         | vippy wrote:
         | It took me a while to grok monads, and the IO monad, and longer
         | still to figure out how to compose them in safe ways, and
         | manipulate execution order, etc. But: now I can write typesafe
         | applications, and I produce fewer bugs when I work in non-FP
         | languages (I get paid to write Java.) Lisp is a starting point.
         | Haskell is where it's at. I recommend learning the style, even
         | if you never produce production code in it.
        
           | xedrac wrote:
           | Yes, Haskell is magnificent for learning FP. I used to think
           | Haskell was terrible for IO, but my tune has changed
           | dramatically since I started working with it full time.
        
           | opportune wrote:
           | Let's say I want to do something simple but slightly beyond
           | the scope of a traditional toy demonstration:
           | 
           | * Read some environment variables and a local file
           | 
           | * Start a monitoring thread that consumes from a channel or
           | something similar, then every X s or X events writes to a
           | local temp file and then sends a request batching some
           | metrics to an external system
           | 
           | * Configure and start an http server
           | 
           | * Said server has a handler that 0. Starts a timer 1. loads,
           | then increments an atomic "num requests served until now"
           | variable 2. uses synchronization to lock on a list or ring
           | buffer containing the last 5 requests' user-agent headers 2.5
           | copies the current last 5 values, replaces oldest one with
           | the one from the handles request, unlocks 3. generates a json
           | response containing like "num_so_far: x, last5agent: [..],
           | "some_env_var":.." 3.5 stops the timer 4. write request user
           | agent and time interval to monitoring thread's channel 5.
           | write response and end handling
           | 
           | * server's gotta be able to do concurrency > 1 with
           | parallelism
           | 
           | * On sigterm set the server to a state that rejects new
           | requests, waits for existing requests to complete, then
           | flushes the monitoring channel
           | 
           | I'd consider this a trial run of some of the most basic
           | patterns commonly used by networked software: init io,
           | immutable shared state, atomic mutable shared state,
           | synchronization locked shared state, http ingress and egress,
           | serialization, concurrency, parallelizarion, background
           | threads, os signals, nontrivial cleanup. In Go, Java, or C++
           | I could write this with my eyes closed. How easy is it in
           | Haskell or Lisp?
           | 
           | If you know of any demos or repos that do something like this
           | - not a pure toy or barebones demo, but not a huge task all
           | in all- in either I'd be interested in seeing what it looks
           | like.
        
             | tlavoie wrote:
             | There are bunches of web frameworks and various support
             | libraries for both Haskell and for Common Lisp. They'll
             | range from simple use cases to more complete and/or
             | opinionated in style, depending what your needs are. For
             | Haskell examples, Servant is used for web APIs, where Yesod
             | is a larger all-around framework.
             | 
             | https://www.servant.dev/ https://www.yesodweb.com/
        
             | remexre wrote:
             | I'll cover the Haskell side because I'm more familiar with
             | its library ecosystem:
             | 
             | > Read some environment variables and a local file
             | import System.Environment (getEnv)         import
             | System.FilePath ((</>))         main = do           dir <-
             | getEnv "WHATEVER_DIR"           data <- readFile (dir </>
             | "foo.txt")           putStrLn ("Had " ++ show (length
             | (lines data)) ++ " lines")
             | 
             | > Start a monitoring thread [...]                   import
             | Control.Concurrent         import Control.Concurrent.Chan
             | import Network.HTTP         -- also more stuff...
             | monitoringThread :: Chan String -> IO ()
             | monitoringThread chan = do           file <- openFile
             | "log.txt" AppendMode           forever $ do -- no $ needed
             | if you pass -XBlockArguments [0, 1]             batch <-
             | replicateM 5 (readChan chan)             let chunk =
             | unlines batch             hPutStr file chunk
             | simpleHTTP (postRequestWithBody "" "text/plain" chunk)
             | main :: IO ()         main = do           logChan <-
             | newChan           void (forkIO (monitoringThread logChan))
             | -- ...           forever $ do             threadDelay (1000
             | * 1000) -- 1M usec             writeChan logChan "Hello,
             | world!"
             | 
             | > Configure and start an http server
             | import Network.Wai         import Network.Wai.Handler.Warp
             | main = run 8000 $ \req respond ->           respond
             | (responseLBS status200 [] "Hello, world!")
             | 
             | > Said server has [...]
             | 
             | Yeah, this is long. If you're just getting the current time
             | with the timer, that's here[2]; synchronize across threads
             | with MVars[3] or STM[4]; JSON is in aeson[5], which should
             | feel broadly familiar if you know Rust's serde.
             | 
             | > server's gotta be able to do concurrency > 1 with
             | parallelism
             | 
             | Yep, GHC Haskell has _excellent_ concurrency support on top
             | of a parallel runtime.
             | 
             | > On sigterm set the server to a state that rejects new
             | requests, waits for existing requests to complete, then
             | flushes the monitoring channel
             | 
             | I haven't personally tried this, but this[6] function
             | sounds like... exactly this, actually, so I think its
             | example should suffice?
             | 
             | On two separate notes:
             | 
             | - Common Lisp and Python 3 are a _lot_ closer than Common
             | Lisp and Haskell, or even Python 3 and JavaScript; the
             | Python 3 object model is very close to Common Lisp's, and
             | Common Lisp is not particularly pure (setf isn't
             | unidiomatic by a longshot), and supports a very non-
             | functional style of programming (it has gotos!).
             | 
             | - "Haskell is worse at IO than other high-level languages"
             | isn't particularly true. What _is_ true is that Haskell has
             | the same "function coloring problem" as JavaScript (Haskell
             | has the IO monad, JavaScript has the Promise monad);
             | Haskell also has a "uses funny academic words" problem
             | (well, debatably a problem...) which I think confuses the
             | issue.
             | 
             | [0]: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/ext
             | s/bloc...
             | 
             | [1]: Haskell has a spec, one "main" implementation (GHC),
             | little spec-committee activity, and a respect for that
             | implementation not superseding the spec; many improvements
             | become language extensions (-X flags or {-# LANGUAGE #-}
             | pragmas), so when you invoke GHC you're getting a by-the-
             | spec implementation by default.
             | 
             | [2]:
             | https://hackage.haskell.org/package/time-1.12.2/docs/Data-
             | Ti...
             | 
             | [3]: https://hackage.haskell.org/package/base-4.18.0.0/docs
             | /Contr...
             | 
             | [4]: https://hackage.haskell.org/package/stm-2.5.1.0/docs/C
             | ontrol...
             | 
             | [5]: https://hackage.haskell.org/package/aeson-2.2.0.0/docs
             | /Data-...
             | 
             | [6]: https://hackage.haskell.org/package/warp-3.3.28/docs/N
             | etwork...
        
             | draven wrote:
             | I don't have time to try it atm but this looks like it
             | would be quite easy to implement in Clojure (that falls
             | under "Lisp", right?)
        
         | kubb wrote:
         | Functional programming took off big time. Just look at the
         | JavaScript ecosystem.
        
         | victorbjorklund wrote:
         | Whatsapp and discord runs on functional elixir/erlang. I heard
         | they are pretty big and not hobby projects.
        
         | tmtvl wrote:
         | Common Lisp isn't a "purely functional" language, it supports
         | every paradigm. It allows silly things like...
         | (let ((pair (cons 1 nil)))         (setf (cdr pair) pair)
         | (list (first pair) (second pair) (third pair)))       ;; => (1
         | 1 1)
        
         | lawn wrote:
         | Elixir uses functional programming and its excellent for web
         | development and whenever you want a fault tolerant system.
         | 
         | You also don't need to throw out all the good features of the
         | other styles, as parts of functional programming are becoming
         | more and more common in "regular" languages too. Rust uses
         | functional patterns in many cases for instance.
         | 
         | And you can also write Lisp in an OO or imperative style if you
         | want, it's no Haskell.
        
         | rileyphone wrote:
         | Note that Common Lisp contains CLOS, which is one of the most
         | advanced object-oriented systems even now. Most Lisps are not
         | functional like Haskell is.
        
           | opportune wrote:
           | I read this Wikipedia article and some examples:
           | https://en.m.wikipedia.org/wiki/Common_Lisp_Object_System
           | 
           | Yes, the article calls it powerful, but aside from the
           | ability to update classes and their functions at runtime -
           | which, maybe I'm missing the utility of so I won't say it's
           | useless although in my experience a SharedInstanceSingleton
           | or LocalImmutableConfig or BatchedMonitoringEvent wouldn't
           | need it - it's "just" dynamically resolving the method
           | implementation to use based on argument types dynamically and
           | letting you provide an order of precedence for diamond
           | inheritance.
           | 
           | I think it does solve one problem I have - with some solid
           | tooling and a guarantee that class updates at runtime don't
           | disrupt ongoing calls, it might let me patch running binaries
           | without doing a full update. Though, the cost is that I seem
           | to incur a few extra lookups or even sorts on each
           | dynamically dispatched method, to resolve the implementation?
           | Besides that it doesn't seem to really solve most problems I
           | have regarding I/O or state - having the option to update
           | some of these at runtime is interesting but it seems like
           | something I'd only want to selectively enable
        
             | varjag wrote:
             | _in my experience a SharedInstanceSingleton or
             | LocalImmutableConfig or BatchedMonitoringEvent wouldn't
             | need it_
             | 
             | When you can't have something, it often becomes felt that
             | you don't need something.
        
       | anonzzzies wrote:
       | I love CL and I really miss it when i'm doing something else. I
       | mean, many things are such a pain in 'modern' languages that it's
       | not even funny, when you compare it to the Lisp experience of
       | even decades ago.
       | 
       | There are many cons, but those are simply not as bad as most of
       | the pure technical language/dev env cons in almost everything
       | else. Sure Python & JS have more uptake, more libraries etc, but
       | the experience of developing for them is so much worse. IMHO of
       | course. I have been doing a lot of languages over the years
       | including C#, TS, Py, Hs and more esoteric ones, but I keep
       | coming back to CL (SBCL + emacs + Slime) when I get seriously
       | angry about stuff that is missing or plainly bad in those
       | languages. It makes me relaxed and convinced there is some good
       | in the world after all.
       | 
       | I am currently raising for a product we (foolishly so)
       | bootstrapped in Typescript but now we will, for a launch version,
       | redo it in CL. Meaning I get to work with / in CL (and all of the
       | fun stuff; implementing DSL, code generation, working with
       | macros, implementing a static type solver etc) for the coming 3-5
       | years before we launch. Lovely.
        
         | Thiez wrote:
         | Why is Typescript unsuitable for the product?
        
         | pjc50 wrote:
         | > There are many cons
         | 
         | Can't have Lisp without cons. (sorry)
         | 
         | What do you miss in Lisp when working in C#?
        
           | anonzzzies wrote:
           | I would say:
           | 
           | 1) painless debugging with Emacs/Slime vs Rider/VS/VSCode
           | 
           | 2) performance & consistency of it; SBCL is _fast_ and
           | remains that way, I can leave emacs /slime running for months
           | and it doesn't degrade; vs/rider... they really burn a hole
           | through my laptop _and_ isn 't even that good at most things
           | compared, even on really old computers
           | 
           | 3) Re-eval; you can re-eval a region, function, file, last
           | expression etc, during running and/or debugging, which is
           | very flexible ; something wrong, change (or write the same
           | function next to it with a fix; very handy), re-eval and when
           | happy , clean up and save
           | 
           | 4) data formats... We have had, since 'forever' had 'proxy'
           | tooling that converts any incoming and outgoing JSON to and
           | from Lisp lists. While in code, we only work with
           | s-expressions and it makes life so easy.
        
       | katspaugh wrote:
       | Kudos for the Janet shout out!
       | 
       | It's an excellent little language, and Janet for Mortals is an
       | excellent book to learn it. The author has a great sense of
       | humor.
        
       | temporallobe wrote:
       | As a Clojure dev, break loops and REPL-driven workflows sound
       | wonderful, and something we could definitely benefit from, which
       | would make it more like front-end coding with JS/TypeScript using
       | the browser's awesome debugging tools. Sadly, the state of
       | tooling and community support for the Clojure ecosystem seems to
       | be pretty lackluster at present.
        
         | netbioserror wrote:
         | Clojure can kinda-sorta simulate the true REPL workflow, if
         | you're making something like a web server where deep calls down
         | the code hierarchy only happen with each request. So you can
         | rewrite and reload various functions while the server is still
         | running and make requests from your browser again. The caveat
         | is that eventually these redefinitions and overwrites pollute
         | the namespaces and eventually something will break, at which
         | point you reload your server.
        
       | omgmajk wrote:
       | I am also learning common lisp in 2023, I like it!
        
       | trhr wrote:
       | When I want "this will run forever," I write it in Rust.
       | 
       | When I want "this will compile forever," I write it in ANSI C.
       | 
       | When I want "this will live forever," I write it Python 2.7 and
       | make it the backbone of the entire org's infra templating. Bonus
       | points if it's a custom Ansible module.
        
       | Roark66 wrote:
       | I'd be interested in if you considered Guile first and what made
       | you decide in favor of common lisp. Few years ago when I decided
       | its finally time to learn lisp I looked at few variants and Guile
       | seemed to have the benefit of: fairly vibrant(but somewhat
       | hermetic) online community, a sizable manual that describes most
       | frequently used APIs (you can learn the language itself very
       | quickly, but it's the knowledge of the APIs you need to do
       | anything in the "real world"), and being actively maintained and
       | extended. So I chose Guile.
       | 
       | For those that don't know these terms Guile and common lisp are
       | two implementations of the same scheme language (simplifying a
       | lot).
        
         | schemescape wrote:
         | When I looked, I got the impression that Guile didn't run on
         | Windows, and that's a platform I needed to support.
        
       | xedrac wrote:
       | There is something very playful about lisp that is so intriguing
       | to me. I've come to rely heavily on powerful type systems at work
       | (which is amazing), but lisp feels like unbounded imagination
       | flowing at my fingertips.
        
       | 10g1k wrote:
       | There are plenty of old business systems which are critical,
       | can't be removed or turned off, and use LISP, COBOL, etc.
       | Meanwhile, nothing important uses Clojure or other trendy flash-
       | in-the-pan language. If you want an interesting project, sure,
       | use Clojure or something. If you want money, learn COBOL.
        
         | xedrac wrote:
         | I hear this a lot, but have never once seen a COBOL job
         | posting.
        
           | asimovfan wrote:
           | https://de.indeed.com/q-cobol-entwickler-
           | jobs.html?vjk=8d36a...
        
           | manicennui wrote:
           | I think a lot of these jobs go to former employees who now
           | contract.
        
           | 10g1k wrote:
           | That's because gigs in trendy languages come and go, and you
           | might earn good pay for six months, whereas cobol gigs run
           | for 20 years and pay consistently high salaries.
        
         | manicennui wrote:
         | It's not as though the company that bought the consultancy that
         | employs many of the core Clojure people runs a bank with
         | Clojure.
        
         | Capricorn2481 wrote:
         | If we're gonna go off what has the most businesses built on it,
         | LISP wouldn't even be in the top 20
        
         | jcpst wrote:
         | Doesn't walmart use clojure?
        
       | kaveh808 wrote:
       | If you're into 3D graphics, this could be a fun Common Lisp
       | codebase to look at. I have tried to keep it simple and
       | comprehensible.
       | 
       | https://github.com/kaveh808/kons-9
        
         | whartung wrote:
         | Look up Kaveh's CL tutorial videos on YouTube. They're really
         | good.
        
           | bkomarath wrote:
           | I think you are replying to him.
        
             | kaveh808 wrote:
             | My Youtube channel:
             | https://www.youtube.com/channel/UCHNK9EcrAwP7djlwQN4C_tg
        
               | the-smug-one wrote:
               | Well, did you watch the recommended tutorials? Or are you
               | one of those artists that don't watch their own work :-)?
        
               | kaveh808 wrote:
               | If that was intended for me, I rarely watch my own
               | videos. Only when I want to check on something. Don't
               | like the sound of my voice. :)
        
       | jbottoms wrote:
       | Then Prolog should be somewhere on your list also.
        
       | massimosgrelli wrote:
       | Always been fascinated by Lisp, but I never spent enough time to
       | enjoy its elegance and applications. I went through Lurk, a Lisp
       | dialect, a Turing-complete programming language for recursive zk-
       | SNARKs in the last year. I started to grasp a bit of its
       | potential in solving real-world problems, but still too little to
       | understand why it's so right for solving some problems. I'm
       | curious about what other projects you guys are successfully and
       | better solving because of Lisp today.
        
       | dutchblacksmith wrote:
       | Big fan of Lispworks (Yes, there is a free version). Using it in
       | production, as many others. Using Quicklisp in experiments. Not
       | direct in my codebase. Lisp will always be there. Learning Lisp
       | will make you a better programmer, while having fun.
        
       | harshaw wrote:
       | as a manager type, I wish my engineers were more broadly aware of
       | REPL style development and the massive productivity boost it can
       | have for certain kinds of development. I am used to doing a lot
       | of ruby/python/js in REPL, but the idea of a sort of "break into
       | a repl and implement the missing function and continue" sounds
       | really nifty.
        
       | xgdgsc wrote:
       | It' s 2023. It' s time to switch [From Common Lisp to
       | Julia](https://news.ycombinator.com/item?id=32745318)
        
       | massimosgrelli wrote:
       | I'm sorry about my basic question. Back in the 80s, AI was
       | betting on Lisp machines --
       | https://en.wikipedia.org/wiki/Lisp_machine -- now, of course
       | obsolete. Is Lisp still relevant in the AI space?
        
         | ShamelessC wrote:
         | Not really no. It's mostly Python 3. The AI space back then had
         | heavy emphasis on symbolic AI. Modern deep learning algorithms
         | have very little overlap.
        
       | ilrwbwrkhv wrote:
       | Steel Bank Common Lisp is the workhorse which led me to build
       | profitable software companies. I don't think I would be as
       | productive without it. The repl driven workflow is amazing and
       | the lisp images are rock solid and highly performant.
        
         | mathisfun123 wrote:
         | > The repl driven workflow is amazing and the lisp images are
         | rock solid and highly performant.
         | 
         | do people not realize that basically everything vm/interpreted
         | language has a repl these days?
         | 
         | https://www.digitalocean.com/community/tutorials/java-repl-j...
         | 
         | https://github.com/waf/CSharpRepl
         | 
         | https://pub.dev/packages/interactive
         | 
         | not to mention ruby, python, php, lua
         | 
         | hell even c++ has a janky repl https://github.com/root-
         | project/cling
         | 
         | edit: i get downvoted by the lisp crowd every time i bring up
         | that the repl isn't a differentiating feature anymore :shrug:
        
           | memefrog wrote:
           | Of course people "realise" this. But those REPLs are not
           | actually REPLs. They are interactive language prompts. They
           | aren't actually REPLs. As the joke goes, Python doesn't have
           | a REPL: it lacks READ, EVAL, PRINT and LOOP.
           | 
           | Being able to type in code and have it evaluated one line at
           | a time isn't a REPL.
        
             | actuallyalys wrote:
             | IMO, the downside with the term REPL is that if you don't
             | understand the specific Lisp definitions of the terms, it
             | sounds like any other interactive execution environment.
        
             | mathisfun123 wrote:
             | i have no idea what subtle or nuanced distinction you're
             | trying to strike so what exactly do you imagine is the
             | difference between a lisp repl and a python repl?
             | 
             | Edit: people that aren't familiar with python (or how
             | interpreters work in general) don't seem to understand that
             | being able to poke and prod the runtime is entirely a
             | function of the runtime, not the language. In cpython you
             | can absolutely do anything you want to the program state,
             | all the way up to, and including, manually push/pop from
             | the interpreter's value stack (to say nothing of moving up
             | and down the frame stack), mutating owned data, redefining
             | functions, classes, modules, etc. You can even, again at
             | runtime, parse, to AST, and compile source to get macro-
             | like functionally. It's not as clean as in lisp but it 100%
             | gets the job done.
        
               | LispSporks22 wrote:
               | In TFA, go to the "Try this in your favorite repl", try
               | that in your "repl" and that would be the fine
               | distinction you're missing.
        
               | mathisfun123 wrote:
               | >The answer to that question is the differentiating point
               | of repl-driven programming. In an old-fashioned Lisp or
               | Smalltalk environment, the break in foo drops you into a
               | breakloop.
               | 
               | do you want me to show you how to do this in a python
               | repl? it's literally just breaking on exception...
        
               | [deleted]
        
               | eadmund wrote:
               | No, it's not: an exception unwinds the stack all the way
               | up to where the exception is caught. By the time the
               | enclosing Python pseudo-REPL sees the undefined function
               | error, all the intervening stack frames have dissolved.
               | The way it works is that a function tries code, and
               | catches exceptions.
               | 
               | In Lisp (and I believe Smalltalk), it doesn't work that
               | way: there is an indirection. Rather than try/except, a
               | function registers a condition handler; when that
               | particular condition happens, the handler is called
               | _without unwinding the stack_. That handler can do
               | anything, to include reading and evaluating more code.
               | And re-trying the failed operation.
               | 
               | It would be possible to implement this in Python, of
               | course, but it doesn't offer the affordances (e.g.
               | macros) that Lisp has, and it's not built into the
               | language like it is in Lisp (e.g., every single
               | unoptimised function call in Lisp offers an implicit
               | 'retry').
        
               | [deleted]
        
               | ghfwlc wrote:
               | Restarting from the debugger keeps state without third
               | party Python hacks that you mention. In this example
               | Python increments x twice, Lisp just once:
               | >>> x = 0       >>> def f():       ...     global x #
               | yuck!       ...     x += 1       ...        >>> def g(y):
               | ...     h()       ...        >>>        >>> g(f())
               | Traceback (most recent call last):         File
               | "<stdin>", line 1, in <module>         File "<stdin>",
               | line 2, in g       NameError: name 'h' is not defined
               | >>>        >>> def h(): pass       ...        >>> g(f())
               | >>>        >>> x       2
               | 
               | Versus:                 * (setf x 0)       * (defun f()
               | (incf x))       * (defun g(y) (h))       * (g(f))
               | debugger invoked on a UNDEFINED-FUNCTION in thread
               | #<THREAD "main thread" RUNNING {1001878103}>:         The
               | function COMMON-LISP-USER::H is undefined.
               | Type HELP for debugger help, or (SB-EXT:EXIT) to exit
               | from SBCL.            restarts (invokable by number or by
               | possibly-abbreviated name):         0: [CONTINUE      ]
               | Retry calling H.         1: [USE-VALUE     ] Call
               | specified function.         2: [RETURN-VALUE  ] Return
               | specified values.         3: [RETURN-NOTHING] Return zero
               | values.         4: [ABORT         ] Exit debugger,
               | returning to top level.            ("undefined function")
               | 0] (defun h() nil)       ; No debug variables for current
               | frame: using EVAL instead of EVAL-IN-FRAME.       H
               | 0] 0       NIL       * x       1
        
               | FPGAhacker wrote:
               | Can you connect to a running server or other running
               | application, inspect live in memory data, change live in
               | memory data, redefine functions and classes and have
               | those changes take immediate effect without restarting
               | the server or app?
               | 
               | I think that is that is the big difference.
               | 
               | It's a triple edged sword bonded to a double barreled
               | shotgun though, and the very antithesis of the idea of
               | functional programming vs mutable state.
        
               | mathisfun123 wrote:
               | >Can you connect to a running server or other running
               | application, inspect live in memory data, change live in
               | memory data, redefine functions and classes and have
               | those changes take immediate effect without restarting
               | the server or app?
               | 
               | The answer to all of these things, at least in python, is
               | emphatically yes. I do this absolutely all the time. You
               | can debug from one process to another if you've loaded
               | the right hooks. You don't need to take my word for it or
               | even try to do it; you just need to reason a fortiori:
               | python can do it because it's an interpreter with a boxed
               | calling convention and managed memory, just like lisp
               | interpreters.
               | 
               | It's amazing: people will die on this hill for some
               | reason but lisp isn't some kind of mysterious system that
               | was and continues to be beyond us mere mortal
               | language/runtime designers. the good ideas in lisp were
               | recognized as good ideas and then incorporated and
               | improved upon.
        
               | FPGAhacker wrote:
               | Can you give me some links? I don't program clojure much
               | these days but I've never found anything comparable in
               | python.
        
               | mathisfun123 wrote:
               | https://www.jetbrains.com/help/pycharm/remote-debugging-
               | with...
               | 
               | I need to be very clear so that no one misunderstands:
               | this is not proprietary pycharm functionality - this is
               | all due to to sys.settrace and the pydev debug protocol
               | 
               | https://www.pydev.org/manual_adv_remote_debugger.html
               | 
               | So you can hook this up completely by yourself with some
               | work but lucky for you and me pycharm makes it
               | effortless.
        
               | vkazanov wrote:
               | The answer to all these things should be "just doesn't
               | work in practise", not for real programs anyways. Unlike
               | Lisp, Python doesn't lean itself well to this mode of
               | development.
               | 
               | Primitive CLI-like tinkering, figuring out language
               | features, calc-like usage - maybe. But not a single time
               | in 15 years of doing Python across the industry I saw
               | anybody using these features for serious program
               | development, or live coding, or REPL-driven development.
        
               | mathisfun123 wrote:
               | >Primitive CLI-like tinkering, figuring out language
               | features, calc-like usage - maybe. But not a single time
               | in 15 years of doing Python across the industry I saw
               | anybody using these features for serious program
               | development, or live coding, or REPL-driven development.
               | 
               | I swear you people are like ostriches in the sand over
               | this - Django, pytest, fastapi, pytorch, Jax, _all_ use
               | these features and more. I work on DL compilers and I use
               | those features every day - python is a fantastic edsl
               | host for whatever IR you can dream of. So just because
               | you 're in some sector/area/job that doesn't put you in
               | contact with this kind of python dev doesn't mean it's
               | not happening, doesn't mean that python doesn't support
               | it, doesn't mean it's an accidentally supported API (as
               | if such a thing could even be possible).
               | 
               | Really what this convo is doing is underscoring for me
               | how there really is nothing more to be learned from lisp
               | - I had a lingering doubt that I'd missed some aspect but
               | you guys are all repeating the same thing over and over.
               | So thanks!
        
               | vkazanov wrote:
               | Listen, I've been on many sides: Lisp stuff, Python
               | stuff, C stuff, etc. I don't think that "something has to
               | be learned". Lisp has many good ideas, Python has good
               | ideas. But REPL-driven development is not one of them.
               | But let me explain.
               | 
               | You see, it's not about how REPL in Python just does not
               | allow something (even though it is rather primitive).
               | Python makes it superhard to tweak things, even if you
               | can change a certain variable in memory. Here's why.
               | 
               | Think about Lisp programs, including OOP flavours. These
               | fundamentally consist of 2 things: a list of functions +
               | a list a variables. If you replace a function or a
               | variable then every call will go through it. And that's
               | it. You change a function - all calls to it will be
               | routed through the new implementation. Because of REPL-
               | centric culture of things people really do organise their
               | programs around this style of development.
               | 
               | Python was developed with an dynamic OOP idea in mind
               | where everything is an object, everything is a reference.
               | Endless references to references of references to
               | references. It's a massive graph, including methods and
               | functions and objects and classes and metaclasses. There
               | is no single list of functions where you can just replace
               | this name-to-implementation mapping.
               | 
               | TL;DR Replacing a single reference doesn't change much in
               | the general case. It does work in some cases. But that's
               | not enough for people to rely on it as main development
               | driver.
               | 
               | Python fundamentally makes a different tradeoff than your
               | average lisp.
        
               | regularfry wrote:
               | I've mentioned this in a sibling thread, but it's
               | interesting to compare this to Ruby. Ruby _does_ support
               | the sort of redefinition you 're talking about. And yet
               | REPL-centric development isn't primary there, either.
               | Yes, there are very good REPL implementations, but I
               | don't know of anyone who develops at the Ruby REPL the
               | same way you would in a Lisp REPL. Maybe it's a
               | performance thing? Maybe it's the lack of images?
        
               | vkazanov wrote:
               | Lispy expressions are easy to type into a repl? The
               | leaking block reference trouble is still there, btw, just
               | not that bad as in python.
               | 
               | I did explore the problem in python and don't really
               | understand Ruby so no idea.
        
               | LispSporks22 wrote:
               | I think in just about every response you left in these
               | threads, you misunderstood what was being said. Possibly
               | through impatience, or just plain arrogance. I really
               | encourage you to spend some time trying to understand how
               | interactivity/restartability (as in Lisp restarts, not
               | process restarts) is built into the language. Especially
               | if you're specializing in the compilers of dynamic
               | languages.
               | 
               | You might also check out Smalltalk, which has a similar
               | level of dynamism.
        
               | freilanzer wrote:
               | What a condescending answer.
        
               | eadmund wrote:
               | > Really what this convo is doing is underscoring for me
               | how there really is nothing more to be learned from lisp
               | - I had a lingering doubt that I'd missed some aspect but
               | you guys are all repeating the same thing over and over.
               | 
               | No, you keep on misunderstanding what people are trying
               | to tell you. It's a communication failure. The thing that
               | you think you are doing in Python is not the thing that
               | people are doing in Lisp.
               | 
               | As an example, I suppose that when you're developing code
               | in Python's pseudo-REPL you often reimport a file
               | containing class definitions. When you do that, what
               | happens to all the old objects with the old class
               | definition? Nothing, they still belong to the old class.
               | 
               | If you did this on a REPL connected to a server, what
               | would happen to the classes of objects currently being
               | computed on? Nothing, they would still belong to the old
               | class.
               | 
               | In Lisp, it's different. There is a defined protocol for
               | what happens when a class is redefined. Every single
               | object belonging to the old class gets updated to the new
               | class. You can define code to get called when this
               | happens (say, you added a new mandatory field, or need to
               | calculate a new field based on old ones -- and of course
               | 'calculate' could also mean 'open a network connection,
               | dial out to a database and look up the answer' or even
               | 'print the old object and offer the system operator a
               | list of options for how to proceed'). And everything that
               | is currently in-flight gets updated, in a regular and
               | easy-to-understand way.
               | 
               | People are telling you 'with Lisp central air
               | conditioning, I can easily heat my house in the winter'
               | and you are saying 'with Python, I can easily build a
               | fire whenever my house gets cold too!'
        
               | regularfry wrote:
               | Python is the wrong example here. Ruby _did_ inherit
               | Lisp-style class reopening. But then Ruby always was
               | explicitly very lispy.
        
               | nmlrpzt wrote:
               | As others here, I don't understand how those features
               | (seamless continuation of a program with the exact state)
               | could possibly work in Python.
               | 
               | What I do know is that the Python community has a
               | propensity for claiming that approximations of complex
               | features by gigantic hacks work and are sound, while they
               | are not.
               | 
               | The Python community also has an extreme tolerance for
               | unsound and buggy software that is propped up by
               | censoring those who complain. Occasional complaints are
               | offset by happy (and selected) marketing talks at your
               | nearest PyCon.
        
               | darthrupert wrote:
               | Am I some kind of a python unicorn? I do those things
               | with python just about every time I write new python
               | code.
               | 
               | The thing Common Lisp does that python doesn't (so far)
               | is outputting well-performing code.
        
               | vkazanov wrote:
               | No, you're fine. For certain things Python REPL-like live
               | development is ok indeed. Say, if your program boils down
               | to a list of functions. Think request handlers or
               | something.
        
               | lispm wrote:
               | How does it look like in Python? In Lisp:
               | CL-USER 43 > (+ 1 (foo 20))            Error: Undefined
               | operator FOO in form (FOO 20).         1 (continue) Try
               | invoking FOO again.         2 Return some values from the
               | form (FOO 20).         3 Try invoking something other
               | than FOO with the same arguments.         4 Set the
               | symbol-function of FOO to another function.         5 Set
               | the macro-function of FOO to another function.         6
               | (abort) Return to top loop level 0.            Type :b
               | for backtrace or :c <option number> to proceed.
               | Type :bug-form "<subject>" for a bug report template or
               | :? for other options.            CL-USER 44 : 1 > (defun
               | foo (a) (+ a 21))       FOO            CL-USER 45 : 1 >
               | :c 1       42
               | 
               | Note that we are not in some debug mode, to get this
               | functionality. It also works for compiled code.
               | 
               | Lisp detects that FOO is undefined. We get a clear error
               | message.
               | 
               | Lisp then offers me a list of restarts, how to continue.
               | 
               | It then displays a REPL one level deep in an error.
               | 
               | I then define the missing function.
               | 
               | Then I tell Lisp to use the first restart, to try to
               | invoke FOO again. We don't want to start from scratch, we
               | want to continue the computation.
               | 
               | Lisp then is able to complete the computation, since FOO
               | is available now.
        
               | mathisfun123 wrote:
               | >Note that we are not in some debug mode, to get this
               | functionality.
               | 
               | Jesus Christ I swear it's like you ascribe mysterious
               | powers to the parens. Do you think the parens give you
               | the ability to travel through time or reverse the pc or
               | what? Okay it's not in a debug mode but it's in a "debug
               | mode". Like seriously tell me how you think this works if
               | it's not effectively catching/trapping some sigkill or
               | something that's the equivalent thereof?
               | 
               | I have never in my life met this kind of intransigence on
               | just manifestly obvious things.
        
               | lispm wrote:
               | Common Lisp programs run by default in a way that calls
               | to undefined functions are detected.
               | 
               | Here the Lisp simply tries to look up the function object
               | from the symbol. There is no function, so it signals a
               | condition (aka exception). The default exception handler
               | gets called (without unwinding the stack). This handler
               | prints the restarts and calls another REPL. I define the
               | function -> the symbol now has a function definition. We
               | then resume and Lisp tries again to get the function
               | definition. The computation continues where we were.
               | 
               | That's the DEFAULT behavior you'll find in Common Lisp
               | implementations.
        
               | mathisfun123 wrote:
               | >Common Lisp programs run by default in a way that calls
               | to undefined functions are detected.
               | 
               | Cool so what you're telling me is that by default every
               | single function call incurs the unavoidable overhead of
               | indirecting through some lookup for a function bound to a
               | symbol. And you're _proud_ of this?
        
               | ghfwlc wrote:
               | Compared to Python, Common Lisp hardly has any
               | performance issues.
        
               | mathisfun123 wrote:
               | Okay well when pytorch, tensorflow, pandas, Django,
               | flask, numpy, networks, script, xgboost, matplotlib,
               | spacy, scrapy, selenium get ported to lisp, I'll consider
               | switching (only consider though since the are probably at
               | least another 20 python python packages that I couldn't
               | do my job without).
        
               | rwxrwxrwx wrote:
               | For the sake of anyone reading this thread who isn't in
               | the know: many of these libraries are really written in
               | C/C++ and have Python bindings.
        
               | mathisfun123 wrote:
               | i said ported not implemented; the likelihood that any of
               | those libraries sprout lisp bindings is about as likely
               | as them being rewritten in lisp. so it's the same thing
               | and the point is clear: i don't care about some zany
               | runtime feature, i care about the ecosystem.
        
               | svetlyak40wt wrote:
               | That is a typical consumerism: "Give me everything ready
               | to use and then I'll use it."
               | 
               | How about bringing some value to the community?
        
               | User23 wrote:
               | That depends. The Common Lisp standard says nothing on
               | the subject. CMUCL[1] and its descendent SBCL[2] do
               | something clever called local call. It's not terribly
               | difficult to optimize hot spots in your code to use local
               | call. Outside of the bottlenecks, the full call overhead
               | isn't significant for the overwhelming majority of cases.
               | It's not like full call is any more expensive than a
               | vtable lookup anyhow.
               | 
               | [1] https://cmucl.org/downloads/doc/cmu-
               | user-2010-05-03/compiler...
               | 
               | [2] https://www.sbcl.org/manual/#Miscellaneous-
               | Efficiency-Issues
        
               | lispm wrote:
               | I thought you know Lisp? Now you are surprised that Lisp
               | often looks up functions via symbols -> aka "late
               | binding"? How can that be? That's one of the basic Lisp
               | features.
               | 
               | Next you can find out what optimizing compilers do to
               | avoid it, where possible or where wanted.
        
               | mathisfun123 wrote:
               | At no point in time did I claim to know lisp well. I
               | stated my familiarity at the outset. But what you all did
               | was claim to know a lot about every other interpreted
               | runtime without a grain of salt.
               | 
               | >Next you can find out what optimizing compilers do to
               | avoid it, where possible or where wanted.
               | 
               | But compilers I am an expert in and what you're implying
               | is impossible - either you have dynamic linkage, which
               | means symbol resolution is deferred until call (and
               | possibly guarded) or you have the equivalent of RTLD_NOW
               | ie early/eager binding. There is no "optimization"
               | possible here because the symbol is not Schrodinger's cat
               | - it is either resolved statically or at runtime -
               | prefetching symbols with some lookahead or cabinet is the
               | same thing as resolving at calltime/runtime because you
               | still need a guard.
        
               | tsimionescu wrote:
               | What you're missing is that, unlike any other commonly
               | used language runtime, compilation in CL is not all-or-
               | nothing, nor is it left solely to the runtime to decide
               | which to use. A CL program can very well have a mix of
               | interpreted functions and compiled functions, and use
               | late or eager binding based on that. This is mostly up to
               | the programmer to decide, by using declarations to
               | control how, when, and if compilation should happen.
        
               | regularfry wrote:
               | To be fair, any dynamic language with a JIT will mix
               | interpreted and compiled functions, and will probably
               | claim as a strength not leaving to the programmer the
               | problem of which to compile.
               | 
               | Opinions may vary on that point.
        
               | whartung wrote:
               | It should also be noted that by spec symbols in the
               | system package (like + and such) should not be redefined.
               | This offers "unspecified" behavior and lets the system
               | make optimizations out of the box.
               | 
               | Outside of that you can selectively optimize definitions
               | to empower the system to make better decisions at the
               | cost of runtime protection or dynamism. However these are
               | all compiler specific.
        
               | lispm wrote:
               | > But compilers I am an expert in and what you're
               | implying is impossible
               | 
               | > it is either resolved statically or at runtime
               | 
               | Just tell Lisp which calls to statically resolve, inline,
               | optimize. Overwrite the global default.
               | (defun foo (a)         (declare (inline +)
               | (optimize (speed 3))                  (type (integer 0
               | 100) a))         (* 10 (+ 3 a)))
               | 
               | Above tells Lisp to inline the + function, optimize for
               | speed and declares the type of a to be an integer in the
               | range 0 to 100.                 * (disassemble #'foo)
               | ; disassembly for FOO       ; Size: 32 bytes. Origin:
               | #x7006DC8544  ; FOO       ; 44:       40190091
               | ADD NL0, R0, #6       ; 48:       5C0180D2         MOVZ
               | TMP, #10       ; 4C:       0A7C1C9B         MUL R0, NL0,
               | TMP       ; 50:       FB031AAA         MOV CSP, CFP
               | ; 54:       5A7B40A9         LDP CFP, LR, [CFP]       ;
               | 58:       BF0300F1         CMP NULL, #0       ; 5C:
               | C0035FD6         RET       ; 60:       E00120D4
               | BRK #15    ; Invalid argument count trap
               | 
               | As you can see in the machine code, Lisp then uses the
               | native machine code ADD and MUL instructions.
        
               | [deleted]
        
               | tsimionescu wrote:
               | Do you think Python or Ruby or PHP are any different? And
               | yet, not one of them actually chose to use this in a sane
               | way, where a simple lookup error doesn't have to crash
               | the whole program.
        
               | sireat wrote:
               | Hmm, what advantage does Lisp offer here over Python?
               | >>> 1 + foo(20)       Traceback (most recent call last):
               | File "<stdin>", line 1, in <module>       NameError: name
               | 'foo' is not defined       >>> def foo(a):       ...
               | return a + 21         File "<stdin>", line 2
               | return a + 21                ^       IndentationError:
               | expected an indented block       >>> def foo(a):
               | ...   return a + 21       ...       >>> 1 + foo(20)
               | 42       >>>
               | 
               | Mind the hilarious indentation error, as I had not
               | touched the old-school REPL in ages.
               | 
               | In normal day to day operations, I do the same thing
               | daily with Jupyter Notebooks. I get access to as much
               | state as I need.
               | 
               | With notebooks workflow it is normal to forget to define
               | something and then redefine in the next cell. You could
               | redefine function signatures etc. Ideally then you move
               | cells in the correct order so that code can be used as
               | Run All.
               | 
               | I "feel" ridiculously productive in VS Code with full
               | Notebook support + copilot. I can work across multiple
               | knowledge domains with ease (ETL across multiple database
               | technologies, NLP-ML, visualization, web scraping, etc)
               | 
               | Underneath it is same as working in old school Python
               | REPL just with more scaffolding.
        
               | lispm wrote:
               | From what I see in your example, you invoke the form
               | again. In Common Lisp you don't need that. You can stay
               | in a computation and fix&resume from within.
        
               | Sterm wrote:
               | You're losing all the state since you're not being
               | dropped in the closure where the error happened but in
               | the end of the program.
               | 
               | To see the difference use some function counter() instead
               | of 1 in the example.
        
               | kgwgk wrote:
               | > Hmm, what advantage does Lisp offer here over Python?
               | 
               | It does have a clear advantage if instead of
               | (+ 1 (foo 20))
               | 
               | we were doing                   (+ (long-computation-
               | answering-the-ultimate-question-of-life-the-universe-and-
               | everything)            (foo 20))
               | 
               | (Reminder: we're dicussing Common Lisp here.)
        
               | momentoftop wrote:
               | I have been playing again with CL recently and am doing
               | some trivial web-scraping of an old internet forum. I
               | don't use a REPL directly, but just have a bunch of code
               | snippets in a lisp file that I tell my editor to evaluate
               | (similar to Jupyter?). I haven't bothered doing any
               | exception (condition) handling, and so this morning I
               | found this in a new window:                  Condition
               | USOCKET:TIMEOUT-ERROR was signalled.           [Condition
               | of type USOCKET:TIMEOUT-ERROR]             Restarts:
               | 0: [RETRY-REQUEST] Retry the same request.         1:
               | [RETRY-INSECURE] Retry the same request without checking
               | for SSL certificate validity.         2: [RETRY] Retry
               | SLIME interactive evaluation request.         3: [*ABORT]
               | Return to SLIME's top level.         4: [ABORT] abort
               | thread (#<THREAD tid=17291 "worker" RUNNING
               | {1001088003}>)
               | 
               | plus the backtrace. This is in a loop that's already
               | crawled a load of webpages and has some accumulated some
               | state. I don't want a full redo (2), so I just press 0.
               | The request succeeds this time and it continues as if
               | nothing happened.
        
               | varjag wrote:
               | You are not fixing the issue in the dynamic context of a
               | running program. Doesn't matter in this trivial example
               | but is very noticeable when you have a loaded DB cache
               | and a few hundred active network connections.
        
               | getpokedagain wrote:
               | You got a lot of correct but verbose responses. Put in
               | layman's terms you had to run 1 + foo(20) again. If 1 +
               | foo(20) were replaced by a complex and long winded
               | function you would have lost all of that state and needed
               | to run it all again. What if 1 + foo(20) had to read
               | several TB of data in a distributed manner. You would
               | have to do that all again.
               | 
               | There are ways around this and of course you could
               | probably develop your own crash loop system in python but
               | in lisp you simply continue where it failed. It's already
               | there.
               | 
               | You mention doing things in Jupyter and ETLs which are
               | often long running. This could be hugely beneficial to
               | you.
        
               | pritambaral wrote:
               | > Hmm, what advantage does Lisp offer here over Python?
               | 
               | In lisp, I never edit code at the REPL, yet the REPL is
               | what enables me to edit code anywhere. I edit the source
               | files and have my editor eval the changes I made in the
               | source. This gets me the benefit that should my changes
               | work, I don't have to retype them to get them into
               | version control. This works because the Lisp REPL is
               | designed to be able to switch into any existing package,
               | apply code there, and also switch back to the CL-USER
               | package after. My editor uses the same mechanism and only
               | has to inject a single prefix (`in-package :xyz`) before
               | it pastes the code I've selected for eval.
               | 
               | In Python, editing a method in a class inside some module
               | (i.e., not toplevel) is less easy. At least, I haven't
               | found any editor support for it. What I did find is the
               | common advice to just reload the whole module/file.
               | 
               | Okay, so let's reload the whole module, then? Well,
               | Python isn't really built for frequent module reloads and
               | that can sometimes bite. In Common Lisp, the assumption
               | that any code may be re-eval-ed is built in. For example,
               | there's two ways of declaring a global value in CL:
               | defvar and defparameter. The latter is simply an
               | assignment of a value to a variable in the global scope,
               | but the former is special. By default, `defvar` defines a
               | variable only if it's not already defined. So that a CL
               | source file may be loaded and reloaded any number of
               | times without resetting a global variable.
               | 
               | Then there's classes. Oh my. Common Lisp has the most
               | powerful (in terms of flexibility) OO system I know of.
               | Not only can you redefine functions and methods, you can
               | even redefine classes dynamically. Adding a property to a
               | class adds that property to all existing objects of that
               | class. Removing a property from a class removes it from
               | all existing objects of that class. This feature is no
               | longer CL-exclusive, but it is sufficient to offer a
               | massive advantage over Python. I don't need to talk about
               | method combinations, multi-methods and the many other
               | cool features of the Common Lisp Object System here.
               | 
               | Then there's the debugging system. In Python, when an
               | exception is thrown, it immediately unwinds the stack all
               | the way up until it is first caught. So not only do you
               | need to know beforehand where to catch what exception, if
               | you get it wrong you cannot inspect the site of the
               | error. In CL, a condition ("exception") does not unwind
               | the stack until a restart is chosen. Not when it is
               | caught, but rather when -- after being caught -- a
               | resolution mechanism has been chosen. This allows
               | interactive debugging (another cool CL feature) to
               | inspect the stack frames at (and above) the site of
               | error, redefine whatever code needs to be corrected, all
               | before the error is allowed to unwind and destroy the
               | stack. You still need to set-up handlers (and restarts)
               | before the error happens, but you can be absolutely
               | wildly lax and use catch-all handlers anywhere on the
               | stack and restarts that take absolutely anything (even
               | functions) at debug-time so you don't really need to be
               | prescient with your error handling code unlike in Python.
               | 
               | I'm sure there's more, but I think this is pretty
               | sufficient.
        
           | rfrey wrote:
           | The repls you mention are not like lisp repls. You're being
           | downvoted because your comment makes it sound like you've
           | never programmed a lisp but have strong opinions nonetheless.
        
             | bbbobbb wrote:
             | Not the OP but would somebody be able to summarize HOW are
             | the lisp REPLs different then to me? I've written limited
             | amount of clojure and common lisp just to play around and I
             | don't recall any difference between Clojure REPL and the
             | REPL I get for say Kotlin inside IntelliJ idea.
             | 
             | Maybe the ability to send expression from the IDE into the
             | REPL with one keybind but I cannot say it's not possible
             | with the Kotlin one right now because that's not what I use
             | it for.
        
               | bowsamic wrote:
               | The fact that I've never seen a CL lover who can explain
               | this adequately is quite concerning in itself
        
               | svetlyak40wt wrote:
               | Watch this video on Lisp interactive development
               | approach. I've recorded it especially to answer the
               | question:
               | 
               | https://www.youtube.com/watch?v=JklkKkqSg4c
        
               | bbbobbb wrote:
               | Thanks, I forgot about this aspect of live program
               | editing. Whether or not it's possible (or how close just
               | quick live reload) is to this it' definitely not a first
               | class citizen like you presented. It also reminds me of
               | Pharo (or maybe just smalltalk, I've only played with
               | Pharo) where you build the program incrementally "inside
               | out".
               | 
               | It does make me wonder how aplicable this way of
               | programming is to what I do at work but that is more
               | because of the technologies and architectural choices
               | where most of the work is plumbing stuff that is not
               | local to the program itself together. And maybe even for
               | that with the edges mocked out it would make sense to
               | work like this.
               | 
               | Again, interesting video that made me think. Thanks.
        
               | schemescape wrote:
               | Yes, Smalltalk/Pharo also support this.
               | 
               | Being able to interactively update code in response to an
               | error, _without leaving the error context_ and being able
               | to restart stack frames (not just a "catch" or top level,
               | as in most languages) is one of the key features that
               | makes REPL-driven development possible. Or at least
               | that's how I see it.
               | 
               | It's not something you always need to use, but it can be
               | handy, especially for prototyping and validating fixes.
        
               | mathisfun123 wrote:
               | There's a person above saying that it's about being to
               | able to mutate program state from the repl, which is a
               | thing that's also possible in any repl for a language
               | with managed memory.
        
               | ohyes wrote:
               | Cl Condition system + repl = godmode. Your software
               | crashes? Do you go back and set a breakpoint? No, because
               | you're already in the stacktrace in the repl exactly
               | where the crash occurred. You fix the code, reload it,
               | tell it to ether run where it left off, or restart from
               | an earlier point.
        
               | mathisfun123 wrote:
               | Flask and Django have the exact same functionality - I've
               | already said that this thing you guys keep talking is
               | just a matter catching exceptions.
               | 
               | https://flask.palletsprojects.com/en/2.3.x/debugging/
               | 
               | https://docs.djangoproject.com/en/dev/ref/settings/#debug
        
               | ohyes wrote:
               | That is definitely not the same. I write a lot of python
               | code and the interpreter / interactive development is
               | just not as good as it is in Common Lisp.
               | 
               | To my knowledge there's no real "mainstream" language
               | that goes all in on interactive development. Breakpoints
               | and traceback are all perfectly cromulent ways to debug,
               | but it's really not the same, sadly.
        
               | MarceColl wrote:
               | exceptions unwind the stack in all languages I know
               | except in CL
        
               | patterns wrote:
               | and Smalltalk ;-)!
        
               | MarceColl wrote:
               | good to know! but the point still stands :D
        
               | schemescape wrote:
               | Not just from the REPL, but from the REPL _in the context
               | where the error occurred_ , without having to structure
               | the code ahead of time to support this. It's not always
               | an important distinction, but it's handy when prototyping
               | or if the error is difficult to reproduce.
               | 
               | There are some other affordances for interactive
               | programming, such as a standard way to update existing
               | instances of classes. I'm sure you could implement this
               | sort of functionality in any language, but this is
               | universal and comes for free in Common Lisp.
               | 
               | CL also has other interesting features such as macros,
               | multiple dispatch, compilation at runtime, and being able
               | to save a memory snapshot of the program. It's quite
               | unique.
        
             | mathisfun123 wrote:
             | >you've never programmed a lisp but have strong opinions
             | nonetheless
             | 
             | i've written racket and clojure (and mathematica, which is
             | a lisp). not multiple 10kloc but enough to understand what
             | the big ideas are. claiming i just haven't written enough
             | lisp is basically the logical fallacy of assuming the
             | premise.
        
               | behnamoh wrote:
               | > "mathematica is a lisp"
        
               | mathisfun123 wrote:
               | http://xahlee.info/M/lisp_root_of_wolfram_lang.html
               | 
               | http://xahlee.info/M/lisp_vs_WolframLang.html
               | 
               | > WolframLang has all the characteristics of LISP:
               | 
               | seems you either don't know what lisp is or you've never
               | written mathematica
        
               | behnamoh wrote:
               | > "seems you either don't know what lisp or you've never
               | written mathematica"
               | 
               | Meanwhile, you brought up examples from Mathematica docs
               | that talk about head/tails (car/cdr) but by that logic,
               | Python is a Lisp too because you have:
               | list[0]
               | 
               | and                   list[1:]
               | 
               | Maybe your Clojure/Racket experience wasn't enough to
               | teach you what the essence of Lisp was. From your first
               | link:
               | 
               | "Mathematica expressions are in many respects like LISP
               | lists. In Mathematica, however, expressions are the
               | lowest-level objects accessible to the user. LISP allows
               | you to go below lists, and access the binary trees from
               | which they are built."
               | 
               | That right there is telling you that Mathematica is not a
               | Lisp.
               | 
               | Edit: Corrected the Python list example.
        
               | mathisfun123 wrote:
               | I'm sorry but are you really going to pretend like car
               | and cdr are not core to lisp?
               | 
               | >list[0] and list[-1]
               | 
               | That is not car and cdr; closer would be list[0] and
               | list[1:] if lists were cons in python.
               | 
               | >Mathematica expressions are in many respects like LISP
               | lists. In Mathematica, however, expressions are the
               | lowest-level objects accessible to the user. LISP allows
               | you to go below lists, and access the binary trees from
               | which they are built
               | 
               | This is a quote from 1986. I wonder if the language has
               | changed much since then
               | 
               | https://reference.wolfram.com/language/tutorial/Expressio
               | ns....
        
               | behnamoh wrote:
               | Read PG's "Roots of Lisp" and you'll understand what I
               | mean.
        
               | mathisfun123 wrote:
               | I believe that is an argument from authority (if I
               | remember correctly).
        
               | lispm wrote:
               | The content on the pages clearly explain the differences.
               | 
               | Mathematica is a symbolic language based on 'rewriting'
               | There are other examples - Prolog would be an example, a
               | logic language. Also most other computer algebra systems
               | are in this category, similar to Mathematica:
               | Macsyma/Maxima, Axiom, ...
               | 
               | > WolframLang has all the characteristics of LISP
               | 
               | It has many, but there are a lot of differences, too.
               | 
               | The big difference is the actual engine. Mathematica is
               | based on a 'rewrite system'. It translates expressions by
               | applying rewrite rules.
               | 
               | Lisp evaluates expressions either based on an interpreted
               | evaluator or by evaluating compiled code. Lisp has
               | macros, but those can be transformed before the code is
               | compiled or running. The practical effect is that in many
               | Lisp implementations usually all code is compiled, incl.
               | user code. Mathematica uses C++ then. Most of the UI in
               | Mathematica is implemented in C++, where many Lisp
               | systems would implement that in native compiled Lisp.
               | 
               | Thus the computation is very different. Using a rewrite
               | system for programming is quite clunky and inefficient
               | under the hood. A simple example would be to look how
               | lexical closures are implemented.
               | 
               | Another difference is that Mathematica does not expose
               | the data representation of programs to the user all the
               | time, where Lisp programs are also on the surface written
               | as s-expressions (aka symbolic expressions) in text.
               | 
               | The linked page from the Mathematica book also claims
               | that Mathematica is a higher level language. Which is
               | true. Lisp is lower level and languages like the Wolfram
               | Language can be implemented in it. That's one of its
               | original purposes: it's an implementation language for
               | other ('higher-level') languages. Sometimes it already
               | comes with embedded higher-level languages. CLOS + MOP
               | (the meta-object protocol) would be an example for that.
        
               | mathisfun123 wrote:
               | > Another difference is that Mathematica does not expose
               | the data representation of programs to the user all the
               | time, where Lisp programs are also on the surface written
               | as s-expressions (aka symbolic expressions) in text.
               | 
               | I have already addressed this: FullForm
               | 
               | https://reference.wolfram.com/language/tutorial/Expressio
               | ns....
               | 
               | >Thus the computation is very different. Using a rewrite
               | system for programming is quite clunky and inefficient
               | under the hood. A simple example would be to look how
               | lexical closures are implemented.
               | 
               | You're skimming a couple of paragraphs without actually
               | knowing much about Mathematica. It's absolutely not the
               | case that Mathematica is purely a redex system; it's just
               | that it's very good at beta reduction because it has a
               | strong focus on CAS features.
        
               | lispm wrote:
               | > I have already addressed this: FullForm
               | 
               | No you haven't addressed it. The "Wolfram Language" user
               | typically does not write code in FullForm. It's used as
               | an internal representation.
               | 
               | > it's just that it's very good at beta reduction
               | 
               | and not so good at compiling code...
               | 
               | https://reference.wolfram.com/language/ref/Compile.html
               | 
               | See "Details and Options"
        
               | mathisfun123 wrote:
               | >The "Wolfram Language" user typically does not write
               | code in FullForm. It's used as an internal
               | representation.
               | 
               | I have no clue what you're talking about - it's an
               | available primitive and I use it all the time.
               | 
               | >and not so good at compiling code...
               | 
               | Lol I am 100% sure that the majority of lisps cannot be
               | aot compiled.
        
               | kazinator wrote:
               | > _Lol I am 100% sure that the majority of lisps cannot
               | be aot compiled._
               | 
               | Ahead-of-time compiling has been the principal method in
               | mainstream Lisps going back to the 1960's. The Lisp 1.5
               | Programmer's Manual from 1962 describes ahead-of-time
               | compiling.
               | 
               | The curious thing is how can you be "100% sure" in making
               | a completely wrong statement, rather than some lower
               | number, like "12% sure".
        
               | mathisfun123 wrote:
               | >The curious thing is how can you be "100% sure" in
               | making a completely wrong statement, rather than some
               | lower number, like "12% sure".
               | 
               | The reason is very simple and surprisingly
               | straightforward (but requires some understanding of
               | compilers): dynamically typed languages that are amenable
               | to interpreter implementations are _very_ hard to compile
               | AOT. Now note I have since the beginning emphasized AOT -
               | ahead of time - but this does not preclude JITs.
               | 
               | But in reality I don't really care about this aspect - it
               | was the other guy who for whatever reason decided to
               | flaunt that clisp can be compiled when comparing it with
               | Mathematica.
        
               | kazinator wrote:
               | For someone playing with Mathematica, you have a curious
               | intellectual process. To be clear, I'd rather have you
               | doing that than hocking loogies at cars from an overpass.
        
               | eadmund wrote:
               | > Lol I am 100% sure that the majority of lisps cannot be
               | aot compiled.                   CL-USER> (defun foobar
               | (x) (1+ x))         FOOBAR         CL-USER> (disassemble
               | #'foobar)         ; disassembly for FOOBAR         ;
               | Size: 35 bytes. Origin: #x5365BF44
               | ; FOOBAR         ; 44:       498B4510         MOV RAX,
               | [R13+16]                ; thread.binding-stack-pointer
               | ; 48:       488945F8         MOV [RBP-8], RAX         ;
               | 4C:       BF02000000       MOV EDI, 2         ; 51:
               | 488BD3           MOV RDX, RBX         ; 54:
               | FF14251001A052   CALL QWORD PTR [#x52A00110]      ; SB-
               | VM::GENERIC-+         ; 5B:       488B5DF0         MOV
               | RBX, [RBP-16]         ; 5F:       488BE5           MOV
               | RSP, RBP         ; 62:       F8               CLC
               | ; 63:       5D               POP RBP         ; 64:
               | C3               RET         ; 65:       CC10
               | INT3 16                          ; Invalid argument count
               | trap         NIL         CL-USER>
               | 
               | There you go: #'FOOBAR is AOT-compiled down to four MOVs,
               | a CALL, two MOVs, a CLC, a POP and a RET.
        
               | lispm wrote:
               | > I have no clue what you're talking about
               | 
               | That's not good. Try again.
               | 
               | In Lisp adding two numbers looks like this is source
               | code: (+ 1 2)                 CL-USER 41 > (+ 1 2)
               | 3
               | 
               | If I quote the expression and evaluate it, the result is
               | (+ 1 2)                 CL-USER 42 > (quote (+ 1 2))
               | (+ 1 2)
               | 
               | Thus in Lisp the textual representation of code and code
               | as data are the same.
               | 
               | Not so in "Wolfram Language": a + b has a FullForm which
               | looks differently. The user does not write ALL of the
               | code in FullForm notation.
               | 
               | Source notation                 a + b
               | 
               | FullForm                 Plus[a, b]
               | 
               | Lisp:
               | 
               | Source notation                 (+ a b)
               | 
               | FullForm                 (+ a b)
               | 
               | Can you see the difference?
               | 
               | > Lol I am 100% sure that the majority of lisps cannot be
               | aot compiled.
               | 
               | I'd expect that they can. That's a feature since 1962.
               | SBCL for example does AOT compilation by default, always.
               | * (disassemble (lambda (a) (+ a 42)))       ; disassembly
               | for (LAMBDA (A))       ; Size: 36 bytes. Origin:
               | #x7006DC83B4                        ; (LAMBDA (A))
               | ; B4:       AA0A40F9         LDR R0, [THREAD, #16]
               | ; binding-stack-pointer       ; B8:       4A0B00F9
               | STR R0, [CFP, #16]       ; BC:       EA030CAA         MOV
               | R0, R2       ; C0:       8B0A80D2         MOVZ R1, #84
               | ; C4:       3CAA80D2         MOVZ TMP, #1361       ; C8:
               | BE6B7CF8         LDR LR, [NULL, TMP]              ; SB-
               | KERNEL:TWO-ARG-+       ; CC:       DE130091         ADD
               | LR, LR, #4       ; D0:       C0031FD6         BR LR
               | ; D4:       E00120D4         BRK #15
               | ; Invalid argument count trap       NIL
               | 
               | Looks like native ARM64 code to me.
        
               | mathisfun123 wrote:
               | > FullForm Plus[a, b]
               | 
               | How can I make this any more clear? You are able, in
               | Mathematica, to write Plus[a, b] with your own fingers on
               | your own keyboard and it will be interpreted as the same
               | thing as a+b
               | 
               | > I'd expect that they can.
               | 
               | Clisp is not the only lisp - I can name 10 others that
               | cannot be compiled.
        
               | kazinator wrote:
               | If you have time to research Lisp implementations until
               | you gather ten that don't have compilers, you might want
               | to take a few seconds to visit https://clisp.cons.org to
               | find out what Clisp means.
        
               | kazinator wrote:
               | If we count everyone's one-weekend project that evaluates
               | (+ 1 2) into 3, then there are probably thousands of
               | Lisps that cannot be compiled. So what?
        
               | lispm wrote:
               | Then the person should spend another weekend and
               | implement a compiler for it.
        
               | lispm wrote:
               | > You are able, in Mathematica, to write Plus[a, b] with
               | your own fingers on your own keyboard and it will be
               | interpreted as the same thing as a+b
               | 
               | Sure, but it is not Mathematica's InputForm:
               | 
               | https://reference.wolfram.com/language/ref/InputForm.html
               | 
               | The majority of code is written not in FullForm. In Lisp
               | 100% of the code is written in s-expressions.
               | 
               | > Clisp is not the only lisp - I can name 10 others that
               | cannot be compiled.
               | 
               | Typical Lisp and Lisp dialects all can be compiled:
               | Common Lisp, Emacs Lisp, ISLisp, Scheme, Racket, ...
               | 
               | Which Lisps can not be compiled?
        
               | mathisfun123 wrote:
               | >Racket
               | 
               | Do you really know what you're talking about here?
               | 
               | https://docs.racket-lang.org/raco/make.html
               | 
               | >The raco make command accept filenames for Racket
               | modules to be compiled to bytecode format.
               | 
               | That's not a compiler...
               | 
               | I don't claim to be an expert on lisp, so further
               | googling I find
               | 
               | https://racket.discourse.group/t/chez-for-architectures-
               | with...
               | 
               | which has some discussion about this and that native
               | backend.
               | 
               | Suffice it to say I am not any more confident that being
               | compilable is somehow intrinsic to lisp.
        
               | lispm wrote:
               | From the Racket documentation:
               | 
               | https://docs.racket-lang.org/reference/compiler.html
               | 
               | "18.7.1.2 CS Compilation Modes
               | 
               | The CS implementation of Racket supports several
               | compilation modes: machine code, machine-independent,
               | interpreted, and JIT. Machine code is the primary mode,
               | and the machine-independent mode is the same as for BC."
               | 
               | CS is the new implementation of Racket on top of the Chez
               | Scheme runtime. Chez Scheme is known for its excellent
               | machine code compiler.
               | 
               | "Machine code is the primary mode"
               | 
               | > Do you really know what you're talking about here?
               | 
               | Read above.
        
               | patterns wrote:
               | But Racket and Clojure are very different from Lisps such
               | as Common Lisp that embrace the idea of a lively,
               | malleable and explorable _environment_ , which is
               | arguably the biggest idea.
        
           | xbpx wrote:
           | A REPL isn't just a REPL. You are comparing modern day Toyota
           | Corollas to a Spaceship sent from the future to the 80s. One
           | is just different level radical. At least when it's baked by
           | SLY or SLIME
        
             | mathisfun123 wrote:
             | here is the list of slime features on the slime webpage
             | 
             | >Code evaluation, compilation, and macroexpansion.
             | 
             | >Online documentation (describe, apropos, hyperspec).
             | 
             | >Definition finding (aka Meta-Point aka M-.).
             | 
             | >Symbol and package name completion.
             | 
             | >Automatic macro indentation based on &body.
             | 
             | >Cross-reference interface (WHO-CALLS, etc).
             | 
             | https://slime.common-lisp.dev/
             | 
             | and i'm still wondering which of these things i can't do in
             | a python repl? note macroexpansion doesn't count because
             | that's not a dimension of the repl.
        
               | CraigJPerry wrote:
               | >Code evaluation, compilation
               | 
               | I couldn't debug the following in pycharm and add the
               | missing function at runtime, or could i?
               | def interactively_writing_code():
               | this_doesnt_exist_yet()
               | interactively_writing_code()
               | 
               | I don't think i can patch a function at runtime without
               | losing state either in python - the act of redefining the
               | function causes the variables to be reset but in lisp the
               | bindings are untouched.
        
               | mathisfun123 wrote:
               | I just did it - it works perfectly fine. Debug-run your
               | code, an exception will be thrown at the call site, step
               | up one frame from the exception (ie module level), define
               | the missing function, call again and it succeeds - all
               | without leaving the same repl instance. Don't believe me?
               | Try it.
               | 
               | I'll say it again: you guys are in plain denial not about
               | python or lisp as languages but about _how interpreters
               | work_. There 's just nothing more to be said about this
               | dimension of it.
        
               | yaantc wrote:
               | Calling again and continuing are not the same thing.
               | Sure, with the above trivial example it is. But if the
               | parent function has non idempotent code before calling
               | the missing function (like doing some global change /
               | side effects), then calling again will give a different
               | result than just continuing from the current state.
               | 
               | So is it possible to define the missing function and
               | continue from the same state in Python? I don't think so,
               | but I'm not a heavy Python user (just for small/medium
               | scripts).
        
               | mathisfun123 wrote:
               | >So is it possible to define the missing function and
               | continue from the same state in Python? I don't think so,
               | but I'm not a heavy Python user
               | 
               | This is a pointless debate - someone has to catch the
               | exception, save caller registers, handle the exception
               | (if there's a handler) or reraise. Either you have to do
               | it (by putting a try except there) or your runtime has to
               | be always defensively saving registers or _something_.
               | Lisp isn 't magic, it's just a point on trade-off curve
               | and I have without a shadow of a doubt proven that that
               | point is very close to python (wrt the repl). So okay
               | maybe clisp has made some design decisions that make it a
               | hair more effective at resuming than python. Cool I guess
               | I'll just ignore all the other python features where
               | there's parity or advantage because of this one thing /s.
        
               | versteegen wrote:
               | I'll take this as an answer to my sibling comment that
               | the answer is "No". I'm really sad CPython can't do that,
               | but maybe some other Python can. It shouldn't necessarily
               | be any slower for the interpreter to figure out where to
               | jump to before saving the execution trace and jumping.
               | 
               | It's not "pointless", I was tearing out my hair and
               | losing days because I couldn't do this in CPython. Yes,
               | I'd much rather use Python than Common Lisp regardless.
        
               | lispm wrote:
               | This works in compiled Lisp code.
        
               | mathisfun123 wrote:
               | It works in code compiled from c++ too: define and
               | associate a signal handler for sigkill, call a function
               | whose symbol can't be runtime resolved by the linker,
               | sigkill is sent and caught, define your function (in your
               | asm dejure), patch the GOT to point from the original
               | symbol to wherever the bytearray is with your asm, and
               | voila.
               | 
               | I'll say it again: what exactly do you think your magical
               | lisp is doing that defies the laws of physics/computing?
        
               | lispm wrote:
               | > It works in code compiled from c++ too: define and
               | associate a signal handler for sigkill, call a function
               | whose symbol can't be runtime resolved by the linker,
               | sigkill is sent and caught, define your function (in your
               | asm dejure), patch the GOT to point from the original
               | symbol to wherever the bytearray is with your asm, and
               | voila.
               | 
               | I don't need to do anything like that in Lisp. I just
               | define the function and RESUME THE COMPUTATION WHERE IT
               | STANDS in my read eval print loop. << important parts in
               | uppercase.
        
               | mathisfun123 wrote:
               | Do you think the magic fairies are doing it for you? Your
               | interpreter/runtime is still doing it whether you're
               | aware of it or not.
               | 
               | My point is very simple: I can do it too, in any language
               | I want, and so there's nothing special about lisp.
        
               | kgwgk wrote:
               | https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule
        
               | lispm wrote:
               | > My point is very simple: I can do it too, in any
               | language I want, and so there's nothing special about
               | lisp.
               | 
               | The big difference is: "I can do it too" means YOU need
               | to do it. Lisp does it for me already, I have not to do
               | anything. I don't want to know what you claim you can do
               | with C++, show me where C++ does it for you.
               | 
               | Telling me "I can do it too" is not a good answer. Show
               | me where the language implementation (!) does it for you.
        
               | mtlmtlmtlmtl wrote:
               | You act as if you know better than everyone in this
               | thread and yet you don't know the 101 level fact that you
               | can't catch SIGKILL.
               | 
               | Maybe try to relax, and learn some humility.
        
               | nmlrpzt wrote:
               | So you update a single function without updating the
               | global state, using a vile hack. In CL the entire state
               | is saved.
        
               | versteegen wrote:
               | What's being asked is, after defining the missing
               | function, whether it's possible to clear the exception
               | and continue the execution without having to restart from
               | the beginning. This is very useful when you hit an
               | exception after 10 minutes of execution. (This is a real
               | usecase which would have saved me untold hours.)
               | 
               | I hope it's possible somehow, but if you just load pdb
               | (e.g. with %pdb in ipython), pdb is entered in post-
               | mortem mode, from which it's impossible to modify
               | code/data and resume execution. Setting a breakpoint (or
               | pdb.set_trace()) would requiring knowing about the bug
               | ahead of time. Does it only work when interrupting with a
               | remote debugger rather than on exception?
               | 
               | However, it wouldn't be possible if the interpreter
               | unwinds the stack looking for exception handlers before
               | finding that there is none? In other languages/VMs such
               | as SBCL the runtime can look up the stack for handlers,
               | and invoke the debugger before destructively unwinding.
        
               | mathisfun123 wrote:
               | The other guy up above claims this is a feature unique to
               | calling functions, rather than all error states, and that
               | the lisp runtime specifically guards against this. If
               | that's the case then my answer is very simple: it would
               | be trivial to guard function calls (all function calls)
               | to achieve the exact same functionality in python. I'm in
               | bed but it would literally take me 5 minutes (I would
               | hook eval of the CALL_FUNCTION opcode). Now it would be
               | asinine because it's a six-sigma event that I call a
               | function that isn't defined. On the other hand, setting a
               | breakpoint and redefining functions as you go works
               | perfectly well and is the common case and simultaneously
               | the kind of "repl driven development" discussed all up
               | and down this thread.
        
               | versteegen wrote:
               | Thank you, you're very helpful despite this raging flame
               | war. I'm glad to hear you can hook opcodes like that,
               | then you really can do anything. And I really need to
               | give "set a defensive breakpoint and then step through
               | the function" an honest go. Now that you say it, I
               | realise I haven't.
        
               | mathisfun123 wrote:
               | >I'm glad to hear you can hook opcodes like that, then
               | you really can do anything
               | 
               | Just in case someone comes around calls me a liar: the
               | way to do this is to spread the bytecodes out one per
               | line and set a line trace. Then when your bytecode of
               | choice pops up, do what you want (including manipulate
               | the stack) and _advance the line number_ (cpython let 's
               | you advance the manipulate the line number).
        
           | Calamitous wrote:
           | > i get downvoted by the lisp crowd every time i bring up
           | that the repl isn't a differentiating feature anymore
           | 
           | I'd suggest it has more to do with tone than content.
        
         | SanderNL wrote:
         | I think the times when your tech stacks mattered in the
         | slightest are mostly behind us.
         | 
         | Also: it's good you concocted some arcane shit that works like
         | a charm, but now nobody - except the ones whose pay you express
         | in number of zeroes - is touching it.
        
           | eadmund wrote:
           | I think that you're just restating the Blub point of view.
           | You look back on the tech stacks of the past, and can see how
           | they were worse than the ones we have today, but looking at
           | the ones today you think that there are no more improvements
           | to be made -- or at least, none that matter.
           | 
           | Given that (I assume) you really do appreciate how much
           | better the stacks of today are then the ones of the past,
           | that seems a highly unwarranted assumption. Heck, I will tell
           | you this: as much as a Lisp stack _is_ better than the
           | alternatives today, it's not perfect. There's a ton of future
           | work to improve things even above the current state of the
           | art.
           | 
           | But that state of the art is still better than what everyone
           | else is using. What's great about Lisp is that improvements
           | are possible: with other technologies, there are more hard
           | limits on what can be done.
        
             | SanderNL wrote:
             | Given the myriad other variables that go into a successful
             | software business, the choice of stack and its various
             | modes of expressing whatever transformation on whatever
             | data it is you are mangling is so exceedingly minor a
             | consideration that I'm close to experiencing it as
             | professional negligence to even fuss over it to the degree
             | it is being fussed over by many people.
             | 
             | I'm not dissing Lisp by any means by the way.
        
               | freilanzer wrote:
               | I understand your point and it's quite true - but hard
               | problems require adequate tools and I wouldn't choose
               | Java, for example, non-crud stuff.
        
           | underdeserver wrote:
           | If this were true then half the posts in HN would have no
           | audience :)
        
           | Sterm wrote:
           | I always find it odd that people say this. If stack doesn't
           | matter than why not start writing machine code again?
        
             | dgb23 wrote:
             | It's said mostly by people who let others make technical
             | decisions for them. Others being either their bosses or the
             | main stream.
        
             | contrast wrote:
             | I think they meant the stack doesn't matter in the sense of
             | "which stack you choose from the options available", rather
             | than "whether you choose a stack versus writing machine
             | code".
        
               | Sterm wrote:
               | You can hook into the abi for software that runs in Linux
               | trivially. So why isn't machine code acceptable? When you
               | give the honest answer you see why the majority of
               | languages aren't acceptable either.
        
             | dawnofdusk wrote:
             | Agree. ThePrimeagen had something to say about this on one
             | of his streams, responding to someone who said "The
             | programming language doesn't matter, only the programmer."
             | He said something like "If that were true, let's just all
             | go back to writing C, it's pretty good. But then you'd say
             | 'well not exactly...'"
        
             | SanderNL wrote:
             | That's not a good faith interpretation given the near
             | infinite amount of options for conjuring up your favourite
             | moneyprinting system of choice besides "machine code". SBCL
             | is about the most arcane option you can pick and even that
             | can work, which I think actually proves the point: it
             | doesn't matter to any significant degree (anymore).
        
               | Sterm wrote:
               | How else is one meant to read that language doesn't
               | matter?
               | 
               | You can hook into anything that runs in Linux since it's
               | abi is rock solid so the excuse of not being able to use
               | the usual tech stacks doesn't hold water either.
        
         | [deleted]
        
         | winrid wrote:
         | Care to share the companies for those curious?
        
         | haolez wrote:
         | It looks awesome, but I'm too lazy as of today to go back to
         | Emacs. I usually just use VSCode close to the defaults for my
         | (mostly) Python and JavaScript development. I don't code full
         | time, since I'm on a CTO role.
        
           | nbf_1995 wrote:
           | You may be interested in https://github.com/nobody-
           | famous/alive which brings the power of slime to vscode
           | (Mostly, it's relatively new and missing some features, but
           | getting better all the time)
        
           | ilrwbwrkhv wrote:
           | I don't know if you're interested in Sublime Text or not but
           | https://github.com/s-clerc/slyblime is pretty good. VS Code
           | also has Alive which I heard is good although I don't use
           | Electron apps.
        
             | haolez wrote:
             | Thanks a lot! It does indeed look good.
             | 
             | Btw, what made you choose Common Lisp instead of Scheme
             | (Guile, Racket, etc) or Clojure? What made it more business
             | effective? Genuine curiosity :)
        
       | largbae wrote:
       | I wonder if LLM assist tools like GitHub CoPilot will further
       | consolidate the programming language landscape. The productivity
       | gains from using a well-supported language might raise the
       | barrier to entry for new or niche ones.
        
       | qwerty456127 wrote:
       | > It's 2023, so of course I'm learning Common Lisp
       | 
       | So am I although none of the features mentioned seem useful to me
       | so far (perhaps I will change my mind once I become fluent). I
       | just hope Lisp will make it easier to express my thought in code,
       | minimizing/abstracting all the cruft/boilerplate. To me Lisp
       | expressions seem the most natural way of expressing a thought.
       | 
       | As I primarily am interested in writing GUI apps I hope to master
       | Clog or find/develop a good wrapper around some GUI toolkit.
        
       | schemescape wrote:
       | Wow, wasn't expecting to see my post on here! Eventually, I want
       | to write a follow-up, but I'm still a beginner.
       | 
       | Here's what I've liked about Common Lisp so far:
       | 
       | * The condition system is neat and I've never used anything like
       | it -- you can easily control code from afar with restarts
       | 
       | * REPL-driven programming is handy in situations where you don't
       | quite know what will happen and don't want to lose context -- for
       | example parsing data from a source you're unfamiliar with, you
       | can just update your code and continue on instead of having to
       | save, possibly compile, and restart from the very beginning
       | 
       | * Common Lisp has a lot of implementations and there's a good
       | deal of interoperability -- I was able to swap out
       | implementations to trade speed (SBCL) for memory usage (CLISP) in
       | one case (multiple compatible implementations is one of the
       | reasons I've been leaning towards CL instead of Scheme for
       | learning a Lisp)
       | 
       | * Even as an Emacs noob, the integration with Common Lisp is
       | excellent, and it works great even on my super slow netbook where
       | I've been developing -- this isn't as big of an advantage these
       | days with fast computers, VS Code, and language servers, but it's
       | definitely retrofuturistic
       | 
       | There's also a few things I don't like:
       | 
       | * The most popular package manager (QuickLisp) is nice, but not
       | nearly as featureful as I've become accustomed to with newer
       | languages/ecosystems
       | 
       | * Since the language itself is frozen in time, you need lots of
       | interoperability libraries for threads, synchronization, command
       | line arguments, and tons of other things
       | 
       | * I really, really wish SBCL could support fully static builds,
       | to enable distributing binaries to non-glibc Linux distributions
       | 
       | I'm sure there are more pros/cons, but that's what came to mind
       | just now.
        
         | vindarel wrote:
         | > lots of interoperability libraries
         | 
         | That's true. For cases when you want to start with a good set
         | of libraries (json, csv, databases, HTTP client, CLI args,
         | language extensions...), I am putting up this collection
         | together: https://github.com/ciel-lang/CIEL/ It can be used as
         | a normal Quicklisp library, or as a core image (it then starts
         | up instantly) or as a binary.
         | 
         | It can run scripts nearly instantly too (so it isn't unlike
         | Babashka). We are ironing out the details, not at v1.0 yet.
         | 
         | > handling a runtime error by just fixing the broken code--in-
         | place, without any restarts [from the blog]
         | 
         | Also (second shameless plug) I should have illustrated this
         | here: https://www.youtube.com/watch?v=jBBS4FeY7XM
         | 
         | We run a long and intensive computation and, bad luck, we get
         | an error in the last step. Instead of re-running everything
         | again from zero, we get the interactive debugger, we go to the
         | erroneous line, we compile the fixed function, we come back to
         | the debugger, we choose a point on the stackframe to resume
         | execution from (the last step), and we see our program pass.
         | Hope this illustrates the feature well!
        
         | CodeCompost wrote:
         | Small typo enusre => ensure
        
         | easeout wrote:
         | Love your site's CGA vibes.
        
           | distcs wrote:
           | Maybe I'm missing something. What about the site is giving
           | CGA vibes?
        
             | wott wrote:
             | The 4-colour palette with cyan and magenta.
        
           | schemescape wrote:
           | That is exactly what I was going for!
        
         | matrix12 wrote:
         | I will give you a cons. https://cons.io Gerbil/Gambit scheme
         | are fully static binary generating alternative to CL.
        
           | schemescape wrote:
           | I'll take a look, thanks! My biggest concern with Scheme is
           | that each implementation seems to have its own ecosystem due
           | to subtle incompatibilities.
           | 
           | From an outsider's perspective it seems a lot more fragmented
           | than CL. Not necessarily a big deal if you have the libraries
           | you want, but it gives me pause.
        
             | bitwize wrote:
             | R7RS, which Gambit (mostly?) supports, helps mitigate this
             | by making library code more portable across
             | implementations. Gambit, in particular, can also very
             | easily take advantage of the wide variety of C libraries;
             | it has one of the easiest, most integrated FFIs of all
             | Scheme implementations.
        
         | TheOtherHobbes wrote:
         | LISP continues to be a very interesting language.
         | 
         | But REPL development is a mixed blessing. There are many
         | situations where you _want_ to start from a blank slate with no
         | previous state.
         | 
         | LISP would be a more practical language if it included a
         | trivial option to make that possible.
        
           | agumonkey wrote:
           | I wish there was some, even theoretical, effort to fix this.
           | It's a crossdomain issue, even react in a way deals with
           | that.
        
           | aidenn0 wrote:
           | > LISP would be a more practical language if it included a
           | trivial option to make that possible.
           | 
           | If you're using SLIME: M-x restart-inferior-lisp
        
           | jabradoodle wrote:
           | Never programmed in common lisp but I imagine it is trivial
           | to enumerate all refs and unbind them.
        
           | anonzzzies wrote:
           | I just create new / changed functions next to the others and
           | eval the selected region, then clean up. When I think i'm
           | done, I'll restart the repl and try if it all is fine or if I
           | depended on something in the state. That doesn't often happen
           | anymore. I use the repl to try out things I just written in
           | files. I can't say I remember a moment when state was a/the
           | problem.
           | 
           | M-x slime-restart-inferior-lisp
           | 
           | works fine.
        
           | Tcepsa wrote:
           | I usually add one or more _reset_ functions, and then I can
           | customize whatever state I want to return to.
        
           | ColonelPhantom wrote:
           | In that case, can't you just restart the REPL? Or give the
           | program a main function that you run?
        
             | realharo wrote:
             | Won't you also be more likely to write code based on data
             | that you happen to have in the _current_ situation, but not
             | for data that covers _every_ situation?
             | 
             | E.g. code that accesses an optional property as if it was
             | always present, because it happens to be present when
             | you're writng the code, etc.
             | 
             | That seems like a possible pitfall when relying on a REPL
             | heavily, but I haven't used such a language myself, so
             | can't speak from experience.
        
               | aidenn0 wrote:
               | And with TDD, aren't you ore likely to write code based
               | on the _current_ tests you have, but not code that covers
               | _every_ situation?
               | 
               | Any time writing code, you (should) aim for the general
               | situation and then test it with whatever edge-cases you
               | think of at the time. The REPL lets you live-test. I know
               | many people who dump their REPL history to a file and
               | turn them into tests.
        
               | realharo wrote:
               | My point was, having an actual _example_ of data in front
               | of you, instead of only definition of the structure
               | /schema/interface/type of the data could push people more
               | towards relying on things specific to that example.
               | Especially in dynamically typed languages, but also for
               | things like trying to take the first element of a list
               | that might be empty (in languages where that doesn't
               | return an `Option`), etc.
               | 
               | And I wonder whether someone observed that in practice.
        
               | pfdietz wrote:
               | My attitude with tests is not to write individual tests
               | when I can write property-based tests. The payoff from
               | the latter is considerable. Let the computer do the work
               | of generating and running tests; its time is worth a
               | whole lot less than mine.
               | 
               | For individual tests, say for coverage, these should also
               | be generated automatically if possible, say by looking
               | for inputs that kill mutants. I've backburned a Common
               | Lisp system for doing this, generating mutants from
               | Common Lisp source forms and automatically searching for
               | and minimizing inputs that kill new mutants. Maybe one
               | day I'll finish this and put it out there for general
               | use.
        
         | atgreen wrote:
         | Check out ocicl as an alternative to quicklisp!
        
         | chlorion wrote:
         | I have some cons!
         | 
         | Last time I checked on it, QuickLisp doesn't support fetching
         | packages over anything except for plain http, with no
         | encryption and no verification mechanism in place to detect
         | files that may have been tampered with during transmission.
         | 
         | I think not supporting encryption or authentication for
         | something as important as fetching source code makes QL a non-
         | starter for me and hopefully for anyone else who cares about
         | security.
         | 
         | Another issue I have ran into, is that SBCL is hosted on
         | sourceforge, which has in the past injected malware into
         | projects downloadable archives! I consider this to also be a
         | security issue, and sourceforge in general is not pleasant to
         | work with. I don't think there are any valid reasons to
         | continue to use sourceforge today, so why such an important
         | project continues to use it confuses me a lot.
         | 
         | I don't see these issues mentioned by anyone else which is
         | bizarre to me.
         | 
         | I really like lisps and common lisp specifically but things
         | like this has driven me away from using it and it doesn't
         | appear that anyone cares about fixing these things.
        
           | LispSporks22 wrote:
           | > Last time I checked on it, QuickLisp doesn't support
           | fetching packages over anything except for plain http, with
           | no encryption and no verification mechanism in place to
           | detect files that may have been tampered with during
           | transmission.
           | 
           | I know it's not an excuse, but it was fun as heck booting up
           | "capital M" MacOS (9.2.1) and loading Quicklisp into MCL
           | without any trouble. I'm not even sure that's a supported
           | platform by Quicklisp. https://code.google.com/archive/p/mcl/
        
           | schemescape wrote:
           | Quicklisp doesn't use TLS or signatures? How have I not heard
           | this before?
           | 
           | That would be unbelievably irresponsible. Has this really not
           | been addressed by the CL community?
           | 
           | Edit: here's the issue:
           | https://github.com/quicklisp/quicklisp-client/issues/167
           | 
           | Thanks for bringing this up!
        
             | atgreen wrote:
             | Try ocicl instead of quicklisp. System tarballs are hosted
             | in an OCI registry, and are downloaded via TLS connections
             | (obeying proxies). Tarballs are signed and signatures are
             | stored in the sigstore rekor transparency log for later
             | inspection. https://github.com/ocicl/ocicl
        
               | schemescape wrote:
               | Just wanted to say I did see your other comment and am
               | intrigued by ocicl. Thanks!
        
             | koito17 wrote:
             | The reason for this is quite simple: portability. Quicklisp
             | also uses plain TAR files to distribute dists. Why? Because
             | quicklisp has a built-in TAR extractor written in 100%
             | standard/portable CL. This allows Quicklisp to run on just
             | about everything, from your computer to real LispMs and
             | operating systems like Mezzano.
             | 
             | TLS comes up every time someone discusses Quicklisp, but
             | nobody bothers to go ahead and actually implement it
             | portably (and even if they did, have fun with performance
             | and side channel attacks, both of which require you to
             | break portability to implement well for every platform you
             | want to target).
             | 
             | If you would like a more stereotypical package manager,
             | consider using CLPM. Though one of the big reasons to use
             | CLPM is not encryption IMO, but versioning. ASDF supports
             | locking versions of dependencies, but Quicklisp doesnt ever
             | use this and instead constantly pushes latest of everything
             | from git repositories. This IMO sucks a lot more than using
             | plain HTTP given that this actually breaks code, whereas
             | some MITM from plain HTTP connection to Quicklisp would
             | require so much coordination (and specificity of target)
             | that it's just not in my threat model at all.
        
               | schemescape wrote:
               | > Quicklisp doesnt ever use this and instead constantly
               | pushes latest of everything from git repositories
               | 
               | Yeah, I didn't recall off hand, but this was one of my
               | main complaints with Quicklisp vs. other package managers
               | I've used (for other ecosystems--not CL).
               | 
               | > whereas some MITM from plain HTTP connection to
               | Quicklisp would require so much coordination (and
               | specificity of target) that it's just not in my threat
               | model at all
               | 
               | I hope you're right, but it still seems like an
               | _unnecessary_ risk. Even if I can 't imagine a scenario
               | where someone is able to MITM me (or, more likely, a
               | server I'm deploying code to), there's still the
               | lingering feeling that it's _possible_. I certainly
               | wouldn 't download an executable over HTTP and run it,
               | and downloading library code is fairly similar (although
               | easier to inspect, at least).
        
               | ristos wrote:
               | This does keep coming up, and it's a few years old now. I
               | think Quicklisp can easily still support https while
               | supporting the older packages that are tar+http, which
               | could easily be mirrored in a git repo. Quicklisp has
               | unfortunately taken over the entire ecosystem, making it
               | hard to use anything else, and you often need to depend
               | on it to use a lot of tools in the ecosystem. It sort of
               | reminds me of Systemd in that way.
               | 
               | I agree on the version pinning being a worse situation,
               | and also not having something like "node_modules" for
               | lisp. I haven't tried CLPM since a while back, it was
               | kind of hard to setup back then.
               | 
               | I have a little package manager thing, cl-micropm, that
               | just uses Quicklisp to fetch everything via docker
               | (should probably support podman too), and an .envrc file
               | to tell ASDF to look in the project directory (a project-
               | local node_modules-like folder called "lisp-systems") for
               | systems. That way I can pin my deps manually by picking
               | the commits + git submodule in lisp-systems/, and it's
               | isolated to my local project. I looked into using the
               | Docker container to rewrite the requests to use https,
               | bypassing whatever Quicklisp is doing, but I never got
               | around to that.
               | 
               | I'm looking to switch it to something even
               | simpler/explicit though, cl-pm, that'll only optionally
               | need/use Quicklisp via podman _only_ to figure out what
               | the dependencies are, and then just have a function that
               | uses wget/curl/git-pull to conveniently explicitly pull
               | them in on request. That way you can decide to add a git
               | mirror for an old http library, or pin a specific
               | version, etc. It's slightly more manual than Quicklisp or
               | CLPM, not a big deal, but very easy for anyone with just
               | a little bit of lisp knowledge to understand the whole
               | thing in under an hour.
        
               | aidenn0 wrote:
               | > Quicklisp has unfortunately taken over the entire
               | ecosystem, making it hard to use anything else, and you
               | often need to depend on it to use a lot of tools in the
               | ecosystem. It sort of reminds me of Systemd in that way.
               | 
               | This is a strange statement.
               | 
               | What requires QL to work? In the "bad old days" you had
               | to manually download the sources and drop them somewhere
               | ASDF could find them[1]. This still works. You can
               | blithely live as if QL does not exist and get that same
               | experience.
               | 
               | 1: Yes, there was asdf-install, but I think I managed to
               | get that to work once with about half-a-dozen tries?
        
               | ristos wrote:
               | Ultralisp, Rowsell, Qlot, Quickdocs, etc. Virtually every
               | modern project build/install instructions reference
               | Quicklisp. You have no idea which dependencies you need
               | to pull and from where, which can be a real PITA for a
               | large project. A lot of project code I've looked at also
               | has Quicklisp references in the actual code for whatever
               | reason, usually for testing or building or whatever else,
               | so to run those you need Quicklisp. It's really hard not
               | to say it's taken over the ecosystem or that there isn't
               | lock-in, I don't know what you mean to be honest.
               | Quicklisp is also a curated list gatekept by one person,
               | so whatever is on there isn't really representative of
               | everything that's being worked on. You can publish on
               | Ultralisp if you don't want to wait or if it wasn't
               | accepted, but then you're still using Quicklisp under the
               | hood. And it's hard to discover things on
               | Github/Gitlab/etc because there's a lot of stub repos
               | just trying things out, with little to no stars.
               | 
               | I'd love to see ecosystem support for other package
               | managers. CLPM is still in beta and has been for a good
               | while now. Quicklisp too. Quicklisp famously doesn't
               | support HTTPS, version pinning, project locals, etc,
               | which has really throttled any progress with the Common
               | Lisp ecosystem. It's not like ASDF at all, which is
               | become a standard that's built into a lot of the lisp
               | compilers.
        
               | [deleted]
        
               | eadmund wrote:
               | Quicklisp doesn't need to support TLS, but it _does_ need
               | to support authentication of some sort. Signing files
               | would be good enough.
        
               | joe-user wrote:
               | Are you proposing authentication over an insecure
               | connection? If so, then the credentials could be
               | compromised by a middle man. The same would be true for
               | the signatures.
        
           | ristos wrote:
           | These issues get mentioned a lot, you just haven't noticed I
           | guess. Sourceforge is also an issue with some C libraries
           | too, I'm guessing because it was done a long time ago? not
           | sure.
           | 
           | I use ECL because it has really good C interop. It actually
           | lets you inline C and access macros directly, making it a
           | great glue language for C libraries. It's what I'm using it
           | for now. I think you might even be able to avoid the GC
           | entirely and use it to script C programs together in a
           | performant way, by using the C FFI to allocate and manage the
           | memory, including the ECL types, instead of the GC. And
           | that's actually doable because of how good the
           | inspector/debugger for lisp is. You can even inline assembly.
           | I'm working on a bunch of CL stuff around this sort of thing,
           | I plan to do a writeup of it and share it once I've developed
           | it more.
           | 
           | Lisp has it's downsides, but the C FFI/embeddability, along
           | with the excellent low-level debugger/inspector,
           | interactivity, and conditions and restarts, makes it worth
           | the time for me to invest in it. And the stability of the
           | language. My main gripe is the reader, but it's easy-ish
           | enough to avoid the problems with named-readtables, or a
           | simple lisp parser for `read` or whatever. I like Clojure,
           | but it's missing some key stuff from the old lisp world that
           | I'd love to see. Shadow-cljs is awesome.
        
           | momentoftop wrote:
           | When I started using CL 20 years ago, libraries were stored
           | on cliki and any malicious user could put malware there. Any
           | source you asdf-installed was generally GPG signed and the
           | installer automatically checked signatures against your
           | personal trust-chain.
           | 
           | Learning CL back then was my first introduction to GPG (and
           | Emacs, and Linux)
        
             | aidenn0 wrote:
             | > When I started using CL 20 years ago, libraries were
             | stored on cliki and any malicious user could put malware
             | there. Any source you asdf-installed was generally GPG
             | signed and the installer automatically checked signatures
             | against your personal trust-chain.
             | 
             | Which, in practice, involved downloading GPG public keys
             | from cliki because I didn't know every single CL developer.
        
           | lukego wrote:
           | Nix has a really convenient new CL libraries packaging
           | upstream now. That verifies everything with sha256. It's
           | quite complete because it's seeded from Quicklisp and had
           | more packages added on (aswell as their native library
           | dependcies.)
           | 
           | Nix isn't to everyone's taste but it demonstrates that you
           | can treat security/reproducibility/etc as orthogonal to
           | Quicklisp and Sourceforge (and to Lisp native tooling in
           | general.)
        
           | vindarel wrote:
           | Solutions for the lack of https:
           | 
           | - add in https://github.com/rudolfochrist/ql-https (downloads
           | packages with curl)
           | 
           | - use another package manager, CLPM: https://www.clpm.dev (or
           | the newest ocicl)
           | 
           | > CLPM comes as a pre-built binary, supports HTTPS by
           | default, supports installing multiple package versions,
           | supports versioned systems, and more.
           | 
           | - use mitmproxy:
           | https://hiphish.github.io/blog/2022/03/19/securing-
           | quicklisp...
        
           | sussmannbaka wrote:
           | > I have some cons
           | 
           | I'm sure you do :deg)
        
         | keithalewis wrote:
         | I cdr car less about your cons. Seriously though, mad props for
         | being diligent enough to spend your attention on this. There is
         | a lot to learn from people who came before us and build on
         | that.
        
         | tgbugs wrote:
         | For static builds, if you're willing to run a slightly older
         | version of sbcl daewok's work on building and linking sbcl in a
         | musl environment might be solution you're looking for. I've
         | tried to port his patches to more recent versions but there are
         | segfaults due to changes in upstream.
         | 
         | https://www.timmons.dev/posts/static-executables-with-sbcl.h...
         | https://www.timmons.dev/posts/static-executables-with-sbcl-v...
        
           | schemescape wrote:
           | Yes, I did see that, but I was scared off by having to apply
           | patches :)
        
         | mark_l_watson wrote:
         | Thanks for your write up. I am looking forward to the next
         | installment.
        
           | schemescape wrote:
           | Thank _you_ for your Lisp books!
           | 
           | I like your pragmatic approach of using Lisp where it makes
           | sense and not being afraid to shell out to something else
           | where appropriate (among many other nuggets of wisdom).
        
         | mrcode007 wrote:
         | SBCL supports static builds by saving core with runtime into an
         | executable file you can then copy around at will.
        
           | schemescape wrote:
           | Do they work across glibc verisons or musl libc? My
           | understanding is that they do not.
        
             | baq wrote:
             | If you link against an old version, it'll generally work
             | with a newer one.
             | 
             | Old versions are unfortunately not always compatible with
             | new libraries...
        
             | mark254 wrote:
             | I often use RHEL7-compatible binaries on RHEL8 and Debian
             | (testing) machines, with no problems.
        
       | ungamedplayer wrote:
       | Me too buddy. I'm not even sure how I got to this point, but I
       | can't go back.
        
         | schemescape wrote:
         | Care to share what you're using CL for?
        
           | ungamedplayer wrote:
           | I automate my workflow for approval of rhel kernel content to
           | customers. Keeping the wheels on the delivery of 12 different
           | streams of kernels to customers.
           | 
           | It also controls the workflow of delivery of intermediate
           | "hot fix" kernels between scheduled releases when fixes are
           | needed immediately.
           | 
           | I also use it for gathering metrics on gitlab ci and internal
           | pipelines, alerting if the system is stalling or performing
           | outside acceptable limits.
        
       | nine_k wrote:
       | The scoop: Scheme and Janet are great, but the author wants a
       | more standalone language. What makes the difference is the
       | breakloop, a full-blown REPL that opens when an error in a
       | program occurs. Not a stacktrace, not a debugger; just build from
       | the point where it's currently broken.
        
         | peanutz454 wrote:
         | This sounds so amazing, why is Common Lisp not the most popular
         | language out there? (asking as someone who almost never writes
         | code)
        
           | 0xcde4c3db wrote:
           | It probably didn't help that a bunch of key Lisp people were
           | leaning hard into proprietary $80,000 minicomputers right
           | around the time that commodity(ish) microcomputers were about
           | to massively explode in popularity.
        
           | vindarel wrote:
           | Only five years ago, CL's web presence was not attractive.
           | This included "official" websites and online documentation
           | (despite all the great books). It's better now (common-
           | lisp.net was reshaped, there's lisp-lang.org, a better
           | Cookbook, the CL Community Spec, more YT tutorials...)
           | 
           | there is no full-featured web framework (although you can
           | write web apps of course),
           | 
           | no satisfactory GUI lib (now Gtk4, Qt5 (hard to install),
           | IUP, nice-looking Tk themes, more low-level bindings to
           | graphics libraries etc)
           | 
           | the package manager came late,
           | 
           | good open-source compilers came late,
           | 
           | less choice in editors (now many
           | https://lispcookbook.github.io/cl-cookbook/editor-
           | support.ht...),
           | 
           | and, well, lots of FUD and a language not for everyone.
        
           | atemerev wrote:
           | "Avoid success at all costs"
        
           | jokethrowaway wrote:
           | It's hard to maintain and read. There you go.
           | 
           | I'm not a huge fan of lisp, but I do like the language.
           | Unfortunately, it's way too hard on 90% of the developers.
           | They need some more structure so they can think about one
           | thing at a time, which is why C-like syntax won in the end.
           | 
           | All the best developers I know are into Lisp or Haskell (or
           | both). They can crank out ridiculous code which then goes
           | unused because maintenance would be too much of a burden.
           | Sometimes I write some really complex one-liners (which are
           | like 5-10 lines long) to do some tasks using all the possible
           | hacks to avoid having to type an extra character. I might be
           | able to do that, but most developers wouldn't be able to see
           | how the data get transformed and keep all of that in their
           | mind. Whatever I wrote is unmaintainable by most people.
           | 
           | The reality is that the majority of people can't grasp their
           | mind around complex concepts. Which is ok, most developers
           | write a few API endpoints and some UI components, they don't
           | need much to create value.
           | 
           | We can get some good concepts from the functional world and
           | transfer them to C-like syntax languages though. We can even
           | have some of the programmability of Lisp (but not all of it)
           | via macros.
        
           | tikhonj wrote:
           | Because language popularity is, at best, _loosely_ correlated
           | with any intrinsic qualities of the language itself.
        
             | AnimalMuppet wrote:
             | I was going to disagree with you, until I re-read and
             | noticed the word "intrinsic".
             | 
             | I would say that language popularity is highly correlated
             | with the actual usefulness of the language. But "actual
             | usefulness" covers far more than the "intrinsic qualities"
             | of the language. It also covers the scope and quality of
             | the standard libraries, the third-party libraries, the
             | available tools like compilers, IDEs, and debuggers (which
             | may be third-party), available documentation and training,
             | and people available to hire who know the language. Of
             | those items I listed, the only parts that could be
             | considered "intrinsic" are the standard libraries and the
             | tooling that comes with the language by default.
        
             | db48x wrote:
             | See also advertising. C++ and Java had enormous advertising
             | budgets, while Common Lisp had virtually none. For years,
             | virtually every programming book and magazine was touting
             | C++ and then later Java. Every conference, every keynote,
             | everything a CTO might ever read or notice was telling them
             | to use C++ or Java.
        
               | to23iu42343434 wrote:
               | Sounds like a religion.
               | 
               | https://www.nicklitten.com/if-programming-languages-were-
               | rel...
               | 
               | Unsurprising that C/C++/Java are all put in the 'religion
               | of the book' family, with great emphasis on
               | proselytization.
        
               | pjc50 wrote:
               | C++ itself never had a marketing budget! The nearest you
               | might find is marketing for _implementations_ back when
               | people paid for programming languages, but the only
               | surviving one of those is really Visual Studio.
               | 
               | Lisp has had decades to break out of its niche if it
               | delivered a really advantageous solution, but somehow
               | that never happened.
        
               | eadmund wrote:
               | > Lisp has had decades to break out of its niche if it
               | delivered a really advantageous solution, but somehow
               | that never happened.
               | 
               | I think a huge part of it is that it is not immediately
               | obvious that one needs what Lisp offers, and by the time
               | the system has grown to the extent that the need is
               | obvious, it has also grown to the extent that one no
               | longer sees the fores for the trees. One doesn't think
               | 'oh man, I need garbage collection'; one thinks, 'oh man,
               | I need to manage malloc and free better!'. One doesn't
               | think, 'oh man, dynamic scope would really fit this
               | problem well'; one thinks 'oh man, I need dependency
               | injection.' Peter Norvig famously noted that 16 of the
               | original 23 design patterns were invisible or simpler in
               | dynamic languages such as Lisp+. Heck, there was a time
               | when one couldn't rely on recursion, or even
               | conditionals! But the programmer who has managed to get
               | stuff done without recursion, or without conditionals, or
               | without macros doesn't really see the point. He's even
               | worried: those things may add _too much_ expressivity to
               | the language. Why, folks could write unmaintainable code
               | with them!
               | 
               | Of course, folks write unmaintainable code _without_
               | them, too ...
               | 
               | Anyway, I think a huge issue is one of education and
               | experience. Ours is a massively growing field. The vast
               | majority of folks are juniors, and don't know any better;
               | a portion of their education was miseducation. The
               | seniors often have one year of experience, twenty times
               | (rather than twenty years of experience). Objective
               | standards are rare to nonexistent. Norms and standards
               | are absent.
               | 
               | But yeah, when I'm working on a large project in a
               | language other than Lisp, I often think, 'man, this would
               | be so much easier in Lisp!' or even 'man, this would be
               | _practical_ in Lisp!' (because anything is possible in a
               | Turing-complete language ...).
               | 
               | +: https://norvig.com/design-patterns/ppframe.htm
        
               | db48x wrote:
               | Yes, and whose advertisements do you think show up in
               | every single one of those magazines? Which
               | implementations get mentioned by every single C++ book?
               | Which organization sponsored every single C++ conference?
               | Don't forget that they had stiff competition from the
               | advertising budgets of other large companies, such as
               | Oracle and IBM.
               | 
               | Also, don't forget that Lisp machines were once the most
               | coveted development machines on the market. But Symbolics
               | had to develop not only the language and IDE, but also
               | the OS, the hardware, the microcode, and everything else
               | all at once. It's pretty telling that they soon began
               | running Unix (on a separate processor) and then their
               | next product was an add-in card for an Apple Macintosh II
               | containing a Lisp processor ASIC. By then the C++ hype
               | train was gathering steam and the AI winter had begun.
               | Symbolics didn't survive, and their direct competitor LMI
               | had even less chance. So it's not that Lisp offers no
               | advantages, it's just that market conditions killed off
               | the companies that were offering it. Note that these
               | market conditions were created by advertising and
               | shifting public perception.
               | 
               | I thus return to my thesis, which is that the market
               | success of a language has little, if anything, to do with
               | the advantages of the language. Instead marketing and
               | advertising rule the day.
        
               | pjc50 wrote:
               | > But Symbolics had to develop not only the language and
               | IDE, but also the OS, the hardware, the microcode, and
               | everything else all at once
               | 
               | This was _forty years ago_. Doing LISP advocacy like this
               | just makes people sound like they 're that Japanese guy
               | who refused to surrender until the 1970s. The world has
               | moved on; there have been other opportunities; and LISP
               | has not won them either.
        
           | Blackthorn wrote:
           | It's questionable whether it's really much better than just a
           | debugger with a core dump (what I usually work on, it's not
           | any better). It is, however, a pretty snazzy feature.
        
             | em-bee wrote:
             | with a debugger, after you fix the application, you still
             | have to restart and run it again. the big benefit here is
             | that no restart is required.
             | 
             | smalltalk can do the same btw. i had been working on a
             | small website where a specific request from the browser
             | would fail. instead of sending a failure message the
             | request would just hang. in the mean time on the server in
             | my pharo smalltalk window an error would pop up. when i
             | fixed the error, the download of the request resumed in the
             | browser as if nothing had happened other than a delay.
        
               | behnamoh wrote:
               | I am really curious about your experience with Smalltalk
               | and Pharo!
        
               | em-bee wrote:
               | i am really just a beginner with smalltalk and CL. as a
               | vim user i didn't really have a good integration of the
               | CL repl with the editor (there were tools, but they
               | weren't as straightforward to set up as slime would have
               | been). and when i encountered the breakloop i didn't
               | really know what do to and just tried to get out of it as
               | quickly as i could. (exiting vim is easier ;-) the thing
               | that bothered me was that when i change code in the repl
               | without an integrated editor, then how do i keep track of
               | the changes and make sure i don't loose them? but then, i
               | just never tried to set up a proper environment.
               | 
               | in smalltalk on the other hand you get a nice IDE with
               | all the comforts of a GUI. you have your windows where
               | you browse your code neatly structured in classes and
               | methods. there is a window where you run your app and
               | manage your tests which light up red or green if they
               | fail or pass, another which logs error or other print
               | messages, and if an error happens while an app is running
               | a new window pops up, showing you a trace of what was
               | running and a text field with the code that failed, like
               | in a debugger, and right there you can edit the code and
               | resume.
               | 
               | the code is written to your class, and when you go back
               | to your code browser the change is reflected there, and
               | you can commit it to a version control system. pharo btw
               | has pretty good integration with git, and already a few
               | years ago it almost acted like a git gui. it's probably
               | even better now. the primary downside is that the text
               | editor in pharo is simple, like a browser text area, and
               | not a sophisticated editor like emacs or vim.
        
               | maxwelljoslyn wrote:
               | > [Lisp] the thing that bothered me was that when i
               | change code in the repl without an integrated editor,
               | then how do i keep track of the changes and make sure i
               | don't loose them
               | 
               | > [Smalltalk] the code is written to your class, and when
               | you go back to your code browser the change is reflected
               | there
               | 
               | I feel your pain. "writing the changes back to the source
               | code definition" seemed like a no-brainer desirable
               | feature of a Lisp REPL, yet I could not find a way to do
               | that out of the box using Slime. I'm sure one could
               | program it, however! Bet someone has...
        
               | pritambaral wrote:
               | > ... yet I could not find a way to do that out of the
               | box using Slime.
               | 
               | Here's what I use: edit code, save file, tell slime to
               | eval current defun. I haven't yet suffered indiscipline
               | to hook `slime-eval-defun` to call `save-buffer`. Would
               | that work for you?
        
               | Blackthorn wrote:
               | > with a debugger, after you fix the application, you
               | still have to restart and run it again. the big benefit
               | here is that no restart is required.
               | 
               | We like to make sure everything running in prod is
               | verifiably built from source in-repo. So that's the
               | thing, while it's a really snazzy feature for sure, the
               | value over the rest of the world is on the questionable
               | side. At least for our use case, but I think it's true
               | for _most_ use cases.
               | 
               | edit: Also really curious about your smalltalk and pharo
               | experience. Sounds fascinating!
        
               | em-bee wrote:
               | once you fixed the problem you of course commit the
               | change to the code on disk. there is nothing in the
               | workflow that prevents you from doing that. you are not
               | going to just fix apps in production without running your
               | tests and what not. at worst you fix an error in a
               | production system, and run the tests afterwards to make
               | sure everything is clean. but mostly this feature is used
               | during development when your code is still incomplete.
               | not having to restart every time there is an error simply
               | speeds up your development loop.
        
             | schemescape wrote:
             | In my experience, it's definitely better for prototyping
             | because if you hit an error that is difficult to reproduce,
             | you can update your code and try again, without having to
             | try and create reliable steps to reproduce the problem.
        
               | Blackthorn wrote:
               | Yeah I can see this being a pretty handy feature for
               | prototyping. Otherwise you'll need to, like, catch errors
               | in your main loop to ensure you don't have some program-
               | halting issue while you're working.
        
           | paulddraper wrote:
           | Performance, approachability
           | 
           | Someone's going to argue with me. Fair enough. Provide your
           | explanation.
        
             | em-bee wrote:
             | this is an age old argument, but given the popularity of
             | other slower languages, i'd rather think that
             | approachability is the more critical issue.
        
               | whartung wrote:
               | It's the issue. The ever popular syntax issue continues
               | to haunt it.
               | 
               | CL has had no real "unknown unknowns" for a very long
               | time. While folks who newly discover it feel they found
               | the gold idol in the jungle cave, the cave is, in truth,
               | well explored, mapped, and documented but the idol is
               | left behind.
               | 
               | All excuses to not use CL have long been, or have had the
               | opportunity to be, addressed. Today, it's fast enough,
               | small enough, empowered through utilities and libraries
               | enough, has different build and deployment scenarios to
               | work with a vast array of applications. And yet here we
               | are...still.
               | 
               | ABCL runs on the JVM, which runs everywhere on
               | everything. Clojure, first class system on top of the
               | JVM, but no real adoption. Some, to be sure, likely (I
               | have no data) more than CL itself. But it's still an blip
               | on the radar.
               | 
               | Meanwhile, a bunch of hackers threw together a language
               | sharing many aspects of the core feature set made popular
               | in Lisp and Scheme runtime environments, made it look
               | like an Algol step child with curly braces and
               | everything, and since then an entire ecosystem of
               | software has been written (and rewritten) into this
               | system and it's runtime is the focus of some of the
               | largest companies in the history of civilization.
               | 
               | Raise your hand if you think that if the creators of
               | JavaScript went with an S-expression syntax instead of a
               | C/Java derivative, we'd be running a VBA clone in our
               | browsers (but nowhere else)?
               | 
               | Because at this juncture, THE thing that distinguishes CL
               | and other Lisps from where we are today, is the syntax.
               | Every other charm these systems enjoyed have been cherry
               | picked away.
               | 
               | Advocates say the syntax is not an issue. It's a feature
               | m, not a bug. But the "wisdom of the crowds" has spoken,
               | and they stay away.
        
           | dleslie wrote:
           | Eventually you need to work with other people, and using a
           | common time-shared or multi user session is unlikely. Now
           | consider that lisp images generally can't be easily diff'd or
           | merged.
           | 
           | And with that the edit-and-continue paradigm loses much of
           | its value. If you have to commit changes to a shared source
           | file anyhow then you'll be not much worse off with debugging
           | a core dump.
        
             | Capricorn2481 wrote:
             | I'm confused. Why aren't you all just working on your own
             | machines?
        
               | dleslie wrote:
               | The classic lisp way is to build a runtime image by
               | editing the image while running it, then dumping a
               | binary. You never specifically need to load a source
               | file.
               | 
               | But you can't easily collaborate with that style of
               | development.
        
               | foobarbaz33 wrote:
               | With lisp you typically develop in source files,
               | versioned with Git. The same as any other language.
               | Source files and live development are not mutually
               | exclusive. SLIME can send code snippets from your file
               | over to the REPL for live development. You have your cake
               | and eat it too.
               | 
               | The REPL (or scratch buffer) is typically used for
               | testing/observing. Not the actual source code
               | development. Although it is possible to never write your
               | source code to a file if you're just playing around with
               | a toy experiment.
        
               | kgwgk wrote:
               | > The classic lisp way is to build a runtime image by
               | editing the image while running it, then dumping a
               | binary. You never specifically need to load a source
               | file.
               | 
               | Says who?
        
             | db48x wrote:
             | People say this a lot, but they fail to take into account
             | that you can debug your server live as it continues to
             | handle normal traffic. Even if you don't deploy changes via
             | the REPL, merely debugging the problem in a REPL without
             | restarting anything is a huge win.
        
               | dleslie wrote:
               | Lots of languages that are not lisp have this ability.
        
               | db48x wrote:
               | I don't think that they do. I know that Erlang has
               | something similar; you can reload a module and it will
               | gradually replace the old code as processes are replaced.
               | In principle you could debug a single thread in a C (or
               | C++) program without stopping the others, and some IDEs
               | will let you edit the code and recompile while the
               | program is running (they patch out the old function
               | definition so that it jumps to the new one instead), but
               | good luck doing that in production.
               | 
               | But don't forget that in Common Lisp, you can redefine
               | classes at run time as well as functions. All existing
               | instances of the class will be updated to the new
               | definition, and you can provide the code that decides how
               | the old fields are translated into the new ones if the
               | default behavior is insufficient. Good luck doing that in
               | C or C++.
               | 
               | My favorite story involved a race condition that was
               | discovered in the code running on a satellite, after it
               | had been launched. The software on the satellite was
               | mostly written in Common Lisp (there was a C component as
               | well), so they opened a connection to the satellite,
               | started the REPL, debugged the problem, and uploaded
               | replacement code (which obviously added a lock or
               | something) to the satellite all through that same REPL.
               | While the satellite was a hundred million miles away from
               | Earth, and while it kept performing it's other duties.
               | You can't do that on a system which merely dumps core any
               | time something unexpected happens.
        
               | maxwelljoslyn wrote:
               | Said "software on satellite" story is from Ron Garret,
               | for anyone interested.
               | 
               | https://flownet.com/gat/jpl-lisp.html
               | 
               | > During that time we were able to debug and fix a race
               | condition that had not shown up during ground testing.
               | (Debugging a program running on a $100M piece of hardware
               | that is 100 million miles away is an interesting
               | experience. Having a read-eval-print loop running on the
               | spacecraft proved invaluable in finding and fixing the
               | problem.
        
               | em-bee wrote:
               | examples please, because so far i have only seen this
               | from common lisp and smalltalk. there is also pike where
               | i can reload classes or objects at runtime, thus avoiding
               | a full restart, but it's not as closely integrated as in
               | smalltalk and you actually have to build your app in a
               | way that allows you to do that.
        
               | dleslie wrote:
               | JavaScript immediately comes to mind.
        
               | em-bee wrote:
               | how do you do it? in the browsers debugger? maybe, but
               | that is not integrated with your actual source files, so
               | you have to be careful to track your changes and copy
               | them to your source. that may help in some cases but
               | isn't really practical.
        
               | lenkite wrote:
               | Java supports live debugging and profiling.
        
               | db48x wrote:
               | But that's not the same thing at all. If you're debugging
               | an exception in Java, you cannot continue execution as if
               | the exception had not been thrown at all. With Common
               | Lisp's condition system you can.
        
               | lenkite wrote:
               | Umm.. you can throw an exception, you can return to
               | previous call frame, you can reload modified classes. If
               | you want unlimited code modification, you can use dcevm
               | https://github.com/dcevm/dcevm
               | 
               | https://www.jetbrains.com/help/idea/altering-the-program-
               | s-e...
        
               | regularfry wrote:
               | The question was whether you can _debug_ a live service
               | while it 's handling live traffic. Not whether you can
               | _fix_ it. Java can definitely do the former, and
               | definitely can 't do the latter.
        
               | pjc50 wrote:
               | It's not always usable, but Visual Studio offers this for
               | C# (works most of the time) or C++ (works in fewer cases
               | because of the terrible header model)
        
               | drekipus wrote:
               | Which?
        
           | nine_k wrote:
           | Lisp is more of a meta-language than a mere language. Since
           | it's homoiconic, you eventually end up developing a domain-
           | specific language that works great for your subject area. It
           | also may make it a bit harder to onboard new team members,
           | because the level of abstraction which you can reach can be
           | relly high, all while keeping performance reasonable.
           | 
           | Technically, you could run e.g. a Python program under pdb,
           | break on certain exceptions, and fix things inside a living
           | system. It's just not a customary way to do that.
        
         | lenkite wrote:
         | Isn't all this stuff a vector for malicious code and security
         | vulnerabilities in production ?
        
           | moonchild wrote:
           | No.
        
             | lenkite wrote:
             | Can you explain why this is not ? Code injection in
             | production environments is generally considered an easy
             | attack vector. Lots of CVE's around this in other language
             | SDK's that have been ironed out over the last decade and
             | half. I don't think Common Lisp gets "special protection"
             | here or does it ?
             | 
             | Unless you are restricting this to only development in
             | which case there are a lot more languages other than common
             | lisp that support hot-reloading/re-definition.
        
               | moonchild wrote:
               | > Lots of CVE's around this in other language SDK's that
               | have been ironed out over the last decade and half
               | 
               | Like what? The only notable one I know of is log4shell.
               | And no one advocates not to use java because of rce. Nor
               | javascript, nor python, nor erlang. Compare with c...
        
         | TacticalCoder wrote:
         | That sounds intriguing as a Clojure dev but what happens in the
         | following case (not very lispy code but it's just to show what
         | I don't get):                   (do-it (do-it first))
         | 
         | What if (do-it first) works fine, but it's the call to (do-it
         | (do-it first)) that fails?
         | 
         | I get control right where it's broken, so I can fix the do-it
         | _defun_. Great, I like that. But by fixing it, this means I
         | changed the result of (do-it first).
         | 
         | So the point at which the machine (?) is is a point that's
         | unreachable anymore by the current code.
         | 
         | I hope my example is clear enough.
         | 
         | I really don't understand how that works when fixing what would
         | allow you to continue would change the state at which you're
         | given control to fix things?
        
           | belmarca wrote:
           | Please excuse the really contrived example, but you can do
           | this in Gambit:                   ~ cat do-it.scm
           | (define (do-it x)         (if (> x 0)             x
           | 'error))              (define (do-it-fixed x)         (if
           | (and (number? x) (> x 0))             x             'error))
           | ~ gsi do-it.scm -       > (do-it (do-it 0))       *** ERROR
           | IN do-it, "do-it.scm"@2.7 -- (Argument 2) REAL expected
           | (> 'error 0)       1> ,b       0  do-it
           | "do-it.scm"@2:7         (> x 0)       1  (interaction)
           | (stdin)@1:1             (do-it (do-it 0))       2  ##main
           | 1> ,e       x = 'error       1> (set! do-it do-it-fixed)
           | 1> ,(c x)       error       > (do-it (do-it 0))       error
           | 
           | Per the Gambit docs[1], "The nested REPL's continuation and
           | evaluation environment are the same as the point where the
           | evaluation was stopped.". The call to ,(c x) is really just
           | calling the reified continuation c with argument x.
           | 
           | [1]: https://gambitscheme.org/latest/manual/#Debugging
        
           | em-bee wrote:
           | you didn't necessarily change the result of (do-it first),
           | you may have, but that just means you introduced another
           | error.
           | 
           | i think the approach here is to accept that you fixed the bug
           | for the second call, but you will still have to go back and
           | retest the first call.
        
             | erik_seaberg wrote:
             | Lisp used to specialize in offering extravagantly expensive
             | features, maybe time travel debugging would be a good
             | addition.
        
             | TacticalCoder wrote:
             | > you didn't necessarily change the result of (do-it first)
             | 
             | You're right.
             | 
             | > i think the approach here is to accept that you fixed the
             | bug for the second call, but you will still have to go back
             | and retest the first call.
             | 
             | Gotcha. It looks like a very useful feature. I may actually
             | just try it to try to understand how it works: especially
             | since TFA says the CL integration with Emacs is good (I
             | happen to be an Emacs user).
        
         | belmarca wrote:
         | This is standard in Gambit Scheme as well.
        
           | schemescape wrote:
           | It supports modifying code in the middle of an error and
           | continuing on? I hadn't found that in a Scheme before!
        
             | belmarca wrote:
             | I'm sure you can find differences, but here's an example
             | adapted from the docs[1]:                 Gambit v4.9.5
             | > (let ((x 10) (y (- 1 1))) (\* (/ x y) 2))       \*\*
             | ERROR IN (stdin)@1.30 -- Divide by zero       (/ 10 0)
             | 1> ,e       x = 10       y = 0       1> (set! y 2)       1>
             | ,(c y)       4       >
             | 
             | [1]: https://gambitscheme.org/latest/manual/#Debugging
        
         | BaseballPhysics wrote:
         | > What makes the difference is the breakloop, a full-blown REPL
         | that opens when an error in a program occurs. Not a stacktrace,
         | not a debugger; just build from the point where it's currently
         | broken.
         | 
         | This just makes me wanna bust open a smalltalk image...
        
       | Zambyte wrote:
       | I don't see why the author says:
       | 
       | > I had previously abandoned using Scheme because, frankly, I ran
       | out of free time for exploratory programming.
       | 
       | But they find Common Lisp acceptable. In what way are Schemes
       | more "exploratory" than Common Lisp? Isn't that exactly what the
       | author says they like about CL (REPL driven development)?
        
         | schemescape wrote:
         | Sorry that was unclear. What I meant was: a while back, I was
         | exploring Scheme (motivated by SICP) and then ran out of free
         | time. Now, I've got some free time again and want to try Common
         | Lisp because of the REPL-driven workflow.
         | 
         | It wasn't meant to be a comment on Scheme vs. CL.
        
           | Zambyte wrote:
           | I see, thanks for clarifying!
        
           | em-bee wrote:
           | i found the repl driven workflow intriguing but i could never
           | get into it. i am not an emacs user and the vim integration
           | wasn't as good as slime promises to be and i couldn't really
           | get comfortable running lisp from within vim. not ssure, i
           | probably didn't try to hard.
           | 
           | smalltalk on the other hand made this a lot easier. not repl
           | driven but having an actual UI to manage code and handling
           | errors it provides the same ability to fix issues at runtime
           | without restarting but with a nicer interface to manage the
           | code.
        
           | gorjusborg wrote:
           | Thanks for clarifying.
           | 
           | I recently went into the lispy rabbit hole for a while.
           | 
           | Scheme is so beautiful.
           | 
           | CL seems more willing to compromise for pragmatism.
        
             | db48x wrote:
             | Yes, CL is extremely pragmatic. And Scheme was invented
             | specifically as a pedagogical tool, so everything is much
             | cleaner. At least until you install scm-utils, and find
             | that it added an entire computer algebra system and physics
             | simulation system and so on. :)
        
       | robomartin wrote:
       | Let me preface this by saying I used LISP professionally in the
       | '80's for about ten years.
       | 
       | It's a great language. It is right up there at the top of my list
       | with Assembler, APL and Forth as languages that taught me so much
       | more than the typical C-like language path most people are
       | exposed to today. And, yes, I used those languages professionally
       | for years.
       | 
       | I have always said it is important to learn these non-C
       | languages.
       | 
       | However...
       | 
       | > I've spent some time contemplating future-proof programming
       | languages because I want to ensure that code I write will be
       | usable in the future.
       | 
       | I think it is clear that it will not be long until you can use an
       | AI-based tool to translate any program from language A to
       | language B. And, in fact, likely improve, maintain and extend it.
       | 
       | For example, you might be able to have the AI tool write a
       | function or module in assembler targeted at different processors
       | and be able to accelerate critical code in a platform-specific
       | manner that would be almost impossible for most developers to
       | manage and maintain today.
       | 
       | I experimented with some of this using ChatGPT. We built a
       | product using MicroPython that require hard real time
       | performance. Sure, MicroPython was not the right choice to begin
       | with. This was one of those projects where we walked into
       | something that morphed and we were stuck. Being that I am
       | perfectly comfortable in assembler, I replaced chunks of code
       | with ARM assembly routings. The performance boost was massive, of
       | course.
       | 
       | As an experiment, I wrote a specification for one of those
       | modules and asked ChatGPT to write the code in ARM assembler. It
       | took all of five seconds to get a listing. Let's just say it took
       | me a lot longer. The code was not optimal, yet, it worked just
       | fine. Someone like me, with experience in the domain, could
       | easily take that as a starting point and improve from there. Just
       | for kicks, I asked ChatGPT to write the same code in C, C++, JS,
       | Python, 8080, 8085, 6502, 68K and x86 assembler. That probably
       | took a minute or so. Did not test all of the generated code. All
       | of it looked like it would run just fine.
       | 
       | In other words, I believe that, today, the only reason to pick a
       | language is likely something like: It's what I know and it has
       | the libraries, frameworks and support I need. In some cases, it's
       | because it's the only way to achieve required performance
       | (example: Python is 70+ times slower than C).
       | 
       | Code longevity is not likely to be an issue at all.
        
         | at_a_remove wrote:
         | I strongly agree. For me, it's the libraries.
         | 
         | Not just having libraries, but having One Obvious Choice. I
         | don't want to compare and contrast libraries, realize that one
         | has sixty percent of what I need, the other has eighty, and
         | they overlap for about forty percent of it.
         | 
         | More and more, I think in terms of algorithms and data
         | structures over anything else. Being able to express those
         | fluently is my focus.
         | 
         | So to bring it around to your comment, what I like to imagine
         | is that someone designs a programming language where the focus
         | is on the ability of the language to be translated to other
         | languages. Then, libraries will be built out, everything that
         | is in standard Python and more. Once a translator is built and
         | tweaked, we could have functional (not like the paradigm)
         | libraries for any langue you fancy.
         | 
         | Yes, the translator would need to be more constrained to avoid
         | "hallucination" and I am sure the resultant libraries would be
         | slow, inefficient, and so on, but they would be _there_. As it
         | stands now, I think there 's a lot of rebuilding the wheel in
         | scores of languages. I wouldn't say that the effort is wasted,
         | exactly, but I can imagine talented programmers making better
         | use of their time.
        
         | behnamoh wrote:
         | > In other words, I believe that, today, the only reason to
         | pick a language is likely something like: It's what I know and
         | it has the libraries, frameworks and support I need.
         | 
         | I would take it even further and say that in the near future,
         | everyone will have their own beloved DSL completely customized
         | to their needs and the AI will be able to translate any code to
         | your favorite DSL. You'll code and commit the changes and the
         | AI will take care of that and convert it back to other peoples'
         | DSL's.
        
         | nescioquid wrote:
         | I was going to reply by suggesting emacs lisp as a candidate
         | language, really making it a bet on how long emacs will be
         | around. Will people (commonly) be using emacs in 50 years? I
         | think people will, though I hesitate to say so. If it turns out
         | that we converge on text as a necessary interface to a computer
         | (at least in some cases), maybe the bet pays off.
         | 
         | But I think your idea that the expression of a program will
         | become fungible or machine-translatable is much more salient.
         | Though if the program itself depends on a whole chain of
         | ancient dependencies and idioms (think a VB UI in front of an
         | Access DB) might run afoul of infinite regress. So, to really
         | future-proof on a long time-horizon, it seems you need to be
         | preoccupied with a lot more than the programming language.
        
       | koito17 wrote:
       | I use Clojure at work but wow do I miss just about everything
       | about Common Lisp whenever I have to debug anything or want
       | performant code. Being able to be in nested errors and click at
       | any part of the stack to inspect lexical bindings is extremely
       | useful, and more importantly, clicking on an object then pushing
       | M-<RET> to copy it to my REPL is much nicer than what Clojure
       | offers (tap>, which I consider a glorified pretty printer even if
       | you use tools like Portal).
       | 
       | As for performance, well, Common Lisp lets you statically type
       | things, and SBCL can emit really efficient code if you do this. I
       | find it helpful to run DISASSEMBLE on my own code to see what
       | exactly is being emitted and optimize from there. And more
       | importantly, packages like SB-SIMD and Loopus are a god send for
       | any number crunching application.
        
         | maxwelljoslyn wrote:
         | This nicely summarizes some of my frustrations with using
         | Clojure for my master's thesis. I'm not unhappy with the
         | choice. Clojure allows such a juicy crossover between
         | "everything is a key-value map, mannn" and "If it has :quack
         | key set to true, treat it like a duck" which works really well
         | for entity-component-system game-design-y things.
         | 
         | but the development story in Common Lisp ... and my gawd, the
         | CONDITION SYSTEM ... were things that I sorely missed for the
         | last year. and I'm not even that experienced of a CL hacker. It
         | just grew on me so quickly. If only CLOS and the primitive data
         | types in CL played together more nicely than they seem to.
        
           | rmckayfleming wrote:
           | I know. I've been spending a lot of time with CL, Scheme, and
           | Clojure the past few years, and the ideal Lisp is some
           | combination of them all. There are aspects of each that I
           | miss in the others. CL has the nicest environment and
           | development story (generally speaking). Scheme feels more
           | refined in the small. And although they can be divisive, I
           | really appreciate Clojure's data structure literals.
        
             | rmckayfleming wrote:
             | CL is the x86 of the Lisps. Successful because of backwards
             | compatibility, but also ugly because of it.
        
         | Capricorn2481 wrote:
         | You should look at flowstorm for Clojure. It lets you step
         | through and back from a function and you can send maps to the
         | repl with their functions.
        
         | jabradoodle wrote:
         | I don't think either language offers a way to send a form to
         | the repl, that is a function of the tooling.
         | 
         | This is certainly easy to do with Cider and I imagine the main
         | tooling in other editors is equally competent.
        
         | [deleted]
        
       | ghfwlc wrote:
       | Common Lisp is still the most pleasant REPL language. The only
       | complaint I have is that too many function names are taken due to
       | the large spec.
        
         | tmtvl wrote:
         | It's fine, you can shadow any function you want: <https://cl-
         | community-spec.github.io/pages/shadow.html>
        
       ___________________________________________________________________
       (page generated 2023-07-27 23:02 UTC)