为啥 `bool?` 上没有解除短路运算符?

Posted

技术标签:

【中文标题】为啥 `bool?` 上没有解除短路运算符?【英文标题】:Why are there no lifted short-circuiting operators on `bool?`?为什么 `bool?` 上没有解除短路运算符? 【发布时间】:2011-07-09 10:17:54 【问题描述】:

为什么bool? 不支持解除&&||?他们本可以解除 truefalse 运算符,这将间接添加解除 &&||

运算符|& 已被解除并实现正确的Three-valued logic。但当然它们不会像 ||&& 那样短路。

问题是为什么他们决定在创建规范时不取消这些运算符。所以“之所以这样,是因为规范是这样说的”并不能回答“为什么?”。

当提升truefalse 时,null 既不是true 也不是false

public static bool operator true(bool? x) 

    return x.HasValue && x.Value


public static bool operator false(bool? x) 

  return x.HasValue && !x.Value

这将导致&&|| 的行为就像它们的非短路对应物一样。除了false && anythingtrue || anything 会短路(falsetrue 在这两个示例中都不是编译时常量)。

这与DBBool example on MSDN 非常相似。

我认为解除这些运算符不会引起任何令人惊讶或危险的行为。我错过了什么吗?

我已经阅读了another SO question 这方面的内容,但没有一个令人满意的答案。


Jeff Yates 的回答很好地说明了为什么提升 true/false 运算符不是最佳的,它没有解释为什么直接提升 &&|| 是不好的。由于运算符提升是编译器的魔法,特殊情况 Nullable<T> 它不需要遵循普通类型的重载规则,因此能够在不提升 true 的情况下提供 &&/||

【问题讨论】:

这不是假设 NULL 意味着 false 吗?不是每个人都会同意这一点。在例如关系理论(和 SQL)NULL AND true , NULL and NULL, FALSE OR NULL 是 .. NULL,既不是真也不是假 我相信会有很多无意义的答案。只有 Eric Lipper 可以给出有意义的答案,希望他能抓住问题:) 也许我错过了你的观点,但是,如果 x 在上面的代码中为空,那么 true(x) == false(x);。这似乎没有任何意义。 @Jonathan Wood 对于既不是true 也不是false 的值,您期望哪个结果?它将为两者返回false @acid 我没有说 null 是 false&&true,但它可以假设这两个值。可能只是您的一个误导性表述。 【参考方案1】:

您的建议将为可空类型创建两种不同的使用模式。

考虑以下代码:

bool? a = null;

// This doesn't currently compile but would with lifted true/false operators.
if (a)



// Whereas this provides a consistent use of nullable types.
if (a ?? false)


为了保持可空类型使用的一致性,不解除bool 上的truefalse 运算符是有意义的。我不知道这是否是它没有完成的真正原因,但这对我来说很有意义。

【讨论】:

我不知道if 使用true 运算符。我认为它需要隐式转换为bool。但我刚刚测试过,你是对的。但这并不能解释为什么他们不会解除 && 和 ||直接不举truefalse @CodeInChaos:你怎么能这样? && 和 ||两边都需要布尔值(请参阅规范) - 不提升 truefalse,这是无法完成的。【参考方案2】:

由于您表明提升 truefalse 在技术上是可行的,因此您的问题只有两个可能的答案(“他们”是编写编译器/规范的人):

    这是规范中的错误,即。他们没有想到这一点。 (可能,但我对此表示怀疑) 他们认为解除短路运算符可能容易出错。这可能与为什么 C# 完全基于类(没有 C++ 中的唯一函数)或为什么像 if (myNullVar) ... (以 myNullVar 作为参考)这样的语句在 C# 中不起作用(但它确实如此)的推理方式相同在 C/C++ 中)。

我认为在让编程语言更强大和更不容易出错之间总是存在平衡。

更新:只是为了你的兴趣,official documentation 是这么说的:

这是不允许的,因为不清楚 null 在条件上下文中的含义。

【讨论】:

这个答案很好地说明了为什么提升op_true/op_false 考虑到条件的实现方式是一个坏主意(IMO 在条件中使用op_true 是愚蠢的,我需要隐式转换bool) 它没有说明为什么不应该直接解除短路的运算符。 @CodesInChaos:当 C# 做出(恕我直言)不幸的决定时,如果任一操作数为 null,结果应为 null 的公式隐式提升可空类型上的所有运算符,这意味着true | nullfalse & null 不能分别评估为 truefalse,就像三值逻辑的情况一样,而是必须评估为 null 以与其他提升运算符保持一致。 &&|| 的正常含义是,如果给定相同的操作数,它们应该返回与 &| 相同的值,但只计算正确的操作数... ...当它的值可能影响结果时。虽然通过在左侧操作数为非空时评估右侧,可以使&&||&| 保持一致,但它将是如果在给定bool b=false; bool? bq = false; 的情况下,即使b & f() 不会,表达式bq && f() 也会计算右侧,这将是相当令人惊讶的。 @supercat 但是 C# 规范有一个关于 bool? operator |(bool? x, bool? y)bool? operator &(bool? x, bool? y) 形式的运算符的特定部分,它显然对 bool? 做了一个例外,规则是如果任何操作数不HasValue,结果也是null。所以true | null true。你自己看。但是,对于||&& 以及可空对象,规范还不清楚。我最近 asked a question 关于那个。【参考方案3】:

false && anythingfalse 相同。但是,如果您希望 false && anything 仅在 anything 为假时为真,那么 !anything 就是您想要的。

另外,true || anythingtrue 相同。 ...而且我不确定如何让它在任何情况下都返回 false,因为让“这个或那个”什么都不返回是没有意义的!

...既然一切都清晰而简单,为什么还要增加额外的权重?

我通常不擅长“因为这是这样”,但我看不到添加此类功能的优势。

【讨论】:

我并不是说 false 在该示例中是编译时常量。但是一个已经评估为假的表达式,因此不需要对右侧的评估。 假 && 任何东西都是假的。没有? 哦!所以,你在谈论cond1 && cond2,而你希望cond2 被评估,即使cond1 是假的?

以上是关于为啥 `bool?` 上没有解除短路运算符?的主要内容,如果未能解决你的问题,请参考以下文章

HPCC-ECL 逻辑运算符 - 为啥 OR 不短路?

当运算符优先级说不应该时,为啥短路评估会起作用?

为啥析取赋值运算符 |= 不适用于布尔向量?

为啥 C/C++ 中没有 ^^ 运算符?

用于比较值类型的短路运算符的.Net性能?

为啥下面的表达式返回 true?