2010-09-30 86 views
3

偶尔我会遇到一些情况,我写了一些代码,并根据其逻辑,确定了一条路径是不可能的。例如:处理“不可能”代码路径的优雅方式

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()不能返回无。那么,我应该检查它吗?

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

    raise SingularityFlippedMyBitsError() 

既然“知道”这是不可能的,如果有什么甚至有:

同样也有类似while循环总是返回循环会发生什么?

+0

+1'SingularityFlippedMyBitsError'。还有一条评论,我经常看到一些程序,比如说“错误:用户不应该看到这个对话框”。确保你的不可能的情况是不可能的! – Seth 2010-09-30 23:09:00

回答

4

If len(activeGames) >= limit, then there must be at least one active game, so getBestActiveGameStat() can't return None. So, should I even check for it?

有时我们会犯错误。现在你可能会有一个程序错误 - 或者有人以后可能会创建一个。

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

一个快速写出的断言陈述可以表达一个预期的不变的人类读者。并且在调试时,失败的断言可以快速找出错误。

Sutter和Alexandrescu在“C++编码标准”中解决了这个问题。尽管标题,他们的论点和指导是语言不可知的。

Assert liberally to document internal assumptions and invariants ... Use assert or an equivalent liberally to document assumptions internal to a module ... that must always be true and otherwise represent programming errors.

例如,如果不能发生default情况下在switch声明中,添加具有断言(假)的情况。

+0

我同意断言可以是确保其他开发人员知道你不会忘记某事的好方法。对于类似交换机默认值的情况,这也可能是产生错误的有用方法,而不是默默无闻(可能导致灾难性后果)。尽管如此,我确实认为这有一个平衡点。对于像空引用这种非常常见的情况,无论如何都会抛出一个错误,它应该是非常明显的事情,甚至一个简单的断言最终可能会让干净的代码变得不那么干净。 – 2010-10-01 06:23:39

+0

在我看来,最重要的事情就是要确保对最终用户礼貌地处理任何错误(断言或其他)。 :) – 2010-10-01 06:26:05

+0

@Chris Jaynes - 断言有时可以更接近问题的根源。如果选择是在表达一个不变量或不表达它之间,因为我们没有时间来编写一个礼貌的处理我们希望永远不会发生的情况,那么选择应该总是表达不变量。 – 2010-10-01 14:02:44

2

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

如果你有一套体面的单元测试,他们将确保大量的确定性,这种问题不会逃离开发者机器。

至于第二个,你真正防范的是一个竞争条件。如果“doStuffToMakeFooTrue()”方法从未使foo为真,该怎么办?这段代码最终会自行落实。我通常会把这样的代码放在一个计时器上,而不是冒这个风险。如果你的语言具有闭合或函数指针(真的不知道有关Python ...),你可以隐藏时序逻辑的一个很好的helper方法的执行,并调用它是这样的:

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

如果你不“T有倒闭或函数指针,你将不得不处处做的很长的路要走:

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

啊雅python有这两个=)。虽然没有lisp风格的宏。 – Claudiu 2010-09-30 19:52:54