不要讨厌 COBOL,除非你尝试过

COBOL 就像计算机编程界的罗德尼·丹泽菲尔德,一直未受尊重,但它仍在使用中,并且确实值得尊敬。
485 位读者喜欢这篇文章。
What to like about COBOL

Rainer Gerhards。由 Opensource.com 修改。CC BY-SA 4.0

COBOL 就像编程语言界的罗德尼·丹泽菲尔德——它不受任何尊重。它因其冗长而被经常贬低,并被斥为过时。然而,COBOL 远非一种死语言。据估计,它处理了所有商业交易的 85%,并且每年编写 50 亿行新的 COBOL 代码。

我做了 10 年的 COBOL 程序员,我不认为它像人们口口相传的那样糟糕。事实上,它非常擅长处理货币和固定格式的记录。但是 COBOL 确实有它的怪癖,其中许多怪癖都根植于早期编程的计算环境中。这是一个关于一张穿孔卡片如何吃掉我的程序的故事。

一个神秘的错误

这是一个问题代码的示例,它试图计算订单的运费和预计发货日期

 1      identification division.
 2      program-id.
 3          test-ship.
 4
 5      data division.
 6      working-storage section.
 7
 8      01 shipping-method            pic x(2) value 'US'.
 9      01 cust-type                  pic x(2) value 'EM'.
10      01 normal-ship-date-yyyymmdd  pic 9(8) value 20170522.
11      01 nextday-ship-date-yyyymmdd pic 9(8) value 20170508.
12      01 expected-shipping-date     pic 9(8).
13      01 shipping-charge            pic 99v99 value 4.99.
14
15      procedure division.
16          if shipping-method <> 'FX'
17              move normal-ship-date-yyyymmdd to expected-shipping-date
18          else
19              move nextday-ship-date-yyyymmdd to expected-shipping-date.
20
21          if cust-type = 'EM'
22              move 0 to shipping-charge.
23
24          display expected-shipping-date.
25          display shipping-charge.

即使您以前从未见过 COBOL 代码,也应该很容易理解这个逻辑。如果运输方式是“FX”,客户将获得次日送达服务,否则运输需要两周时间。(那是 90 年代。)员工可以享受免费送货;其他人则需支付 4.99 美元。这段代码在我看来是正确的,但它有一个错误——发货日期计算正确,但员工被收取了全额运费。

问题最终被证明是第 19 行末尾的句点。在当时,追踪到这个问题需要一些侦探工作,但现代的语法高亮编辑器会立即标记出来。但是为什么这是一个问题?当 COBOL 对第 22 行末尾的句点非常满意时,为什么它不喜欢第 19 行的句点呢?

句子而不是代码块

要回答这个问题,我们需要追溯到 COBOL 在 1950 年代后期的起源。在此之前,大多数语言都是为解决科学和工程问题而设计的,因此它们的语法类似于数学方程式。(Fortran 是这种类型语言的经典示例。)另一方面,COBOL 旨在用于商业计算。为了让外行人更容易学习,格蕾丝·霍珀和她的国防部及 IBM 工程师团队赋予了 COBOL 英语语言语法。COBOL 程序没有大多数现代语言都具有的递归语法,而是具有分层结构。COBOL 没有代码块,而是将语句组合成“句子”。就像在英语中一样,每个句子都以句点结尾。

虽然这在理论上可能看起来是个好主意,但在实践中却被证明是有问题的。它使得移动代码变得困难,因为一个意外的句点可能会意外地终止一个代码块。句点也很难注意到——在 90 年代早期的 CRT 终端上,它们通常只是一个像素。但这里存在一个更深层次的问题,这个问题与程序员在 COBOL 最初开发时编写代码的方式有关。

穿孔卡片

COBOL punch card

opensource.com

