是否可以在函数中使用(declare (type ...))
声明,但也可以对函数参数进行类型检查,以产生更快但仍然安全的代码?
(defun add (x y)
(declare (type fixnum x y))
(the fixnum x y))
作为(add 1 "a")
调用时将导致未定义的行为,因此最好将其修改为
(defun add (x y)
(declare (type fixnum x y))
(check-type x fixnum)
(check-type y fixnum)
(the fixnum x y))
,但我担心编译器被允许假设check-type
总是通过,从而省略检查。
所以我的问题是,上面的例子是错误的,因为我期望它,其次,是否有任何共同的成语*在使用优化代码实现类型安全?
*)我可以想象,例如,使用优化的lambda并在进行类型检查后调用它,但我想知道这是否是最优雅的方式。
您总是可以先检查类型,然后输入优化后的代码:
(defun foo (x)
(check-type x fixnum)
(locally
(declare (fixnum x)
(optimize (safety 0)))
x))
LOCALLY
用于局部声明。
既然你在问:
在我看来,你似乎忽略了关于Common Lisp类型系统的重要一点,那就是该语言不是(也不可能是)静态类型的。让我们来澄清这一点。是否有可能在函数中使用
(declare (type ...))
声明,但也对函数参数执行类型检查,以产生更快但仍然安全的代码?
程序设计语言大致可分为三大类:
- 带有静态类型检查:每个表达式或语句都是在编译时检查类型正确性,从而导致类型错误可以在程序开发过程中检测,代码多吗有效,因为在运行时不需要检查类型;
- 带动态类型检查:每个操作都在运行时检查用于类型正确性,以便在运行时不会发生类型错误;
- 不进行类型检查:类型错误可能在运行时发生,因此 程序可能会因错误或未定义的行为而停止。
关于前面的分类,Common Lisp规范把决定采用第二种还是第三种方法的责任留给了实现!不仅如此,通过optimize
声明,规范还允许实现在同一个程序中自由地动态更改这一点。
因此,大多数实现,在初始优化和安全级别,实现第二种方法,丰富了以下两种可能性:
可以请求编译器在编译某些代码片段时省略运行时类型检查,通常是出于效率的原因,因此,在特定的代码片段中,取决于优化和安全设置,语言可以表现得像第三类语言:这可以通过类型声明的提示来支持,如
(declare (type fixnum x))
用于变量和(the fixnum (f x))
用于值;可以通过
check-type
在代码中插入显式的类型检查测试,以便在运行时执行,以便最终检查值的类型差异将导致"可纠正的错误"。
(defun plus1(x) (1+ x))
(defun read-and-apply-plus1()
(plus1 (read)))
,由于(read)
的类型在编译时不知道,因此不能对(plus1 (read))
的调用进行静态类型检查。