This reminds me of my favorite special form in common-lisp: `the`. https://www.lispworks.com/documentation/HyperSpec/Body/s_the...
(the fixnum (compute-my-fixnum-value))
This specifies that the value in the form in the second argument is of the type specified by the first argument. One might assume that this is what other languages call `assert`, and it can be; your compiler / interpreter can be configured to assert if it detects a mismatch between the two.
... but the spec actually specifies that if they don't match, the behavior is undefined. `the` is also an opportunity for the compiler to throw away some dynamic typechecking logic; essentially, it's a chance to paint racing stripes on the implementation so it goes faster at the cost of risking undefined behavior.
Exactly. The primary purpose of type declarations in Common Lisp is to give the compiler a hint that you are taking responsibility for type management so the machine code doesn't need to check the type at runtime. But the spec does not require that the compiler obey that hint, and if the compiler does obey the hint the spec says it's not the compiler's fault if you screw up the type that you took responsibility for.
An additional purpose for type declarations is not mentioned in the spec: Static analysis. SBCL goes the extra mile and does do some static analysis with your type declarations, which means it catches many kinds of programmer errors at compile time. Not all CL implementations do this.
If you want a Common Lisp that performs thorough static analysis, use Coalton.
This is one of the things I appreciate about Common LISP's approach: it allows for undefined behavior, but UB is (mostly, as far as I know, I'm sure someone will jump in and correct me ;) ) off by default.
And I think that's the right place for the default to be. C and C++ support UB as well and there are definitely times where you want that for the speed benefits it affords the compiler's output, but getting to UB in those languages is as easy as creating a character array and then copying a string that is too long into that character array (gcc will warn you, but about the conversion of a string literal into a char pointer, not about the buffer overrun).
And with the C++ spec having a page count exceeding the entire Lord of the Rings trilogy, that's a lot of language definition for undefined behavior to live in.
> it allows for undefined behavior, but UB is (mostly, as far as I know, I'm sure someone will jump in and correct me ;) ) off by default.
It's actually much more sophisticated than that. See:
https://www.lispworks.com/documentation/HyperSpec/Body/01_db...
would you happen to know whether the spec requires a default value for the safety optimization quality, when no declartions are given in the program? Or is it implementation-defined; could conforming implementations be unsafe by default.
No idea, sorry.
[UPDATE] There is a clue in section 3.3.1 Minimal Declaration Processing Requirements:
"A safety declaration that increases the current safety level must always be recognized. An implementation that always processes code as if safety were high may safely ignore this declaration."
To me this seems to imply that the default value of SAFETY is implementation-dependent.
I also found that passage. It's either implementation-defined or else they went incredibly out of their way to hide the requirements.
Common Lisp has declared safety levels, so implementations can provide diagnostics about types at safety level 3, letting you roast in the flame of your undefined behavior only at lower safety levels.
I can't remember what the exact requirements are; I'd have to go back and re-read that.
Anyway, whether required by ANSI CL or not, implementations are good about protecting you from yourself unless you declare type AND request high speed and low safety.
Looking at the spec now, I don't see where it specifies that code is safe by default (safety 3) if no declarations are specified in the global or lexical environment. I see the requirement that implementations must not ignore safety deeclarations that raise the level of safety (unless they treat all code as safe and don't implement those declarations).