3 ms·
As mentioned, types are in the standard, and certain implementations provide compile time warnings of type and other issues...[0] The biggest non-feature advan
by Jach 8y ago
As mentioned, types are in the standard, and certain implementations provide compile time warnings of type and other issues...[0]
The biggest non-feature advantage (the condition system is a pretty big feature though missing from everything else) is the mindset of writing programs, which other dynamic languages typically don't get right. The idea of "growing" a program, and responding to change, is part of that mindset and once it's internalized a lot of the language decisions make a lot more sense. e.g. "trace", "break", "compile" are all part of the standard, all available at runtime, whereas in other languages you tend to have a separation of the runtime from any "IDE feature" like debugging break points, tracing function calls, and compiling (not "eval"ing) new code. Other languages + IDEs are getting there but there's so much more to go.
In Java land, with the support of things like JRebel, we can make pretty significant modifications to a running program like add/change/remove methods to a class. But what about any existing objects I may have instantiated? Those are left around, referring to the old code. In Lisp, redefining classes works out of the box (no need to wait decades for JRebel to show up), and "update-instance-for-redefined-class" is a standard generic function, which you can write a version of to handle conversion of existing objects. No mysterious old versions of objects running around, you didn't have to bring down the program to restart it, nice. It's a very dynamic and inspectable system, going beyond just the types of things. That to me is still Lisp's advantage as other languages + language tools slowly add more and more of its features that are there already in Lisp independent of extra tools (and Lisp has extra tools too for more things).
I can't resist commenting a bit more on the type situation directly though... The creator of Clojure talks about "situated programs" in https://www.youtube.com/watch?v=2V1FtfBDsLU https://www.youtube.com/watch?v=2V1FtfBDsLU (he also has 20+ years of professional programming -- I on the other hand am only arguably on year 10 of "paid" exp (I wouldn't call all my gigs professional and not all were full time) but I tend to ignore how much experience someone has when people with equal or greater experience have such divergent views) and along the way I think he makes good points about how type systems get in the way of designing these big long-running systems that need to change as the years go by. Certainly I see this problem in the gigantic Java code base I deal with every day. Tight coupling is the nemesis of modularity, which you need for big systems, I tend to view static types as premature tight coupling. They're not without their benefits (typo protection less so for me but I love the easy speed wins, which you get in Common Lisp too if you bother to declare types; a form of QE via formal type proofs can be useful too), but they're also not without their downsides, and for many types of programs large or small the downsides can dominate.
[0] Examples: https://news.ycombinator.com/item?id=12222404 https://news.ycombinator.com/item?id=12222404 (told about state never being reached? awesome!) https://news.ycombinator.com/item?id=13389287 https://news.ycombinator.com/item?id=13389287 (notes about why it couldn't use a fast operator, so you need to fix your types) https://news.ycombinator.com/item?id=14780381 https://news.ycombinator.com/item?id=14780381 (other nice things like unused var, wrong number of arguments, typoed name...)
- flavio81 8y ago>is the mindset of writing programs, which other dynamic languages typically don't get right. The idea of "growing" a program, and responding to change, is part of that mindset and once it's internalized a lot of the language decisions make a lot more sense Excellent post.
- jungler 8y agoThere's a page on C2 Wiki that I'm reminded of: "alternating hard and soft layers" as a pattern. And I think this pattern tends to develop throughout large, long-lived systems. Shakeups like transitioning from native apps to the browser, or the replacement of the sysv init scripts with the much larger systemd, make some things "harder" and others "softer". So you want some dynamism throughout so that a layer change is possible, but you also want some static elements so that they do the existing work reliably. It's a cyclical process, and often terminates abruptly when some other piece of software comes up and replaces the existing one. I am finding, after spending some years locked into a static-minded viewpoint, a renewed appreciation for having dynamic types available. In the design phase, it assists in creating useful feedback about a system. Coming at it from a point of experience helps in avoiding abuse of reflection, metaprogramming etc. and keeping the basic structure and algorithm design simple and gradually discovering which techniques will move the system forward. What a static approach tends to do is "lock in" everything, like when a child grows up and their skeleton becomes rigid. If your desire is code with eternal youth, then it would make sense to avoid locking things in! But that might mean denying it some of the wisdom of old age.