There are several misconceptions about how people use Common Lisp.

> Users can portably and safely use assertions if they want that behavior

The point is that SBCL can check both at compile-time and at runtime. Which the others (exception: CMUCL and Scieneer CL) can't.

* (defun foo (a) (declare (string a)) (+ a 10))
; in: DEFUN FOO
; (+ A 10)
;
; caught WARNING:
; Derived type of A is
; (VALUES STRING &OPTIONAL),
; conflicting with its asserted type
; NUMBER.
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; compilation unit finished
; caught 1 WARNING condition

FOO

That means SBCL tells me already at compile-time that there is a problem in my code. That's something which a development environment can exploit. I get a list of compiler warnings and can then fix my code - without the need to run it and to go into a break - and without the need to have a test case.

Now if I fix that error and run that code in my other implementation - that problem is also fixed there.

Now you assume that adding an assertion would have had a benefit for the other implementation, since it would then create a runtime assertion violation if not a string is provided.

The thing is: this is usually not done. Nobody writes code with assertions everywhere in Common Lisp.

What Lisp a developer really does: if we need to provide a runtime check, then we write a CLOS method.

Thus by default we encourage developers to use CLOS:

CL-USER 23 > (defmethod foo ((s string))
(concatenate 'string s "bar"))
#<STANDARD-METHOD FOO NIL (STRING) 4020259F8B>

CL-USER 24 > (foo 3)

Error: No applicable methods for #<STANDARD-GENERIC-FUNCTION FOO 406000173C> with args (3)
1 (continue) Call #<STANDARD-GENERIC-FUNCTION FOO 406000173C> again
2 (abort) Return to top loop level 0.

Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.

> Some compilers may add less runtime checks and will create specialized code -> less safe.

There is another misconception. Nobody forces me to use those compilers or use them in an unsafe mode.

The choice of compilers in Common Lisp is to give the user different tools for different situations. It does not force me to run my code containing type declarations in an unsafe mode - which usually is controlled by compiler switches: OPTIMIZE qualities for SAFETY, DEBUG and SPEED.

If I set safety to 3, most compilers will not create unsafe code - even though there are type declarations.

If we have a type violation in a CLOS method, SBCL even catches that:

* (defmethod baz ((s string)) (+ s 10))
; in: DEFMETHOD BAZ (STRING)
; (+ S 10)
;
; caught WARNING:
; Derived type of S is
; (VALUES STRING &OPTIONAL),
; conflicting with its asserted type
; NUMBER.
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; compilation unit finished
; caught 1 WARNING condition
WARNING: Implicitly creating new generic function COMMON-LISP-USER::BAZ.

#<STANDARD-METHOD COMMON-LISP-USER::BAZ (STRING) {5132DEA1}>

The developer then will fix that code. When it then runs on another Lisp -> benefit.

So my advice usually is: even if one develops for another Lisp implementation, additionally use SBCL to check your code.