Language agnostic 如果没有空,我们该怎么办?

Language agnostic 如果没有空,我们该怎么办?,language-agnostic,null,language-design,non-nullable,Language Agnostic,Null,Language Design,Non Nullable,我曾经读到过,拥有可为空的类型绝对是一种罪恶。我相信这是在一篇文章中写的,作者正是《美国法典》中的作者 无论如何,如果像C#这样的语言在默认情况下使用了不可为空的类型呢?如果null是一个可接受的值,您将如何替换C#或Ruby或任何其他公共语言中的一些常见习惯用法 我们会使用(非常)几个允许空值的地方,而且我们会有很多模糊的bug,因为任何对象引用都会保证指向适当类型的有效实例。我想你指的是这个谈话:“我们使用 鉴别器。表示值为“null”且必须忽略的额外属性、标志或指示符 域特定的空值。一个特

我曾经读到过,拥有可为空的类型绝对是一种罪恶。我相信这是在一篇文章中写的,作者正是《美国法典》中的作者


无论如何,如果像C#这样的语言在默认情况下使用了不可为空的类型呢?如果
null
是一个可接受的值,您将如何替换C#或Ruby或任何其他公共语言中的一些常见习惯用法

我们会使用(非常)几个允许空值的地方,而且我们会有很多模糊的bug,因为任何对象引用都会保证指向适当类型的有效实例。

我想你指的是这个谈话:“

我们使用

  • 鉴别器。表示值为“null”且必须忽略的额外属性、标志或指示符

  • 域特定的空值。一个特定的值——在允许的域内——被解释为“忽略此值”。例如,社会保险号码999-99-9999可能是特定于域的空值,表示SSN未知或不适用


  • 我不想直截了当地宣称可空类型是邪恶的,而是假设:大多数语言将可空性移植到所有类型上,而这两个概念实际上应该是正交的

    例如,所有非原语Java类型(以及所有C#引用类型)都可以为空。为什么?我们可以反反复复,但最终我敢打赌答案归结为“这很容易”。Java语言本身没有任何东西需要广泛的可空性。C++引用提供了一个很好的例子,说明如何在编译器级别去掉空值。当然,C++有很多丑陋的语法,java显然是在试图缩减,所以一些好的特性在坏的地方就出现了。 C#2.0中的可空值类型提供了一个正确的方向——将可空性与不相关的类型语义分离,或者更糟糕的是,与CLR实现细节分离——但它仍然缺少一种与引用类型相反的方法。(代码契约非常棒&所有这些,但它们并不像我们在这里讨论的那样嵌入到类型系统中。)

    很多函数式语言或其他晦涩难懂的语言从一开始就“直截了当”地理解了这些概念……但如果它们被广泛使用,我们就不会有这样的讨论

    回答你的问题:全面禁止现代语言中的null与所谓的“十亿美元错误”一样愚蠢。有一些有效的编程结构,其中null很好:可选参数,任何类型的默认/回退计算,其中coalesce操作符导致简洁的代码,与关系数据库等进行交互。强迫自己使用sentinel值、NaN等将是比疾病更糟糕的“治疗”

    也就是说,我暂时同意引用中表达的观点,只要我可以根据自己的经验详细阐述:

  • 需要空值的情况比大多数人想象的要少
  • 一旦你将空值引入到一个库或代码路径中,去除它们要比添加它们困难得多。(所以不要让初级程序员一时兴起就这么做!)
  • 可为空的bug会随生命周期的变化而扩展
  • 与#3相关:提前崩溃

  • 您可以采用一个简单的规则:所有变量都被初始化(默认情况下,可以重写)为一个不可变的值,该值由变量的类定义。对于标量,这通常是某种形式的零。对于引用,每个类将定义其“null”值是什么,引用将使用指向该值的指针初始化

    这将有效地实现NullObject模式的全语言实现:
    因此,它并没有真正消除空对象,它只是防止它们成为必须这样处理的特殊情况

    Tcl是一种不仅没有空概念,而且空概念本身与语言核心不一致的语言。在tcl中,我们说:“一切都是字符串”。它真正的意思是tcl有一个严格的值语义(恰好默认为字符串)

    那么tcl程序员用什么来表示“无数据”?主要是空字符串。在某些情况下,如果空字符串可以表示数据,则其通常为:

  • 无论如何都要使用空字符串-大多数情况下,它对最终用户没有影响

  • 使用您知道数据流中不存在的值-例如字符串
    “\u NULL”
    或数字
    999999
    或我最喜欢的NUL字节
    “\0”

  • 使用围绕值的数据结构-最简单的是列表(其他语言称之为数组)。一个元素的列表表示该值存在,零元素表示null

  • 测试变量是否存在-
    [info exists variable\u name]

  • 有趣的是,Tcl并不是唯一一种具有严格值语义的语言。C也有严格的值语义,但值的默认语义恰好是整数而不是字符串

    哦,差点忘了另一个:


    有些库使用数字2的变体,允许用户指定“无数据”的占位符是什么。基本上,它允许您指定一个默认值(如果不指定,默认值通常默认为空字符串)。

    我们会创建各种奇怪的结构来传达对象“无效”或“不存在”的信息,如其他答案所示。
    null
    可以很好地传达信息

    • 正如我所说,这种方法也有它的缺点
    • 域特定的空值。这迫使您检查幻数
    • 集合包装器,其中空集合表示“无值”。包装器会更好,但这与检查
      n没有多大区别
      
      void fun(foo *f)
      {
          f->x;                  // error: possibly null
          if (f)              
          {
              f->x;              // ok
              foo &r = *f;       // ok, convert to non-nullable type
              if (...) f = bar;  // possibly null again
              f->x;              // error
              r.x;               // ok
          }
      }