I think Common Lisp got it exactly right. Strongly typed dynamic language where you can optionally specify types for the extra performance/correctness if need be (especially with SBCL).
Honestly, I think weak typing is more of an issue than dynamic typing and people cry for static types when they suffer mostly from the former.
Dynamic typing is great because it allows you to have extremely complex types for basically free. It allows for insane expressiveness. It also makes prototyping much easier and does not force you into over-specifying in you types early on. In dynamic language most of your types are the most general type that would work by default while static types forces you to use very specific types (especially when lacking structural typing.)
If you want to allow just half the expressiveness of dynamic languages in your static language you will quickly find huge complexity with dependent types, long compile time, cryptic error messages and whatnot.
Generally, I think gradual typing is rising in popularity for good reason. It allows for quick prototyping but also to drill down on your types when you want to. Best of both worlds.
I find much the same to be true. I'm a big fan of Racket's define/contract and clojure's Malli/guardrails. You get one of the biggest benefits of static types (code that self-documents the expected shape of data) while enjoying all the benefits of a dynamic language (like creating types at runtime, and repl-driven development).
I wish Common Lisp had integrated type declarations with TYPEP and CHECK-TYPE, instead of punting with "consequences are undefined if the value of the declared variable is not of the declared type," i.e., sucks to be you.
No doubt you know this, but Common Lisp's standardization gave leeway to implementations. So you could choose which implementation suits you better. Common Lisp is an umbrella for different Lisps to have some commonality. It was a process of negotiation, during a time when there were many design forks in the road, and diverse use-cases
For example, type declarations can enable performance optimizations, compiletime type checking, runtime type checking, IDE autocompletion, etc. Or they can be ignored, if compiler simplicity is more valued. All these things have engineering tradeoffs. For example, runtime checks may have runtime costs at odds with performance optimization
There might be higher-value improvements to Common Lisp, if higher quality code is desired
As someone who doesn't know much about types, do SBCL type declarations provide as good type-based development experience as OCaml and Rust?
And perhaps I wouldn't get your answer, I mean is there something fundamentally inadequate in the way SBCL declares types? I think there is a phrase for it in CS theory.
> As someone who doesn't know much about types, do SBCL type declarations provide as good type-based development experience as OCaml and Rust?
First of all, op was talking about strongly typed languages. Asking are they good as statically typed ones like Rust and OCaml is raising the goal posts quite a bit.
Second of all, SBCL can indeed have a subsection of its code expressed in OCaml-like static types, see
To add to the other comment, it is also important to understand in the more interactive mode of developing in CL. You basically have the program always running, fixing bugs and adding features while it is running.
You simply don't have the problem of batch style programming where you have written a bunch of code and now you want to know if it works so you run a lot of static analysis on it beforehand because running it and getting it to the point and state that is relevant costs time.
In CL you don't end up with lots of code that has never been run. You have constantly run it during development and are much more confident about its behavior. So just having this interactive way of programming already leads to much more reliable software. It is not a replacement for static analysis or unit testing of course but another pillar to help you write more correct software.
Honestly, I think weak typing is more of an issue than dynamic typing and people cry for static types when they suffer mostly from the former.
Dynamic typing is great because it allows you to have extremely complex types for basically free. It allows for insane expressiveness. It also makes prototyping much easier and does not force you into over-specifying in you types early on. In dynamic language most of your types are the most general type that would work by default while static types forces you to use very specific types (especially when lacking structural typing.)
If you want to allow just half the expressiveness of dynamic languages in your static language you will quickly find huge complexity with dependent types, long compile time, cryptic error messages and whatnot.
Generally, I think gradual typing is rising in popularity for good reason. It allows for quick prototyping but also to drill down on your types when you want to. Best of both worlds.