处理“不可能”代码路径的优雅方式

时间:2010-09-30 19:31:16

标签: language-agnostic coding-style

偶尔我会遇到一些情况,我写了一些代码,根据其逻辑,某条路径是不可能的。例如:

activeGames = [10, 20, 30]
limit = 4

def getBestActiveGameStat():
    if not activeGames: return None
    return max(activeGames)

def bah():
    if limit == 0: return "Limit is 0"

    if len(activeGames) >= limit:
        somestat = getBestActiveGameStat()
        if somestat is None:
            print "The universe has exploded"
        #etc...

宇宙爆炸线会发生什么?如果limit为0,则函数返回。如果len(activeGames) >= limit,则必须至少有一个有效游戏,因此getBestActiveGameStat()无法返回无。那么,我应该检查一下吗?

同样的事情也发生在类似while循环的东西中,它总是在循环中返回:

def hmph():
    while condition:
        if foo: return "yep"
        doStuffToMakeFooTrue()

    raise SingularityFlippedMyBitsError()

既然我“知道”这是不可能的,那么甚至还有什么吗?

2 个答案:

答案 0 :(得分:4)

  

如果len(activeGames)> = limit,那么   必须至少有一个活跃的   游戏,所以getBestActiveGameStat()不能   返回无。所以,我应该检查一下   对吗?

有时候我们会犯错误。您现在可能会遇到程序错误 - 或者有人可能稍后创建程序错误。

这些错误可能导致异常或单元测试失败。但调试很昂贵;有多种方法来检测错误很有用。

快速编写的断言声明可以表达对人类读者的预期不变量。在调试时,失败的断言可以快速查明错误。

Sutter和Alexandrescu在“C ++编码标准”中解决了这个问题。尽管有标题,但他们的论点和指导方针与语言无关。

  

自由地断言以记录内部假设和不变量   ...使用断言或等同的文件来记录模块内部的假设 ......必须始终为true,否则表示编程错误。

例如,如果default语句中的switch大小写无法发生,请使用assert(false)添加大小写。

答案 1 :(得分:2)

恕我直言,第一个例子实际上是一个关于如何向用户呈现灾难性故障的问题。如果有人做了非常愚蠢的事情并将activeGames设置为none,大多数语言都将抛出NullPointer / InvalidReference类型的异常。如果你有一个很好的系统来捕捉这些错误并优雅地处理它们,那么我会争辩你完全抛弃这些警卫。

如果你有一套不错的单元测试,他们将确保这种问题不会逃避开发者机器。

至于第二个,你真正要防范的是竞争条件。如果“doStuffToMakeFooTrue()”方法永远不会使foo成立,该怎么办?这段代码最终会自行运行。而不是冒险,我通常会把这样的代码放在计时器上。如果你的语言有闭包或函数指针(老实说不确定Python ......),你可以在一个好的帮助方法中隐藏定时逻辑的实现,并以这种方式调用它:

withTiming(hmph, 30) // run for 30 seconds, then fail

如果你没有闭包或函数指针,你将不得不在任何地方做到这一点:

stopwatch = new Stopwatch(30)
stopwatch.start()
while stopwatch.elapsedTimeInSeconds() < 30
    hmph()
raise OperationTimedOutError()