3 ms·
The deepest and most radical opinions of Lisp are: - You should be able to implement Lisp-in-Lisp within a few pages of code. This a profound and remarkable de
by ekidd 5y ago
The deepest and most radical opinions of Lisp are:
- You should be able to implement Lisp-in-Lisp within a few pages of code. This a profound and remarkable design constraint. (See http://languagelog.ldc.upenn.edu/myl/llog/jmc.pdf http://languagelog.ldc.upenn.edu/myl/llog/jmc.pdf (PDF) for an introduction.)
- Syntax would only hide the fact that code is a simple data structure that can be manipulated like any other data structure.
Just like Rust's strong opinions buy you stress-free threading and bit-banging, Lisp's opinions ensure that it's an almost ideal environment for inventing domain-specific language extensions.
But Rust is poorly suited to object graphs where everything mutates everything else, and Common Lisp is poorly suited to proving that a large program obeys certain strict rules.
I love opinionated tools, but I try to choose ones with the "right" opinions for the task at hand.
- pharmakom 5y agoThe object graph problem really hurts Rust imo. In C# I can just mutate and forget about ownership. In Haskell I can solve this using an immutable graph and a state monad. In Rust it gets pretty awkward.
- db48x 5y agoYea, but in those languages you have a garbage collector working in the background to clean up after you. You don’t always want to pay that cost. From time to time I work on an open source application that spends 60–70% of its time in garbage collection, at least on jobs at the extreme end of the size we can handle. I’m starting to think about ridiculous hacks like combining millions of moderately–sized objects into a giant arena. With no pointers into the arena (just indicies), I can eliminate a huge chunk of the time wasted scanning the heap over and over again. But at that point, why am I writing this in Go? My Rust prototype is very incomplete, but for the parts that are implemented it uses way less memory and completes a lot more quickly. And I haven’t done _any_ performance optimization or ridiculous hacks there yet.
- pitaj 5y agoAnd in Rust you can always drop down to reference counted heap allocated stuff as well.
- db48x 5y agoThat’s true; the prototype uses Rc/Arc for things where I don’t yet know for sure how the ownership should really work out, and doubtless a fair amount of that will stay.
- tsimionescu 5y agoReference counting has completely different properties than other forms of automatic garbage collection. In particular, reference counting still requires some amount of ownership tracking, whereas this concept just doesn't exist (for memory resources) with tracing garbage collection. This is particularly relevant for certain algorithm, such as atomic initialization, that get significantly more complex with in-line ownership tracking.
- db48x 5y agoOn the other hand, Rc turned out to be just what I needed for a particularly complicated data structure that we use. http://db48x.net/reposurgeon/rust-port-docs/reposurgeon/pathmap/index.html http://db48x.net/reposurgeon/rust-port-docs/reposurgeon/path... Also, because of Rust’s wonderful type system it will be fairly straight forward to replace the string keys in this code with interned strings instead. (The amount of strings we use for paths in a large repository is pretty astounding.) That might now be almost possible in Go, if I learn the new generics.
- pjmlp 5y agoIn those languages you also have the features to do C++ like coding if felling so inclined to do so.
- chrismorgan 5y agoRust has been my favourite language since 2013. I constantly miss its ownership model when working in other languages (which most commonly means JavaScript for me). Certainly not everything is a good fit for Rust’s ownership model, but honestly most code benefits from it at least a bit, and steadily more and more is being figured out about how to mesh other models into it without too much pain. It’s very liberating, protecting from various mistakes that are too easy in other languages (and that’s specifically where I miss it). Ownership modelling can require more effort initially if the problem doesn’t match Rust’s capabilities very well (or put another way, if the problem doesn’t match how hardware works without garbage collection), but subsequently it’s liberating to not need to worry about various problems that are ubiquitous in other languages. I reckon it similar to the debate of static versus dynamic typing, though more subtle. For toys, dynamic typing is adequate and static typing a burden, but as you scale a system up, dynamic typing makes life harder and requires more discipline to avoid ossification or drowning from technical debt. It’s taken time, but there has been a significant resurgence in static typing as people slowly come to realise its value through bitter experience in dynamic typing. Like static typing, a strict ownership model requires more effort initially, but makes life easier down the path, and I expect that at least the basic concepts of it will be picked up in more languages new and old over time (this has started already, actually, with Swift and D springing to mind), though it’s probably a harder concept to beneficially retrofit to a language than static typing. You may want to mutate and forget about ownership, but Rust doesn’t let you do this, and it’s for your own good ;-). In time you get more of a feeling of why it is the way it is and learn to appreciate it.
- User23 5y ago> Common Lisp is poorly suited to proving that a large program obeys certain strict rules As I'm sure you know, a Lisper would probably design a domain specific language that was well suited for such proofs. One of the projects I'd like to get around to one day is a Lisp hosted general purpose DSL[1] based on predicate transformer semantics[2] that combines writing specification and program text into a single interactive experience. Think something along the lines of smartparens[3] strict mode, where the editor doesn't allow you to make an edit that will violate the count("(") == count(")") invariant and you modify the tree structure with operations like slurp and barf, but a bit more general. [1] Haha, I know. [2] https://en.wikipedia.org/wiki/Predicate_transformer_semantics https://en.wikipedia.org/wiki/Predicate_transformer_semantic... [3] https://ebzzry.com/en/emacs-pairs/ https://ebzzry.com/en/emacs-pairs/
- cwilkes 5y agoWrite a DSL … and now you have two problems.
- roca 5y agoThe thing is, the sea-of-objects-where-everything-mutates-everything-else programming model is fundamentally bad. It's too hard to reason about. Programs and data need structure. There certainly are structures that do not easily fit into Rust's constraints (e.g. when you're modelling an arbitrary graph), but when you choose a sea-of-objects design when not absolutely required by the problem domain (and it almost never is), you choose poorly. Even if you do need to model an arbitrary graph (for example), though a traditional programming language would make it a lot easier than in Rust, I still wouldn't necessarily let that dictate the choice of programming language. Most likely your program will end up doing a lot more than just banging on the graph and those parts may benefit from a more disciplined programming language.
- int_19h 5y agoYou can structure mutation just fine by organizing those objects into hierarchies of abstraction, such that a sea of objects on one level becomes a single black box on the next. This keeps the "seas" small enough to reason about.