【问题标题】:Why is dereferencing not designed to be safe?为什么取消引用不是为了安全而设计的?
【发布时间】:2017-04-19 06:27:51
【问题描述】:

今天我(再次)取消引用了一个未定义对象的属性,导致我们的服务器发生了惊人的崩溃。解决问题包括编写我最不喜欢的样板代码之一,转

if (foo.bar.baz.id) {...

进入

if (foo && foo.bar && foo.bar.baz && foo.bar.baz.id) {...

因为 baz 在极端情况下恰好是 null,这引发了异常。

所以我的问题是:为什么取消引用 null/undefined 这样的问题?当foo/bar/baz 未定义时,为什么foo.bar.baz.something 不能安全地返回undefined?我了解技术为什么,并且对语言设计感兴趣,为什么?有没有安全取消引用的语言?为什么没有真正的 CS 原因,还是只是传统(继承形式 C,它是老朋友)?

我能想到一个原因,那就是在与取消引用一样经常执行的操作中包含更多“类型检查”风格的逻辑会大大降低语言的速度。但是我也认为大多数问题都可以通过在赋值/if/etc.运算符中进行适当的异常处理来解决,因此取消引用可以继续按原样和“更高级别”运算符照顾偶尔的“oopises”。

我能想到的另一个原因是,对于如何处理这个问题,实施某种规则集只是自以为是的语言设计决定太多了。

我非常感谢任何 CS 人员对这个问题有所了解。

【问题讨论】:

  • 首先想到的是性能问题:如果访问成员字段隐式验证所有包含的对象都是有效的,那么与非 OO 编程相比,OOP 本质上会很慢(如果一个字段的值是从其他两个字段计算出来的,那么整个对象的有效性将被检查至少 3 次)。虽然这可以优化(例如,每次操作只检查一次对象的有效性,除非使用语言的 volatile 或等效语言),但并非所有编译器都同样擅长优化。
  • “有没有可以安全解除引用的语言?” - 是的,Objective-C

标签: computer-science


【解决方案1】:

你所描述的不是deferencing的健全性/安全性,它是我所说的null monadic behavior,意思是如果一个操作T取空值n为输入,它的结果是n,没有进行任何计算。

您可能更熟悉 C# 中的术语 null propagationObjective-C equivalent
甚至SQL NULL 在操作方面也表现得单调。

出于性能原因,像 C 这样的语言没有空传播,在任何尊重之前添加一个分支会大大减慢速度。
其他语言的定义不同,因为它们具有不同的目的(例如 SQL 处理数据并且需要标记为 NULL)或不同的历史记录(Objective-C 来自 SmallTalk,其中对象不被尊重而是被发出信号,因此向无对象发送消息是有效的并且什么都不做)。


但空值传播并没有减轻空值检查的负担,甚至更糟。
有时很方便,但大多数情况下它违反了“快速失败”的规则。

是否承认null was a big mistake in CS.
解决方案是使用 Haskell 中的 monads 或 Java 中的 Optional 或 C# 中的 nullable types 或 C++ 中的 boost::optional
Null 不是值,也没有类型,而上面的所有解决方案都是值并且有类型。
结合模式匹配或其近似,它们使用起来非常流畅,非常适合自我记录代码。
它们也可以安全使用(在语言的类型系统允许的情况下)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-04
    • 2021-12-25
    • 2016-08-09
    • 1970-01-01
    • 2015-10-22
    • 2012-12-04
    • 2011-02-24
    • 2023-04-03
    相关资源
    最近更新 更多