GOTO仍然认为有害?

每个人都知道迪杰斯特拉给编辑的信件:去看看被认为有害的声明(这里也是.html文字记录和这里.pdf),并且自那时以来一直强大的推动,以尽可能避免goto声明。 尽管可以使用goto来生成不可维护,庞大的代码,但它仍然处于现代编程语言中。 即使是Scheme中先进的继续控制结构也可以被描述成一个复杂的goto。

什么情况下需要使用goto? 什么时候最好避免?

作为一个后续问题:C提供了一对函数setjmp和longjmp,它们提供了不仅在当前堆栈帧内而且在任何调用帧内跳转的功能。 这些被认为是危险的吗? 更危险?


迪杰斯特拉本人对这个称号感到后悔,对此他不负责任。 在EWD1308(也在这里.pdf)的最后,他写道:

最后是一个记录的小故事。 1968年,ACM通讯发表了一篇题为“goto声明被认为是有害的”的文本,后来几年这篇文章被引用频率最高,但令人遗憾的是,经常没有看到它的作者经常看到它标题,通过成为一个模板而成为了我的名气的基石:我们将看到几乎所有X都以“X被认为有害”为标题的各种文章,其中包括题为“Dijkstra认为有害”的文章。 但是发生了什么? 我已经提交了一个名为“ 反对goto声明的案例 ”的论文,为了加快发布,编辑变成了“给编辑的一封信”,在这个过程中,他给了它一个新的他自己发明的头衔! 编辑是Niklaus Wirth。

关于这个主题的经过深思熟虑的经典论文,与Dijkstra的论文相匹配,是由Donald E. Knuth撰写的结构化程序设计与语句。 阅读都有助于重新建立语境和对主题的非教条理解。 在本文中,Dijkstra对此案的看法被报道,并且更为强烈:

唐纳德E.克努特:我相信通过提出这样的观点,我并不认同迪克斯特拉的观点,因为他最近写了以下内容:“请不要陷入相信我非常讨厌[去声明] 我有一种令人不舒服的感觉,就是其他人正在把它变成一种宗教,好像编程的概念问题可以通过一个简单的编程技巧来解决!


以下陈述是概括性的; 虽然总是有可能辩论例外,但它通常(以我的经验和谦逊的观点)是不值得冒险的。

  • 内存地址的无约束使用(GOTO或原始指针)提供了太多机会来制作容易避免的错误。
  • 在代码中到达特定“位置”的方式越多,对此系统的状态就越不自信。 (见下文。)
  • 结构化编程恕我直言,不是关于“避免GOTO”,更多是关于使代码结构与数据结构相匹配。 例如,重复的数据结构(例如数组,序列文件等)自然是由重复的代码单元处理的。 内置结构(例如while,for,until,each等)允许程序员避免重复相同的陈旧代码模式的乏味。
  • 即使GOTO是低级实现细节(并非总是如此!),它低于程序员应该考虑的级别。 有多少程序员在原始二进制文件中平衡他们的个人支票簿? 有多少程序员担心磁盘上的哪个扇区包含特定的记录,而不仅仅是为数据库引擎提供密钥(以及如果我们真的用物理磁盘扇区编写所有程序,会出现多少错误?
  • 上述脚注:

    关于第2点,请考虑以下代码:

    a = b + 1
    /* do something with a */
    

    在代码中的“做某事”时,我们可以高度置信地表明a大于b 。 (是的,我忽略了未处理的整数溢出的可能性,让我们不要陷入一个简单的例子。)

    另一方面,如果代码是这样读取的:

    ...
    goto 10
    ...
    a = b + 1
    10: /* do something with a */
    ...
    goto 10
    ...
    

    标签10的多样性意味着我们必须更加努力地对ab之间的关系充满信心。 (事实上​​,在一般情况下,它是不可否认的!)

    关于第4点,代码中“去某处”的概念只是一个比喻。 除了电子和光子(用于废热)之外,CPU内部的任何地方都没有“真正的”走向。 有时候我们会放弃另一个更有用的比喻。 我记得遇到(几十年前!)一种语言在哪里

    if (some condition) {
      action-1
    } else {
      action-2
    }
    

    通过将action-1和action-2编译为非线性无参数例程,然后使用一个使用条件的布尔值调用其中一个的双参数VM操作码,在虚拟机上实现。 这个概念只是“选择现在调用的内容”而不是“去这里或去那里”。 再次,只是一个比喻的变化。


    XKCD's GOTO Comic

    我的一位同事说,使用GOTO的唯一理由是,如果你将自己编程到一个角落,那么这是唯一的出路。 换句话说,提前进行适当的设计,您将不需要稍后使用GOTO。

    我认为这部漫画很好地说明了这一点:“我可以重新调整程序的流程,或者使用一点'GOTO'来代替。” 当你设计不力时,GOTO是一个薄弱的出路。 Velociraptors捕食软弱动物。


    有时可以使用GOTO作为单个函数内异常处理的替代方法:

    if (f() == false) goto err_cleanup;
    if (g() == false) goto err_cleanup;
    if (h() == false) goto err_cleanup;
    
    return;
    
    err_cleanup:
    ...
    

    COM代码似乎经常陷入这种模式。

    链接地址: http://www.djcxy.com/p/53767.html

    上一篇: GOTO still considered harmful?

    下一篇: Programming in Java bytecode