在语言中不包含NULL的含义?

时间:2009-09-18 03:30:23

标签: programming-languages null language-design

我知道在编程语言中不需要NULL,我最近决定不在我的编程语言中包含NULL。声明是通过初始化完成的,因此不可能有一个未初始化的变量。我希望这会消除NullPointerException支持更有意义的例外,或者只是没有某些类型的错误。

当然,由于语言是用C语言实现的,所以在封面下会使用NULL。

我的问题是,除了使用NULL作为错误标志(这是用异常处理)或作为数据结构的端点,如链接列表和二叉树(这是由有区别的联合处理)还有其他任何用例对于我应该有解决方案的NULL?没有NULL可能会给我带来问题吗?

10 个答案:

答案 0 :(得分:8)

最近由Tony Hoare在LtU上引用了一篇名为Null References: The Billion Dollar Mistake的文章,该文章描述了一种允许编程语言中存在 NULL的方法,但消除了引用此类NULL引用的风险。看起来很简单,但这是一个如此强大的想法。

更新:这是我阅读的实际论文的链接,其中讨论了在Eiffel中的实现:http://docs.eiffel.com/book/papers/void-safety-how-eiffel-removes-null-pointer-dereferencing

答案 1 :(得分:3)

借用Haskell's Maybe monad中的页面,您将如何处理可能存在或不存在的返回值的情况?例如,如果您尝试分配内存但没有可用内存。或者你可能已经创建了一个数组来容纳50个foos,但是没有一个foos已经实例化了 - 你需要一些方法来检查这些东西。

我猜你可以使用异常来涵盖所有这些情况,但这是否意味着程序员必须在try-catch块中包装所有?这充其量只会令人讨厌。或者所有东西都必须返回它自己的值加上一个布尔值来表明该值是否有效,这肯定不是更好。

FWIW,我不知道任何没有某种概念NULL的程序 - 你在所有的C中都有null风格的语言和Java; Python有None,Scheme,Lisp,Smalltalk,Lua,Ruby都有nil; VB使用Nothing;和Haskell有一种不同的nothing

这并不意味着一个语言绝对必须有某种null,但如果所有其他大语言都使用它,肯定会有一些合理的推理背后。

另一方面,如果您只是制作轻量级DSL或其他非通用语言,那么如果您的本机数据类型都不需要它,则可能没有null。

答案 2 :(得分:1)

立刻想到的是传递引用参数。我主要是一个Objective-C编码器,所以我习惯于看到类似这样的东西:

NSError *error;
[anObject doSomething:anArgumentObject error:&error];
// Error-handling code follows...

执行此代码后,error对象会详细说明遇到的错误(如果有)。但是说我不关心是否发生错误:

[anObject doSomething:anArgumentObject error:nil];

因为我没有为错误对象传递任何实际值,所以我没有得到任何结果,我真的不担心解析错误(因为如果发生错误,我首先不关心)

你已经提到过你以不同的方式处理错误,所以这个具体的例子并不真正适用,但重点是:当你通过引用传回一些东西时你会怎么做?或者你的语言不这样做?

答案 3 :(得分:1)

我认为对于返回NULL的方法很有用 - 例如,对于应该返回某个对象的搜索方法,它可以返回找到的对象,如果找不到则返回NULL。

我开始学习Ruby和Ruby有一个非常有趣的NULL概念,也许你可以考虑实现一些silimar。在Ruby中,NULL被称为Nil,它就像任何其他对象一样是一个实际的对象。它碰巧被实现为全局Singleton对象。同样在Ruby中,有一个对象False,并且在布尔表达式中Nil和False都计算为false,而其他所有值都计算为true(例如,甚至为0,计算结果为true)。

答案 4 :(得分:0)

在我看来,有两种用例通常使用NULL:

  • 有问题的变量没有值(Nothing)
  • 我们不知道有问题的变量的值(未知)

两种常见事件,老实说,两者都使用NULL会导致混淆。

值得注意的是,一些不支持NULL的语言确实不支持Nothing / Unknown。例如,Haskell支持“Maybe”,它可以包含值或Nothing。因此,命令可以返回(并接受)他们知道将始终具有值的类型,或者他们可以返回/接受“可能”以指示可能没有值。

答案 5 :(得分:0)

