使用(declare(type ...))但仍然具有'安全'功能

时间:2015-08-31 22:48:18

标签: common-lisp compiler-optimization

是否可以在函数中使用(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并在进行类型检查后调用它,但我想知道这是否是最优雅的方式。

2 个答案:

答案 0 :(得分:8)

您可以随时检查类型,然后输入优化代码:

(defun foo (x)
  (check-type x fixnum)
  (locally
    (declare (fixnum x)
             (optimize (safety 0)))
    x))

LOCALLY用于本地声明。

答案 1 :(得分:0)

因为你问:

  

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

在我看来,你遗漏了关于Common Lisp类型系统的一个重要观点,那就是语言不是(并且不能)静态输入。让我们澄清一下这个方面。

编程语言大致可分为三大类:

  1. 使用静态类型检查:每个表达式或语句都是 在编译时检查类型正确性,以便输入类型错误 可以在程序开发过程中检测到,代码更多 因为不必在运行时检查类型,所以效率很高;
  2. 使用动态类型检查:在运行时检查每个操作 对于类型正确性,以便在运行时不会发生类型错误;
  3. 没有类型检查:类型错误可以在运行时发生,以便 程序可以因错误而停止或具有未定义的行为。
  4. <强>被修改

    关于以前的分类,Common Lisp规范给实现留下了决定他们是否想要遵循第二种或第三种方法的负担!不仅如此,而且通过optimize声明,规范允许实现在同一程序中自由地改变它。

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

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

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

    3. 此外,请注意,不同的编译器在编译时检查类型的行为可能不同,但是它们永远不会达到静态类型检查语言的编译器级别,因为Common Lisp是一种高度动态的语言。考虑一下这个简单的例子:

      (defun plus1(x) (1+ x))
      
      (defun read-and-apply-plus1()
          (plus1 (read)))
      

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