[HN Gopher] Practical Common Lisp (2005)
       ___________________________________________________________________
        
       Practical Common Lisp (2005)
        
       Author : bikramgig
       Score  : 124 points
       Date   : 2022-01-08 11:34 UTC (11 hours ago)
        
 (HTM) web link (gigamonkeys.com)
 (TXT) w3m dump (gigamonkeys.com)
        
       | alexott wrote:
       | Just in case, there is a Russian translation of this book:
       | http://lisper.ru/pcl/
        
       | em-bee wrote:
       | i learned lisp from this book almost a decade ago.
       | 
       | about two thirds of the way through it gave me enough ideas and
       | material to write two applications that i a, still using today.
        
       | gigamonkey wrote:
       | Hey, thanks everyone for your kind comments on the book. Kinda
       | amazing that we're only a few years away from it's 20th
       | anniversary. -Peter
        
         | jpe90 wrote:
         | This book got me hooked on lisp years ago, I can't thank you
         | enough for writing it. It made both Common Lisp and emacs lisp
         | accessible to me and I would not have learned them if the book
         | did not exist. I hope you consider writing another edition
         | someday.
        
       | dandotway wrote:
       | Having learned a number of Lisp systems in the past, I wouldn't
       | necessarily recommend ANSI Common Lisp as a first choice for a
       | Lisp unless your needs are very particular, because it is an
       | enormous design-by-committee language having a draft standard of
       | about 1360 pages:
       | https://lisp.com.br/archive/ansi_cl_standard_draft_nice.pdf
       | 
       | This means that in addition to the time spent doing the
       | programming that solves your technical problem, you also have to
       | devote considerable time to language lawyering, investigating if
       | the interpretation of a Lisp expression your Common Lisp produces
       | is or is not standard conforming, using only the frequently
       | ambiguous English of that enormous standard as your guide.
       | 
       | The Java JVM was carefully designed to give identical results on
       | all hosts for the Java platform unless you go out of your way to
       | get nondeterminism or platform specific behavior (make the value
       | of the number N depend on thread scheduling, or use JNI that
       | assumes a platform byte order, etc.). C/C++/Rust allow undefined
       | behavior if you shift a 64-bit int more than 64 bits, but Java on
       | the JVM for example masks the lower 6 bits of a 64-bit shift ('&
       | 0x3f') so that you get the same result on all CPUs rather than a
       | CPU-dependent result:                 https://docs.oracle.com/jav
       | ase/specs/jls/se8/html/jls-15.html#jls-15.19
       | 
       | The nice thing about this is that the JVM makes a "try it and
       | see" approach more viable: if your program has a bug at least it
       | has the _same_ bug everywhere. You won 't suddenly get a crash 10
       | years in the future when your customers upgrade to a new CPU,
       | because your Java bytecodes on their new CPU will faithfully
       | maintain bug-for-bug compatibility.
       | 
       | Clojure is a Lisp that runs on the JVM. I haven't personally used
       | Clojure, but having done quite a bit of Common Lisp, Emacs Lisp,
       | Scheme, etc., it looks to be very well designed and very well
       | loved by its users, and using it could spare you from having to
       | language lawyer the ANSI Common Lisp standard, as it seems to be
       | more "try it and see" friendly.
       | 
       | I've been learning a lot about formal verification for C
       | programs, how to truly make code that is bug free, and to do this
       | you need to first make certain decisions about how you are going
       | to formalize the language standard. E.g. will you assume that
       | CHAR_BIT==8 or will you allow CHAR_BIT>=8 because the official
       | ANSI/ISO C standard allows this even though all modern computers
       | have CHAR_BIT==8? Then for any program you input to your verifier
       | you must judge whether all its behavior is well-defined or if
       | there is undefined behavior (arithmetic overflow, etc.).
       | 
       | There are quite good formal verification tools for Java, also,
       | like JBMC and Krakatoa, and smaller Lisp languages are
       | traditionally among the least tedious to formally verify (very
       | simple semantics, unlike Common Lisp), but the time investment to
       | learn these tools is enormous.
        
         | pixelrevision wrote:
         | Clojure seems like the best choice if you want to use lisp in a
         | professional context but is a bit of a double edged sword if
         | learning lisp for exploratory purposes. When things go wrong
         | with Clojure you get back confusing stack traces from the JVM
         | and you have to work through 2 separate paradigms to figure
         | them out. Common Lisp on the other hand has a baked in live
         | interactive environment that lets you work through errors as
         | they come up. This is such a unique (and productive) way to
         | work that it's addictive. That said Clojure's api is just way
         | more intuitive, probably due to when it was created.
        
         | pjmlp wrote:
         | Kind of, there is some fun tracking down JVM specific
         | implementation behaviours.
         | 
         | JIT, GC and extension differences do give space enough for head
         | scratching, although not as much in other ecosystems.
        
           | dandotway wrote:
           | If you have a second, I'm curious to learn more about your
           | head scratching experiences with JVM. I want to make a
           | program that I can trust will still run the exact same (bug-
           | for-bug compatible) many years in the future without
           | maintenance. One approach is to make it completely bug-free
           | using a formal verifier for a strict formalization of C, but
           | this is extraordinary effort and there is no guarantee that
           | bugs in the stack of garbage my app sits atop and the
           | libraries I call (SDL2?) will cause unwanted user observable
           | behavior. Truly bug-free is actually stricter than what I
           | really need; I just need exact bug-for-bug compatibility so
           | that my bugs always are deterministic. It seems with the JVM
           | at least, the bug-for-bug determinism is really good (except
           | when it obviously isn't and can't be, like thread scheduling,
           | network communications, ...). For client GC there is a low-
           | latency guarantee and people seem happy. Have you found the
           | Java GC is not all it's reputed to be? There are so many huge
           | companies with billions invested in Java and its bug-for-bug
           | compatibility, I think it could easily still be around in a
           | 100 years along with COBOL and is a safe investment for
           | individuals who value longevity above what is trendiest and
           | shiniest.
        
             | pjmlp wrote:
             | You can start here,
             | 
             | https://en.m.wikipedia.org/wiki/List_of_Java_virtual_machin
             | e...
             | 
             | Then dive into the public documentation of each of those
             | listed there, specially the ones that aren't plain
             | rebranding of OpenJDK.
        
         | hajile wrote:
         | The Java VM Spec is almost 650 pages.
         | 
         | The core Java spec is another 850 pages. The core Java
         | libraries add countless more pages on top.
         | 
         | The "CL is big" myth is a strange one. Big was in context of a
         | 80286 in 1982. It already wasn't big by the 90s and a full-
         | blown CL implementation is absolutely TINY compared to pretty
         | much any other managed language you can think of.
         | 
         | I can't speak to the VM spec, but the 90s Java spec and the
         | Common Lisp spec were both largely written by Guy Steel (who
         | said that Java was meant as a stepping stone to shift C
         | programmers a little closer to Common Lisp).
         | 
         | ISlisp and EUlisp both attempt to "correct" the Common Lisp
         | language. Neither has been successful and the big reasons are
         | that CL's core features aren't actually broken and the biggest
         | complaint (naming conventions not always aligning well) can be
         | completely fixed with macros if you want (there are dozens of
         | such projects).
        
         | hayley-patton wrote:
         | You can't seriously say that, just because one targets a well-
         | specified machine, that the language being used is well-
         | specified. The determinism of a Clojure-on-JVM program would
         | also be dependent on the particular code the Clojure compiler
         | generates. The code has to remain semantically identical
         | between compiler versions, and it should not introduce any new
         | non-determinism, e.g. that presented in [1]. In Common Lisp
         | there is the Armed Bear Common Lisp implementation, which runs
         | on a JVM. Does it benefit from JVM determinism or not? It
         | probably does not, because the JVM is simply not aware of
         | undefined behaviour that ABCL or Clojure are implicitly
         | defining.
         | 
         | When it comes to having different platforms, it would also be
         | necessary for any other compilers to generate semantically
         | identical code. Different Clojure systems do _not_ do that. For
         | example, arithmetic in ClojureScript uses JS floats where
         | Clojure-on-JVM and others use integers of some size.
         | 
         | In my experience, writing a non-conforming CL program is hard,
         | and much harder than writing a program without undefined
         | behaviour in C. I am not sure why, other than the UB being more
         | "localised" in some vague way. But there is also a modification
         | of the ANSI standard being worked on, which attempts to
         | eliminate undefined behaviour
         | <https://github.com/s-expressionists/wscl>.
         | 
         | [1] Hans Boehm, Threads cannot be implemented as a library
         | <https://web.stanford.edu/class/cs240/readings/p261-boehm.pdf>
        
       | Annatar wrote:
       | Must OOP be shoved down everyone's throat at every turn and
       | opportunity? One of the great things about Lisp is that it's a
       | champion of functional programming, whereas OOP is extremely
       | complicated and it produces truly horrible machine code which
       | needs a lot of CPU cycles and even more memory, not to mention
       | being unnecessarily difficult to understand and debug!
        
         | na85 wrote:
         | If you actually work on a project of significant size I don't
         | see how one can reason about code that's not encapsulated via
         | classes.
         | 
         | I used to contribute to RunUO, an emulator for Ultima Online,
         | and it's near the 1000000-SLOC level. There's too much going
         | on, too much state, too many corner cases, to consider
         | functional as an architecture.
         | 
         | Not every OOP project is full of FactoryFactorys.
        
           | [deleted]
        
           | zelphirkalt wrote:
           | > If you actually work on a project of significant size I
           | don't see how one can reason about code that's not
           | encapsulated via classes.
           | 
           | I can: Modular code using modules, instead of shoe-horning
           | everything into classes. There are way fewer cases, where
           | classes have actual good reasons for existing in a program
           | than people think. Classes should not be the first go-to
           | solution for grouping things together. First one needs to
           | think about behavior and state. Do I even have a state, that
           | needs to live inside an object over the time, that the
           | program runs? If I don't have state, no class. Done.
           | Similarly for when I only have state and no behavior, that
           | needs to be put together with that state. Often a module,
           | which exports functions, which deal with that state, is more
           | than sufficient and does not allow for inheritance
           | nightmares.
           | 
           | > I used to contribute to RunUO, an emulator for Ultima
           | Online, and it's near the 1000000-SLOC level. There's too
           | much going on, too much state, too many corner cases, to
           | consider functional as an architecture.
           | 
           | Sounds exactly like something, that should not be done in the
           | typical OOP everything-calls-everything way, because then you
           | will end up with lots of state changes mutation happening
           | everywhere. It will not even be clear to the implementers of
           | the system. Therefore you will not know what to test for and
           | therefore it might run accidentally, but not in a way, that
           | one can be approximately be sure to be correct. Every test of
           | a complex scenario will require loads of setup test code, so
           | that you can get some kind of environment, which might be
           | similar to what happens in the system. Designing in a
           | functional way would give you a sort of "entrypoint" at every
           | function to test it, giving all required state as arguments.
           | 
           | I don't think OOP is a given in any big project, especially,
           | when looking at how to write unit tests for mostly
           | everything, and when looking at parallelizing stuff. I see
           | OOP perhaps when it comes to building GUIs, but even in that
           | area attempts are being made to use declarative approaches
           | and functional approaches, so maybe in the future we will see
           | OOP lose ground there as well.
        
           | nesarkvechnep wrote:
           | Did you just generalize that every large project must be
           | object-oriented?
        
             | na85 wrote:
             | I'm positing that any project of sufficient complexity is a
             | good candidate for object oriented, yes.
             | 
             | I don't see how a single developer can reason about an
             | entire codebase of hundreds of thousands of LOC.
        
               | jlg23 wrote:
               | Functional programmers argue that pure functions are
               | easier to reason about than functions that drag in state
               | (like methods in OOP tend to).
        
               | na85 wrote:
               | Please list some real-world software of significant
               | complexity that is 100% purely functional.
        
               | jlg23 wrote:
               | Where does the "100% purely functional" requirement come
               | from? By some strict definition, this is impossible,
               | because you'd not have any means of communicating the
               | result of your computation.
               | 
               | In pure OOP speak: A "final static" method is easier to
               | reason about than some non-static, non-final method. (But
               | when a method is defined as "final" and "static", the
               | providing class only serves as a namespace - where is the
               | OOP in that?)
        
               | toomanydoubts wrote:
               | You should probably try writing something under a
               | functional paradigm, emphasizing immutability and pure
               | functions. You'll quickly see how that will help you
               | reason about a large functional project.
        
         | kaba0 wrote:
         | Citation needed
        
           | avodonosov wrote:
           | Not needed. Book about Common Lisp without CLOS does not make
           | sense. BTW, in this book just 2 chapters out of 32 are
           | devoted to OOP.
        
         | dang wrote:
         | We detached this subthread from
         | https://news.ycombinator.com/item?id=29852508.
        
       | _ph_ wrote:
       | I can highly recommend this book! I even own a signed copy :)
       | 
       | There are many other great Lisp books, but this has been written
       | in more recent times by an author who has before written books
       | about other languages, e.g. Java. As a consequence, I think it is
       | much more hands-on and easygoing for people who had learned some
       | of the mainstream languages first and the examples are also more
       | of this age.
       | 
       | It is an excellent and thorough introduction into the language
       | and in contrast to many older books also has very valuable
       | sections about OOP and condition handling.
        
         | thaumasiotes wrote:
         | I went through Practical Common Lisp; it's great.
         | 
         | I made the mistake of assuming the publisher meant something
         | and bought Practical Ocaml, which was awful. :(
        
       | eduardosalaz wrote:
       | This book is so useful and awesome I can't even thank Peter
       | Seibel enough for getting me through my Lisp class.
        
       | peterhil wrote:
       | I learned Common Lisp with this book. I read other books, but
       | this is easy to understand and well presented.
        
       | robert-brown wrote:
       | Google tech talk by the book author:
       | https://www.youtube.com/watch?v=4NO83wZVT0A&t=79s
        
       | runjake wrote:
       | Earlier this year, I decided to learn Lisp for kicks and
       | Practical Common Lisp was the book that resonated with me the
       | most.
       | 
       | The whole experience didn't result in me switching or even
       | continuing to use Lisp, but what it did is show me some of the
       | origins of the features in the languages I already use.
       | 
       | My Python and JavaScript code is definitely more "Lispy" now, if
       | that makes sense.
       | 
       | Trivia: In my studies, I was surprised to learn that recent
       | versions of Excel support lambda functions in formulae.
       | 
       | https://www.microsoft.com/en-us/research/blog/lambda-the-ult...
        
         | zelphirkalt wrote:
         | Python will probably forever remain stunted for its bad lambda
         | syntax, allowing only 1 statement in it. It is not a deal
         | breaker, but annoying to make named things out of anonymous
         | things. Then there is the issue of no TCO. At least JS has that
         | in the spec, even though almost no one implemented it.
        
           | HerrMonnezza wrote:
           | The Python package lambdex [1] provides a way to write multi-
           | line anonymous functions in Python, with a syntax that's
           | close enough to the "normal" Python.
           | 
           | [1]: https://pythonrepo.com/repo/hsfzxjy-lambdex
        
       | funstuff007 wrote:
       | I love this book. I never write Lisp (for fun or profit), but
       | this book made me think more clearly about how to break problems
       | down into their component parts.
        
       | macintux wrote:
       | A couple of old threads with significant commentary:
       | 
       | * https://news.ycombinator.com/item?id=17644067 (84 comments)
       | 
       | * https://news.ycombinator.com/item?id=13096576 (158 comments)
        
       | nanna wrote:
       | I eventually realised that Emacs Lisp ideally assumes you have
       | knowledge of Common Lisp, so I read PCL and now I feel like I can
       | actually write Elisp and know what's going on
        
       ___________________________________________________________________
       (page generated 2022-01-08 23:01 UTC)