当 COBOL 被设计出来时,硬盘驱动器非常昂贵,因此大多数程序都是在穿孔卡片上编写的。最常见的穿孔卡片由 12x80 的网格组成,其中一个孔代表 1,非孔代表 0。每列是一个 12 位字符,每张卡片是一行 80 个字符的文本。要运行您的程序,您需要将一叠穿孔卡片送入读卡器。每张卡片的前六列和最后八列保留用于序列号和标识符。这样,如果您不小心掉落了您的卡片堆——这可能是您的程序的唯一副本——您可以将卡片通过机械分拣机送入,以将其放回正确的顺序。

这意味着 COBOL 会忽略第 72 列之后的任何字符。如果碰巧是一个句点,您代码的整个逻辑都可能改变。而且,正如您现在无疑已经猜到的那样,第 19 行的句点在第 73 列。以下是 COBOL 编译器实际解释这些行的方式

16          if shipping-method <> 'FX'
17              move normal-ship-date-yyyymmdd to expected-shipping-date
18          else
19              move nextday-ship-date-yyyymmdd to expected-shipping-date
20
21              if cust-type = 'EM'
22                  move 0 to shipping-charge.

一旦我发现问题所在,修复就很容易了:我从第 19 行的开头删除了一个空格字符,这使得句点位于第 72 列。虽然我以前从未遇到过这种情况,但这确实是一个常见的错误,以至于许多大型机 COBOL 程序员会在他们的终端上在第 72 列和第 73 列之间粘贴一根线。

今天的 COBOL

COBOL-85 标准添加了像 end-if 这样的范围终止符,因此句点不再是结束句子的必要条件。COBOL 2002 标准允许自由格式的代码,尽管许多编译器早在之前就支持了。按照 2002 标准编写的相同代码看起来更像是一种现代编程语言

16 if shipping-method <> 'FX'
17     move normal-ship-date-yyyymmdd to expected-shipping-date
18 else
19     move nextday-ship-date-yyyymmdd to expected-shipping-date
20 end-if
21
22 if cust-type = 'EM'
23     move 0 to shipping-charge
24 end-if

请注意,行首的空格也不再是必要的。我通常工作的系统同时支持范围终止符和自由格式代码,所以我直到在另一个系统上进行一些更改时才遇到这个问题。

对于开源爱好者来说,学习 COBOL 一直很困难。COBOL 编译器传统上是闭源且昂贵的,并且大多数 COBOL 代码都是在企业环境中编写的。然而,一个名为 OpenCOBOL 的开源编译器的开发工作始于 2002 年。2013 年,它被正式接受为 GNU 软件包并更名为 GnuCOBOL。要了解有关 GnuCOBOL 的更多信息,包括访问 400 页的程序员指南,请访问项目主页

在沃尔特·曼科夫斯基在费城举行的 FOSSCON 8 月 26 日的演讲 一张穿孔卡片吃掉了我的程序! 中了解更多关于 COBOL 的信息。

标签
User profile image.
沃尔特·曼科夫斯基是一位从象牙塔中走出来的计算机科学家,他最近完成了一项博士后研究,与生物学家合作处理和可视化 TB 级的 2D 和 3D 延时显微镜图像。在他的过去生活中,他曾在一家主要的有线家庭购物网络担任了 10 年的 COBOL 程序员。他喜欢 Perl、正则表达式、高性能计算和《飞出个未来》。

39 条评论

感谢这篇精彩的文章!在我的职业生涯早期,我做了一些 COBOL 工作,并且仍然是它的粉丝。

我已经使用 COBOL-85 标准三十年了,并且从未遇到过句点问题。事实上,我写的每个段落都以 EXIT 语句结尾,并且段落中的最后一件事是 EXIT 前一行上的句点。

在您编写过程划分代码时要有条理;在您的 WORKING-STORAGE SECTION 中要有创新性和条理性,COBOL 可以完成任何事情。

1000-PARAGRAPH.

IF
blah blah blah
END-IF
.
1000-EXIT. EXIT.

:)

只是一个小小的吹毛求疵... 第 72 列很特别。如果它包含连字符或“C”,那么编译器应该将下一行附加为单行进行处理。

