Hacker News new | ask | show | jobs
by astrange 3118 days ago
"Do the right thing" is a brave statement for a language with no typechecking!
3 comments

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.

"Do the right thing", in this context, goes beyond just the presence or absence of typechecking.

But regarding type checking, Lisp (at least Common Lisp) is strongly typed. Really, very strongly typed (for example it will complain about putting a "byte" in a "character" array; or of using an "array" when a "simple-vector" was expected... Lisp is very nitpicky regarding types!), but the type checks happens mostly at runtime. Some checking also happens at compile time, even more if you intentionally include type declarations. (Type declarations are part of the ANSI Common Lisp standard.)

> Some checking also happens at compile time, even more if you intentionally include type declarations. (Type declarations are part of the ANSI Common Lisp standard.)

Just a note that this is entirely implementation-dependent. SBCL, for instance, is very good about using type declarations as correctness checks (those that can't be statically verified transparently degrade to runtime assertions) but their exact behaviour isn't specified in the standard; for example, implementations are free to take them as declarations that the programmer knows things the implementation doesn't and to trust them, which could cause weird bugs if they're not correct.

Emacs, one of the most reliable software ever was written in a language with no typechecking -- in Lisp! Emacs never crashes although it is configurable by the user in almost any way -- also in Lisp.