解析,不进行类型检查

2020-11-26 23:13:36

去年有一篇很棒的文章,标题为Parse,请不要验证。我强烈推荐给任何程序员(以及最近的后续更新,名称不是类型安全的)。基本思想是有两种方法可以检查对函数的某些输入是否有效:

验证器检查输入是否有效,如果无效,则引发错误。它不会返回任何东西。例如,检查列表是否为空。

解析器的作用与验证器相同,但是返回输入的更特定的表示形式,以确保满足所需的属性。例如,检查列表不为空,然后返回NonEmptyList类型。

本文的论点是解析器比验证器更可取。如果您还没有阅读原始文章,请这样做-它写得很好,并且比我可以总结的要好得多。基本信息是使非法国家无法代表。在本文中,这是通过使用类型系统来完成的。这是我完全同意的一种哲学,但我想指出并扩展论证的一个讽刺意味:

毕竟,类型检查器将已经解析的程序表示形式作为输入,如果无法进行类型检查,则将其拒绝。它不会返回该程序的更具体的表示。 (不要与类型推断混淆,后者确实会返回更多信息,而只是返回有关类型的信息)。

那么用编程语言代替类型检查器的解析器将是什么呢?一种方法是实际上创建一种消除非法状态的更具体的语法。例如,如果给定的函数需要一个必须在1到5之间的数字,则不要对函数调用使用通用语法,例如:

one_to_five :: = 1 | 2 | 3 | 4 | 5 fun_call :: =‘lil_fac(‘one_to_five’)’| ...其他功能定义...

创建此类特定的语法是一种制作域特定语言(DSL)的方法。确实,DSL是确保非法状态不可代表的好方法。当然,如果您想使用用户定义的函数来创建通用语言,则这不是可扩展的解决方案。

拥有非常具体的语法的另一种方法是提高抽象级别,从而更容易避免无效状态。例如,编程错误的一个常见来源是超出范围地索引到数组。发生这种情况是因为编程语言仅提供原始索引操作:a [x]。这里的“ x”是一个整数,但可能超出范围,从而导致异常或崩溃(如果幸运的话)。我们可以防止这种情况的一种方法是定义一个更具体的“ 0到12之间的整数”类型,以便类型系统拒绝任何可能无效的索引操作,然后为每个数组跟踪此更精确的类型-再次进行验证。

另一种方法是注意到,通常有几种常见的方法要使用数组,并以捕获这些用法的语言提供特定的抽象。例如,很常见的是要遍历数组以执行某种计算。而不是让每个人都手动为此写出for循环-这种语言的数组是从0还是1开始的?它们停在array.length还是array.length – 1?数组索引是否具有特定类型? -您可以改为提供常规折叠(减少)操作。同样,与其让人们编写自己的哈希表,不如提供一种内置于该语言本身的表。通过提供更好的抽象,您可以减少程序员遇到非法状态的可能性。

然后,您可以继续操作并删除更原始的操作,仅允许访问更高级别的抽象。希望在2020年,大多数程序员会同意,删除goto语句以支持更高层次的结构化编程抽象是一个胜利,其他低层构造(空值,原始内存指针等)也是如此。

在计算机安全领域,这种讨论是直接类似的。大多数计算机系统的安全模型都将我可以(尝试执行)的操作与我可以执行的操作分开:我可以尝试删除您的网站,但是(希望如此)该请求将被拒绝为未授权。相反,在对象能力系统中,我什至可以调用此类操作的能力取决于我是否拥有不可伪造的能力,以授予我执行该能力的权限。甚至无法尝试不允许执行的操作。例如,在使用功能URI的REST API中,我不能简单地将DELETE请求发送到/ users / alice,而是需要将其发送到一些无法猜测的随机URI –如果我还没有该URI,那么我就不能甚至开始发送请求。因此,对象能力安全性旨在使未经授权的状态无法表示。

也许对象能力范例的最广为人知的实施例是E编程语言:一种动态类型的面向对象的编程语言。尽管现在已被抛弃,但它是一种引人入胜的语言,其中包含许多很棒的想法。 E使用强大的抽象边界来确保安全性。警告:E网站是一个深度惊人的兔子洞!

在20年代,我曾经在Tcl中做过很多编程工作。大多数人都同意的一种语言与现代静态类型编程语言之间的距离要尽可能远。 (经常指出一些令人非常厌恶的东西)。然而,使非法状态无法代表的想法对我本人和其他Tcl程序员来说是完全自然的。我经常会通过创建一个空白面板的解释器,剥离所有内置的语言构造(循环,过程,甚至算术),然后重新添加经过精心选择的一组高级领域特定原语来开始一个编程项目。 。然后,该DSL将成为应用程序的配置文件,因为它知道无法表达非法配置,因此非常安全。

总而言之,我的意思不是说类型系统很糟糕或者原始论文有缺陷。相反,我几乎每天都要感谢飞翔的意大利面条怪物在我的日常工作中使用类型系统(那只是Java的温和调剂),而且我认为“解析,不验证”的论文非常出色。但是在过去的二十年中,类型系统取得了如此大的进步,并且采用了有类型的编程模式,我们冒着以为类型系统是实现软件构造正确性的唯一途径的危险。它们是一种非常强大的工具,但是抽象和信息隐藏的更多基本技术也同样强大。使非法状态无法代表的目标应该是软件工程的定义目标之一,但是有很多有效的方法可以解决这个问题。

无耻的插件:我刚刚在Manning出版的关于API安全的书的第9章中深入讨论了功能URI。我还将在第6章中讨论使用类型强制实施安全性属性。

2020-11-21 18:11
2020-11-11 1:46