老实说,我 99% 的时间使用的系统都使用自由格式代码,所以这个问题从未出现过。但我在线找到的所有内容都说,延续符由第 7 列中的“-”表示,这意味着当前行应该附加到上一行。我找不到任何表明第 72 列被特殊对待的迹象。也许您把它与另一种语言混淆了?

回复 作者 马丁·迪维奥 (未验证)

抱歉... 但绝对是第 72 列。已经超过 30 年了,所以我忘记了它是 COBOL66 的一部分还是 ANSI COBOL 74“标准”。我记得有人试图在很久以前使用它,直到系统管理员告诉他使用更短的变量名并继续前进。

回复 作者 waltman

自 1983 年以来,我一直是 IBM 大型机软件开发人员。特殊的是第 7 列,而不是第 72 列。“-”表示从上一行延续,“*”表示注释行,“/”是编译器指令,用于在编译器列表中强制分页符。任何其他内容都不是标准。

回复 作者 马丁·迪维奥 (未验证)

似乎 JCL 和一些大型机汇编程序使用第 72 列来表示延续,所以我猜想某些早期版本的 COBOL 也可能这样做。

回复 作者 斯科特·斯普洛克 (未验证)

如果我没记错的话,在 COBOL 刚问世时,硬盘驱动器并不存在。大型计算机将数据保存在磁带或纸带上。

IBM 在 1956 年发布了他们的第一个硬盘驱动器 IBM 305 RAMAC。那是在 COBOL 出现之前的几年,COBOL 的历史可以追溯到 1959 年。硬盘驱动器存储非常昂贵,这可能就是为什么它们仍然不常见的原因。

回复 作者 格雷格·P

当我查找这个时,它似乎确实存在硬盘,但目前还不清楚它们是如何使用的,因为它们最初通常只有几 MB 的存储空间。

回复 作者 格雷格·P

是的。在我的演讲中,我有一张 1956 年工人们移动一个 5 MB 硬盘驱动器的照片,它有几个冰箱那么大。但是,我曾经用过的第一个 PC 硬盘驱动器只有 3 MB 的存储空间,而且它看起来已经非常大了!

回复 作者 格雷格·P

这叫做臃肿软件。今天的计算机和手机都充满了它。

在嬉皮士时代(60 年代和 70 年代),您有时只有 40 KB 的大型机空间来运行程序。
所以您非常努力地使其适合。如果 COBOL 无法完成,那么您就用汇编程序来完成(至少我们中的一些人是这样做的)。
与今天的精英不同,只有强者才能生存。

回复 作者 格雷格·P

我在 80 年代早期在那些早期的 PC 上开始编程。当我还是象牙塔里的计算机科学家时,我仍然有一台 PC,但它有 32 个 CPU、64 GB 的 RAM 和 TB 级的存储空间。我们能够处理当时无法想象的计算问题。而且,编程已经够难的了,无需再微观管理内存。虽然回顾过去很有趣,但这让我更加欣赏现代硬件和软件!

回复 作者 托尼·Q·金

除非您见过 COBOL 程序在 4K Remington-Rand Univac-II 上编译,并且 12 个大型磁带驱动器同时旋转,否则您什么都没见过。在 1960 年代早期,一个小型程序大约需要 1 到 2 小时才能编译。
但是一旦 IBM 360 在大约 1965 年推出,配备了大型 2311 磁盘驱动器 - 每个 7 兆! - 该程序将在不到 10 分钟的时间内编译完成。

是的,那是 4K,而不是 4 兆。

回复 作者 格雷格·P

磁盘驱动器在 60 年代中期随着 IBM 的 360 系列计算机和操作系统的发布而变得普遍。对于试图在配备 4K RAM 和 12 个大型磁带驱动器的 Remington-Rand Univac-II 上编译 COBOL 程序的人来说,这是一个受欢迎的解脱。
您应该看看当一个小型的 COBOL 程序正在编译时,所有这些磁带是如何工作的。通常需要 1 到 2 个小时(自然是在夜间运行)
(喃喃自语...诅咒你,格蕾丝·霍珀...!)

