(defun foo (x) (compile ()
`(lambda (u)
(print "Executed")
(aref ,x u))))
(foo 0)
... reports a compilation error and of course does not print anything. If however I directly type the offending form (aref 0 0) a runtime type error is signaled.Nowadays that kind of efficiency isn't as big of a deal as it used to be and people tend to go more towards the angle of using the type system for error detection but I still can't shake that feeling that CL's type system feels a bit off when you compare it to other modern type systems.
(this is no excuse to not at least cite Common LISP though)
Getting errors is the same if at compile-time or in the test-suite or at the customer, though having them at compile-time is of course preferred. In LISP you have all 3 cases. In static languages only the first.
These guys here solve their type-checking performance problem by deferring the check to dynamic code. Checks are expensive if your type checking code is slow, or the source code is a dynamic mess. We are talking about ruby on rails here, which is the biggest dynamic mess one can think of. It's the similar problem the JIT guys have, deferring compilation to only actually invoked code and skipping dead branches.
See 'Types in Python' from the manual:
https://common-lisp.net/project/cmucl/doc/cmu-user/compiler....
A variant of that compiler is used in the now popular SBCL implementation: