使用(声明(类型...))但仍具有"安全"功能



是否可以在函数中使用(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用于局部声明。

既然你在问:

是否有可能在函数中使用(declare (type ...))声明,但也对函数参数执行类型检查,以产生更快但仍然安全的代码?

在我看来,你似乎忽略了关于Common Lisp类型系统的重要一点,那就是该语言不是(也不可能是)静态类型的。让我们来澄清这一点。

程序设计语言大致可分为三大类:

  1. 带有静态类型检查:每个表达式或语句都是在编译时检查类型正确性,从而导致类型错误可以在程序开发过程中检测,代码多吗有效,因为在运行时不需要检查类型;
  2. 带动态类型检查:每个操作都在运行时检查用于类型正确性,以便在运行时不会发生类型错误;
  3. 不进行类型检查:类型错误可能在运行时发生,因此
  4. 程序可能会因错误或未定义的行为而停止。

关于前面的分类,Common Lisp规范把决定采用第二种还是第三种方法的责任留给了实现!不仅如此,通过optimize声明,规范还允许实现在同一个程序中自由地动态更改这一点。

因此,大多数实现,在初始优化和安全级别,实现第二种方法,丰富了以下两种可能性:

  1. 可以请求编译器在编译某些代码片段时省略运行时类型检查,通常是出于效率的原因,因此,在特定的代码片段中,取决于优化和安全设置,语言可以表现得像第三类语言:这可以通过类型声明的提示来支持,如(declare (type fixnum x))用于变量和(the fixnum (f x))用于值;

  2. 可以通过check-type在代码中插入显式的类型检查测试,以便在运行时执行,以便最终检查值的类型差异将导致"可纠正的错误"。

此外,请注意,不同的编译器在编译时检查类型的行为可能不同,但它们永远无法达到具有静态类型检查的语言的编译器的级别,因为Common Lisp是一种高度动态的语言。考虑下面这个简单的例子:
(defun plus1(x) (1+ x))
(defun read-and-apply-plus1()
    (plus1 (read)))

,由于(read)的类型在编译时不知道,因此不能对(plus1 (read))的调用进行静态类型检查。

最新更新