** 是的,那是 4 K!不是 4 MB。

回复 作者 格雷格·P

很久以前用过 Cobol,现在仍然喜欢它!简单易懂。如果我今天想编写一行代码,我必须安装 25 个开源工具和库,破解一些命令行内容,并在任何东西出现之前祈祷。

当您在第 7 列中放置星号时,它会将该行的其余部分变成注释。猜猜怎么着,我有一个注释掉了一个 GOTO 语句。(哎呀)

第 7 列和第 72 列协同工作。第 7 列有几个用途,但它可以与第 72 列结合使用,以表示延续和连接几个涉及国家字符集(解析为非拉丁字符代码的多字节序列)的特殊情况。请参阅:https://www.ibm.com/support/knowledgecenter/en/SS6SGM_3.1.0/com.ibm.aix…

关于穿孔卡片的另一个次要观察或趣闻。
今天很少有程序员/IT“专家”意识到 80 个字符的文本行(在编辑器或终端屏幕上)来自 120 年前(至少!)的霍勒里斯穿孔卡片,最终被 IBM 数据处理采用,然后在 1970 年代最终进入磁带(短暂地)并最终进入磁盘的编程库之前。
唉,赫尔曼·霍勒里斯在 COBOL 甚至还没有成为格蕾丝海军上将的 80 列卡片上的一个穿孔之前就去世了。
如果您想为此辩护,您甚至可以争辩说,这些穿孔卡片最初是由 18 世纪的纺织织布工开发的。

附言:在任何人试图追溯到更久远的历史之前
有些人声称穿孔卡片的宽度(或可能是其长度)最初是基于罗马战车车轮的轨道宽度及其在 2000 年前的罗马道路上的特殊矩形凹痕。
胡说八道!与关于土星 1 号火箭助推器尺寸基于罗马道路的说法一样,这只是另一个都市传说。 ;-)

回复 作者 托尼·Q·金

硬盘驱动器的有限容量和成本与穿孔卡片的使用(在存储程序方面)有关,但还存在缺乏廉价终端的问题。在 1970 年代后期的马里兰大学,学生可以使用的 ASCII 电传打字机数量有限,这意味着大多数学生不得不使用穿孔卡片。(当我在那里时,电传打字机被类似 DECwriter 的点阵键盘/打印机取代了。)UNIVAC 大型机的磁鼓已被硬盘驱动器取代,但操作系统继续提供鼓 API,该 API 在硬盘驱动器上模拟鼓。

我只在 1981 年的数据库课程中使用过一次 COBOL,但我事先阅读过丹尼尔·麦克拉肯关于 COBOL 的经典著作(以及他关于 Fortran 和 Algol 的著作)已有几年了。我使用 COBOL 没有问题;每种编程语言都需要不同的思维模式,并且(在有限的时间内)了解 COBOL 与了解我使用过的所有其他语言一样令人智力满足。

在 1990 年代,我认为,一位 COBOL 布道者过去经常在美国新闻组 USENET 上发帖,要么是 comp.os.unix,要么是 comp.lang.c。他主要不是专注于 COBOL;它只是偶尔出现。在一篇文章中,他提出了一个*完整*、*可移植*、4 行 COBOL 程序来对文件进行排序。(我记得是这样...)可移植性是可能的,因为 COBOL 具有内置的排序功能,而大多数其他语言则没有。在另一种语言中使用特定于操作系统的系统调用来运行外部“排序”程序不是一种可移植的解决方案。

我在 80 年代早期去了宾夕法尼亚大学。我从未使用过穿孔卡片,但仍然有很多旧硬件正在逐步淘汰。但我真的在谈论 COBOL 的早期。计算机终端直到 70 年代初才开始出现,而 COBOL 在那时已经使用了十年。电传打字机出现得更早,但我不确定它们与大型机配合使用效果如何,因为我见过的所有电传打字机都需要双同步连接。

今天,当我用 C++、Perl 或 Python 等语言编程时,我经常想知道是否有更好的方法来编写某些东西。我应该使用哈希还是对象?结构还是类?循环还是列表推导?我在 COBOL 中从未这样做过,因为通常只有一种方法可以做任何事情。它可能不是一个好方法,但这就是你的做法。因此,我的大部分精力都投入到解决业务问题而不是语言问题上。当然,当您知道有很多更好的方法可以做事时,也会感到沮丧,但有时缺乏选择可以帮助集中注意力。 :)

回复 作者 亚历克斯·梅斯戴 (未验证)

很棒的文章。我很高兴看到 COBOL 仍然活着并被大量使用。

我是一家仍然活着的主要大型机公司的 COBOL 编译器开发人员。

其中一家大型机公司?您的意思是 Amdahl 和 Hitachi 仍然在游戏中?
45-50 年前,只有“白雪公主”和七个小矮人。
如果您能告诉我那七个可怜的小矮人的名字,那就额外加分!

回复 作者 用户

一个问题... 哪个版本的 COBOL 在 IF 语句中添加了 ELSE 子句?

我是一个 DBA 团队的成员,该团队必须使用不支持 ELSE 子句的 COBOL 从大型机数据库中提取和转换 Y2K 的数据。我们称之为“COBOL I”,但我找不到在线参考文献使用这个名称。

这太奇怪了!我不能说我听说过任何不支持 ELSE 的编程语言。如果您想做等效于 ELSE 的操作,您是否必须使用条件的否定来重复 IF?您的 COBOL 是在大型机上还是在其他平台上运行的?

回复 作者 DocSalvager

珍·萨梅特将“强大的条件(即,IF THEN ELSE)结构”列为 COBOL 的第一个版本 COBOL '60 的核心贡献之一。(参见珍·萨梅特的“COBOL 的早期历史”,第 199-243 页,《编程语言历史 I》(1978)。)我想知道您遇到的版本是否存在特定的实现问题。

回复 作者 DocSalvager

不,问题是第 73 列中的句点被忽略了。我第一次在 Stratus VOS 编译器上看到它,并且我能够在 GnuCOBOL 中复制它。它会在任何控制结构中发生。

回复 作者 杰夫·B (未验证)

但是,GnuCOBOL 没有像旧编译器那样做,而是说“第 72 列之后的源代码文本” :-)

回复 作者 waltman

那是我的第一篇文章,我没有看到编辑它的方法。我的意思是,最后一个不支持 ELSE 子句的版本是什么?

我仍然使用 Cobol。我所有的商业程序都在 Cobol 中。刚刚完成了一个新程序。GUI 界面,MySQL 数据库。从 IBM 360 开始,然后是 DEC10,1970 年代。然后是 TRS80 model II 和 III,最后是 PC。当前的服务器是 Linux Debian,带有 WIN10 用户机器。工作良好且快速。

好文章。我在 80 年代在大学里学习了 COBOL,并在 90 年代早期做了一些 COBOL 编程。我不能说我喜欢它,但它完成了工作。
您提到 COBOL“处理了估计 85% 的所有商业交易”。这个估计是否有具体的来源?
谢谢

很高兴看到 cobol 代码中使用小写字母。

我几十年前就这样做了;没人这么做。很高兴发现代码编译得很好。无法忍受所有大写字母,因为它总是对你大喊大叫。呜。

我在 Cobol 中有很多编程工作。我也使用穿孔卡片作为编程工作的输入。最初,语句被键入并穿孔,然后像其中一篇博客中显示的那样读取读卡器。我在 PDP/11 上处理所有业务应用程序。
编写代码非常容易,我的心仍然向着 Cobol。后来,我在中东为 IBM 计算机工作期间,在 1984 年至 1994 年这 10 年间,用 MF Cobol、RM Cobol、MS Cobol 编写了程序。我还用 AS/400 Cobol/400 编写了几个程序。我想即使在今天,我也会很高兴用 Cobol 编写代码。祝你好运。我在 Cobol 中做得很好

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.