F 编程语言的便携性和强大功能
借助 F 编程语言,作者们结合四十多年的语言设计委员会经验,创造了世界上最便携、高效、强大而又简单的编程语言。Java 的便携性和强大功能最近备受关注,这恰逢其时,因为我们在 F 中展示了效率和可读性不必成为跨平台开发的牺牲品。
在深入探讨 F 编程语言的定义之前,本文首先介绍作者们一些带有偏见但几乎是事实的观点。我们承认——我们不是 C 和 C++ 的粉丝。
列举一些关于编程语言的事实和神话将有助于为 F 的讨论奠定基础。这些观点可能传达 F 编程语言设计背后的一些思想,使人们更好地理解作者的动机,从而更好地理解该语言。
事实 1: 程序被阅读的次数比编写的次数多。从您的第一个编程作业到您的职业生涯,字符被输入 一次,遵循某种语法和逻辑,然后被阅读和重读从两次到数百甚至数千次不等。无法阅读的程序只是糟糕的程序。
神话 1: Abbrev.R++ 缩写是好的。总体设计类似于 abbrev.R++ 的编程语言在思考/创建/编码/调试的快速行动者中非常受欢迎。毕竟,大多数程序员在学习打字之前就学会了如何编程。然而,从用 “}” 代替单词 “end”,用 “int” 代替 “integer”,以及用 i++ 或 ++i 代替 i=i+1 等缩写,只会给已经很复杂的难题增加更多碎片。就像一件抽象艺术品一样,有一天有人可能会看着您的代码并问,“这很好,但它是什么?”
事实 2: 教育语言已经消亡或正在消亡。当世界各地的一些教师正在寻找 Pascal 的合适替代品时,大多数人都在顺应专业潮流,将入门编程课程从 Pascal 转向 C、C++ 或 Java。如果 70 年代和 80 年代在 Pascal 环境中成长起来的一代程序员,在开始学习编程语言时就面临 C++ 或 Java 这种要么适应要么淘汰的局面,那么今天的计算机科学将会是什么样子,我们不得而知。如果 Pascal 不存在,那么阅读这篇文章的人(如果这篇文章甚至杂志存在的话)可能会更少。当然,计算机科学快速发展的一个主要因素是 Pascal 曾经提供的培育环境。
神话 2: 现代教育中 Pascal 的替代品对潜在的专业程序员没有任何优势。许多专业人士,特别是那些从事大型项目的人员,受益于小型编程语言提供的严格的风格执行的优势。小型语言还可以提供可靠的工具(编译器、调试器、性能分析器)、可靠的客户支持、可靠的错误消息和可靠的参考资料(教科书和在线文档)。由于 F 是一种基于现有实践的语言,专业人士可以利用大量现有的已调试代码。
事实 3: 选择错误的实现编程语言会影响大型项目的整体设计、可移植性和可维护性。许多公司在试图用缓慢发展的软件跟上快速发展的多平台行业时,遭受了巨大的经济打击。无论是为了提高效率和新功能而增强软件,还是将软件移植到最新的硬件,对原始编程语言的错误选择都可能导致公司资源的严重损失。在感到头痛之前,C 似乎是一个合适的、强大且可移植的选择。在 90 年代初期,C++ 承诺提供更强大的功能和可能更安全的功能。今天,Java 证明更安全且可移植,但牺牲了效率。
神话 3: 软件危机已经解决。由于看不到解决软件危机的希望,焦点已转移到“市场驱动”的干扰因素上,例如 热门的新编程语言,它充满了比选举年政治家更多的承诺。与此同时,大多数大型软件项目仍然是用 C 编写的,并且继续延迟交付、功能不足或不稳定。只要一种更小更简单的语言不牺牲性能,程序员及其管理层就应该醒悟到按计划交付稳定、完整的软件的可能性。这始于对合适的编程语言的决策。合适的选择不应强调领导该项目的程序员的潜在薪资,而是应考虑
C:我们需要访问系统信息,以牺牲可移植性为代价吗?
C++:我们需要对象和运行时绑定以及访问系统信息,以牺牲可读性和可移植性为代价吗?
Java:我们需要对象、运行时绑定和可移植性,以牺牲效率为代价吗?
F:我们需要可移植性、效率和可维护性,以牺牲访问系统信息(除非从 F 调用 C)和运行时绑定为代价吗? 事实 4: 大多数编程语言中的大多数语句都适合在一行中。在普通程序中,只有少数语句会跨越多行。在每个语句的末尾都需要分号意味着在几乎每一行的末尾都需要分号。 神话 4: 分号是生活的一部分。鉴于行尾通常是语句的结尾,那么微不足道的编程语言设计决策是在语句需要多行的罕见情况下使用特殊字符。在语句末尾需要分号是繁琐且容易出错的。要求使用分号的语言应该被要求在忘记分号时显示友好的错误消息。在 F 中,行尾是语句的结尾。如果一个语句需要多行,则在一行的末尾使用 (&) 符号。
设计一种编程语言涉及数千个想法和决策。效率(包括编译时间和运行时)、可读性、灵活性、熟悉度、简洁性、冗余、实现(编译器和工具)、风格、优雅性、完整性、国际化、标准化、市场性和目标受众等因素之间不断权衡取舍,仅举几例。上述事实和神话以及下面列出的原则帮助我们避免了(大部分)人际冲突,并根据这些目标做出决策
可读性
易学性且不损失专业能力
大型程序的可移植性和维护性
最小化不重要的语法
要求使用单词而不是依赖默认值
消除冗余
令有偏见的作者感到惊喜的是 F 的纯粹优雅。
除了赋值 (=) 和指针赋值 (=>) 之外,每个 F 语句的第一个单词都标识该语句。所有关键字都是保留字,允许为不正确的语法或拼写错误的关键字提供特定的错误消息。表 1 对所有 F 语句进行了分类。该图表显示,每个 F 过程,无论是子例程还是函数,都包含在一个模块中。
在 F 中,函数和子例程之间是有区别的。函数不允许有“副作用”,例如修改全局数据。所有函数参数都必须是 intent(in);子例程参数可以是 intent(in)、intent(out) 或 intent(inout)。所有过程参数都必须指定 intent,这允许编译器检查误用,并强制初学者和专业人员都记录意图。
F 中的内置类型包括 integer、real、complex、character 和 logical。用户定义的类型可以从内置类型和用户定义的类型构造。例如,可以构造一个 person 类型,使其具有姓名、身高、电话号码和指向下一个人的指针。用户可以定义对内置类型和用户定义类型进行操作的运算符。
F 中内置类型或用户定义类型的属性如 表 2 所示。指针是强类型的。也就是说,指针只能指向作为目标的对象。尽管这个想法在教学上很有意义,但单词 pointer 和 target 的最初目的是为了更好地优化编译器。
一种复杂的数组语言有助于对整个数组、连续和非连续部分以及数组切片进行操作。例如
arr(5:1:-2, 3, 6:)
是对二维数组的引用,该二维数组是通过取 arr 的第一维中的元素 5、3 和 1 以及 arr 的第三维中从 6 到上限的元素创建的,所有这些都在数组的第三个平面中。如果 arr 是一个 5x6x7 的数组,则引用的元素将是 (5,3,6)、(3,3,6)、(1,3,6)、(5,3,7)、(3,3,7)、(1,3,7)。
下面展示了一个更简单的示例,用于计算行和列的总和内积
A(i,j) = sum(B(i,:)*C(:,j))g
sum 是 F 中发现的一百多个内置过程之一。
模块是所有 F 代码的核心。模块是一种数据封装机制,允许将数据与操作该数据的过程分组在一起。模块可以使用其他模块。同样,程序和过程也可以使用模块。使用模块可以使该模块的公共实体可用。表 3 中提供了模块的示例。
人们不会像在 C++ 或 Java 中那样实例化模块的实例。相反,对象的概念最好被视为一个模块,该模块定义了一个公共的、用户定义的类型,以及对该类型进行操作的公共过程。此类模块的用户随后可以声明已定义类型的标量或数组,并访问其过程。
可以将公共的、用户定义的类型定义为具有私有组件,以便可以引用该类型及其过程;但是,构成该类型的各个部分对于定义模块是私有的。
F 编程可以称为面向模块的编程。就像 Java 要求所有过程都出现在类中一样,所有 F 过程都出现在模块中。不使用任何模块的 F 程序不能调用任何子例程或引用任何函数。模块可以使用其他模块来访问其公共实体。但是,除非唯一目的是收集一组模块并使所有公共实体都可以从一个模块访问,否则不允许模块使用另一个模块来导出已使用模块中的公共实体。
这种简单而强大的模块继承方法允许构建复杂的模块层次结构,而不会使理解他人代码所需的调查变得复杂。对函数 foo 的任何引用在编译时都被认为是特定模块中名为 foo 的公共函数的引用。即使没有编译器工具的帮助,F 的设计也使得快速搜索(借助 grep)单词 “function foo” 很可能会在屏幕上显示函数 foo 的定义行。
F 的一个很好的教育特性是,每个过程都必须声明为 public 或 private。结果是,编写调用子例程的程序的学生必须学习(或至少输入)单词 program、use、call、module、subroutine 和 public。public 和 private 列表也有助于专业人员,因为模块中过程名称的第一次出现会告诉您它是否是私有的,因此隔离到该模块。
F 允许重载过程名称以及重载运算符。但是,每个引用都在编译时解析。因此,语句
left = swap(int1, real2) * "hello"
显示了一个重载的乘法运算符,该运算符对 int1/real2 交换的结果和字符串 “hello” 进行操作。此外,swap 可以是一个通用名称,但它也在编译时解析为特定的函数。最后,赋值运算符 (=) 也可以重载;如果这不是内置赋值语句,则鼠标单击 = 可能会将您定向到将要调用的特定子例程。
在阅读本节之前,您可能想查看清单 1,1 中的示例 F 程序,即埃拉托斯特尼筛法。看看您是否可以猜出曾经流行的编程语言 F 是基于哪种语言的。基础语言的名称通常具有欺骗性,因为该语言鲜为人知的 1995 年标准比流行的 1977 年版本要现代得多。由于标准团队正在努力使 2000 年版本更加面向对象,因此 1990 年版本的编译器在最近几年才开始从大多数供应商处获得。如果您还没有猜到,您可能会惊讶地发现,当今最好的结构化编程语言是基于世界上第一种结构化编程语言——FORTRAN。
FORTRAN 至今已有 40 多年的历史,与任何其他编程语言相比,更多的程序员精力投入到了 FORTRAN 不断发展的定义中。每个 F 程序都是一个 FORTRAN 程序。随着计划在 2000 年推出更强大的面向对象功能,并继续支持数值密集型程序员,这种最近被遗忘的编程语言有望在未来十年内强势回归。
FORTRAN 的一个优势是标准不断更新新功能。供应商依赖于标准制定工作,并在规范被接受后宣布新的编译器。与在各种编译器已经上市后试图标准化的语言相比,这是一个强大的可移植性声明。随着 FORTRAN 标准关于条件编译的第 3 部分预计在一年内添加,正在为可移植性做出进一步的努力。
F 的 Linux 教育版可免费下载。Imagine1 网页 (http://www.imagine1.com/imagine1/) 包含免费的 Linux 版本,以及适用于 Windows、PowerPC Macintosh 和 Unix 的免费试用版。您还将找到 F 的 BNF、许多示例程序、F 教材的描述以及加入 f-interest-group 的邀请。作为参考,非 Linux 用户需要支付 101 美元购买 F 编译器和书籍。
Walt Brainerd 是大约十几本编程书籍的合著者。他参与 FORTRAN 开发和标准化已超过 25 年,并且曾担任 FORTRAN 90 标准的技术工作主管。 walt@imagine1.com
David Epstein 是 FORTRAN 标准关于条件编译的第 3 部分的项目编辑。他是 FORTRAN 编译器的表达式验证测试套件 (EVT) 的开发者,也是 Introduction to Programming with F 的作者。 david@imagine1.com
Dick Hendrickson 自 1963 年以来一直在教育和工业环境中从事 FORTRAN 编译器开发工作。他目前是编译器优化方面的顾问,也是 FORTRAN 编译器测试套件 SHAPE 的开发者之一。 dick@imagine1.com