我更喜欢将非可空指针作为默认值的概念,可以使用可空指针。您几乎可以通过引用(&)而不是指针来使用c ++来完成此操作,但在某些情况下它会变得非常粗糙和令人讨厌。

一种语言在Java / C意义上可以没有null,例如Haskell(和大多数其他函数语言)都有一个“Maybe”类型,它实际上是一个只提供可选空指针概念的构造。 p>

答案 6 :(得分:0)

我不清楚为什么你想要从语言中消除'null'的概念。如果您的应用程序要求您“懒洋洋地”进行一些初始化,那么您会怎么做 - 也就是说,在需要数据之前不执行操作?例如:

public class ImLazy {
 public ImLazy() {
  //I can't initialize resources in my constructor, because I'm lazy.
  //Maybe I don't have a network connection available yet, or maybe I'm
  //just not motivated enough.
 }

 private ResourceObject lazyObject;
 public ResourceObject getLazyObject() { //initialize then return
  if (lazyObject == null) {
   lazyObject = new DatabaseNetworkResourceThatTakesForeverToLoad();
  }
 }

 public ResourceObject isObjectLoaded() { //just return the object
  return (lazyObject != null);
 }
}

在这种情况下,我们如何为getObject()返回一个值?我们可以提出两件事之一:

- 要求用户在声明中初始化LazyObject。然后用户必须填写一些虚拟对象(UselessResourceObject),这需要他们编写所有相同的错误检查代码(if(lazyObject.equals(UselessResourceObject)...)或:

- 使用其他一些值,与null相同,但名称不同

对于任何复杂/ OO语言,您需要此功能,或者类似的东西,据我所见。拥有非null引用类型可能很有价值(例如,在方法签名中,因此您不必在方法代码中执行空检查),但是对于您的情况,null功能应该可用使用它。

答案 7 :(得分:0)

有趣的讨论发生在这里。

如果我正在构建一种语言,我真的不知道我是否会有null的概念。我想这取决于我希望语言看起来如何。一个很好的例子:我写了一个简单的模板语言,其主要优点是嵌套标记,并且易于使标记成为值列表。它没有null的概念,但它实际上没有除string之外的任何类型的概念。

相比之下,它内置的语言,Icon,广泛使用null。 Icon的语言设计者使用null做的最好的事情可能是使它与未初始化的变量同义(即,您无法区分不存在的变量和当前保持值null的变量之间的差异)。然后创建了两个前缀运算符来检查null和not-null。

在PHP中,我有时使用null作为“第三个”布尔值。这在“黑盒子”类型(例如ORM核心)中是好的,其中状态可以是真,假或我不知道。 Null用于第三个值。

当然,这两种语言都没有像C一样的指针,所以空指针不存在。

答案 8 :(得分:0)

我们在应用程序中始终使用null来表示“无”的情况。例如,如果要求您在给定id的数据库中查找某些数据,并且没有记录匹配该id:return null。这非常方便,因为我们可以在缓存中存储空值,这意味着如果有人在几秒钟内再次请求该ID,我们就不必返回数据库。

缓存本身有两种不同的响应:null,表示缓存中没有这样的条目,或者是一个条目对象。条目对象可能具有空值,这是我们缓存空数据库查找时的情况。

我们的应用程序是用Java编写的,但即使使用未经检查的异常执行此操作也会非常烦人。

答案 9 :(得分:0)

如果有人接受这样的命题:强大的语言应该有某种指针或引用类型(即可以保存对编译时不存在的数据的引用),以及某种形式的数组类型(或其他方式)具有可通过整数索引顺序寻址的存储槽集合,并且后者的槽应该能够保持前者,并且人们可能必须先读取指针/引用数组的一些槽。对于所有这些都存在合理的值,那么从编译器的角度来看,将会有一些程序在读出一个合理的值之前读取一个数组槽(试图在一般情况下确定是否可以读取一个数组槽)它被写成等同于停止问题。)

虽然一种语言可能要求在读取任何数组插槽之前使用某些非空引用来初始化所有数组插槽,但在许多情况下,实际上并没有任何可以存储的内容更好比null:如果尝试读取尚未写入的数组插槽并取消引用其中包含的(非)项,则表示错误,并且系统陷阱的条件比访问某些任意条件更好存在的唯一目的是为数组插槽提供一些它们可以引用的非空的东西。