Hacker News new | ask | show | jobs
by TeMPOraL 3120 days ago
Plenty of typechecking primitives are available, and CL itself is strongly - but dynamically - typed. Now, the Lisp way strongly favours interactivity with programming, so by default, those typecheck helpers are not too convenient, to use, and a lot happens at runtime. But:

- CL standard defines a pretty decent type hierarchy (not Haskell-level decent, though).

- While not required by the standard, good CL implementations make use of typing for optimization and safety checks at compile-time. SBCL is particularly great in that domain, employing a solid type inference engine.

- CL allows you to override optimization/safety levels at very small granularity - even sub-function level - with (declare (optimize ...)) forms - like, you can e.g. drop (declare (optimize (speed 3) (safety 0))) inside a loop inside a function, to optimize just this particular section of code.

- Even though CL type-related primitives aren't very convenient (they generate a bit of line noise in the code), the macro system gives you all the power you need to hide it under whatever syntactic sugar you like. There's nothing stopping you from writing (or finding a library defining) e.g. a macro:

  (defun* foo ((real x) ((fixnum 0 100) y) z) -> rational
    ... some code ...)
that will get expanded into:

  (declaim (ftype (function (real (fixnum 0 100) t) rational) foo)
  (defun foo (x y z)
    (check-type x real)
    (check-type y (fixnum 0 100))
    (the rational (progn ... some code ...)))
which will give you both runtime checks and, with compilers at SBCL, plenty of compile-time type checks too.

--

I see "do the right thing" in the context of that epigram as meaning that you can choose to do the right thing without having to make compromises for syntax and semantics, as Lisp will happily let you remove any and all boilerplate with its macro system.