简介
自 1999 年夏天以来,交互式软件工程部 (ISE) 和来自澳大利亚 Monash 大学的小组,就一直与 Microsoft 合作,将 Eiffel 集成到 Microsoft® 的 .NET Framework™ 中。
Eiffel 是一个综合的软件开发环境 (ISE Eiffel),它基于一个经历整个软件生命周期的方法 - 不仅有实现阶段,还有分析、设计、维护阶段。此环境基于 Eiffel 语言,完全应用对象技术的原则,并实现按合同设计的概念以生成高度可靠、可扩展和可重复使用的应用程序。ISE Eiffel 专门用于面向庞大且复杂的系统,金融、国防、实时和其它工业的一些主要组织将它用于基于关键任务的项目开发中。世界各地的许多大学 (例如 Monash 大学) 也使用 Eiffel 教授各种层次的编程和软件工程。
Microsoft .NET Framework 是 Microsoft 开发的下一代 Web 技术,它利用了许多建立 Internet 应用程序的技术解决方案。此框架包括 Active Server Pages+ (ASP+),与传统方法相比,ASP+ 可以相当快速而容易地构建基于 Web 的应用程序。此技术的核心是运行时,它用元数据来解释和/或编译字节代码(虚拟机的内部语言,也称为“IL”)。元数据说明系统的每一组成部分,包括其所有方法、字段和事件的原型。
对于希望利用操作系统、Internet、Web 基础结构、软件开发方法和开发环境方面的最佳技术的公司,Microsoft .NET Framework 中的 Eiffel 为其提供了完美的组合。特别是 Eiffel 对其它语言和环境的开放以及 .NET Framework 对语言中立性的强调,使最终得到的产品,在 Eiffel 充当“粘合剂”的条件下,能够非常理想地用于开发含有各种编程语言的应用程序。本文说明这种组合以及将 ISE Eiffel 集成到 .NET Framework 中时所面临的挑战。
从 Eiffel 生成 .NET Framework 系统
将 .NET Framework 作为一种语言编译器实际上意味着能够生成 IL 和相关的元数据。
目标
如果目标仅是“在 .NET Framework 下编译 Eiffel”,那么生成 IL 就足够了。然而因为在没有说明 Eiffel 类型的元数据的情况下,其它语言无法重用这些类型,所以达不到为多语言交互操作性提供通用框架的目标。ISE 对于集成 Eiffel 设置的目标之一是能够重用用任意语言编写的现有类型,以及生成能被任意其它 .NET Framework 开发环境所理解的类型。Eiffel 是一个 .NET Framework 扩展器,意思是可编写从用其它语言编写的类继承的 Eiffel 类,扩展 Eiffel 类,然后将它们重新编译为 IL,从而使其它环境能够重用这种新类型。
IL 和元数据是通过系统文件(描述 Eiffel 系统的文件,也称为 ACE 文件)的一个特殊开关生成的,以便新的 Eiffel 编译器充分集成到 ISE 的集成开发环境 (IDE) EiffelBench 中。原有 Eiffel 程序员能够以集成前的方式工作。
端口的另一方面包括将编译器集成到 Microsoft Visual Studio® .NET 中。对于不愿或无暇学习新环境而又已经用 Visual Studio 来加快学习速度的 Eiffel 新开发者来说,这种集成会对他们有所帮助。此集成将支持 Visual Studio 的所有特定功能,如语法突出显示、调试程序和一些向导。
另一个关键的目标是在 Eiffel 中编写 ASP+ 页面的能力。ISE 的目标是全面支持(所谓的高级语义学 )以便 Eiffel 开发者能够使用
"@language="Eiffel""
指令将 Eiffel 嵌套到 ASP+ 页面中。这项支持还包括将 Web 服务写入 Eiffel 的能力。
策略
树立了这些目标后,ISE 围绕两个关键步骤组织集成。集成的第一步生成一种叫做 Eiffel# (发音是“Eiffel Sharp”)的语言。Eiffel 的这种子语言专门面向 .NET Framework 并充分体现“按合同设计”的设计思想。在保持 .NET Framework 原有对象模型的同时,完全能够建立真正的应用程序。第二步包括将结果扩展到整个 Eiffel 对象模型。
集成到 Visual Studio 和 ASP+ 中都从 Eiffel# 开始。集成到 Visual Studio 需要先简单地集成不带任何可用功能的命令行编译器。对 ASP+ 的支持需要先支持 Web 服务。
由 Microsoft .NET Framework 的第一个非测试发行版可以得到对所有这些技术以及整个 Eiffel 语言的支持。Eiffel# 将逐渐利用越来越多的 .NET Framework 技术。
Eiffel#,语言
本节集中说明定义 Eiffel# 的第一版。规范将随后续的 .NET Framework 测试版不断进行改进。对 Eiffel# 的关键要求是只使用通用语言运行时而不使用任何其它 Eiffel 专用的运行时。
Eiffel,简介
因为本文档的其它部分通过说明 Eiffel# 与 Eiffel 的不同来定义 Eiffel#,所以我们首先需要看看 Eiffel 的主要特征。更多的细节可以在 Object-Oriented Software Construction,第二版 和 Eiffel: The language 这两本书中以及 Eiffel Web 站点 http://www.eiffel.com/ 上找到,本文的一些资料就是从此站点获得的。
作为一种语言,Eiffel 基于以下少数强大的概念,是“纯粹”的面向对象的语言(有人说它是现有语言中最系统地应用面向对象原则的语言,这一点是有争议的):
无缝开发。Eiffel 适用于从分析、高级别设计到实现和维护的整个生存周期,在整个软件过程中提供单个概念框架。
作为模块结构和类型系统的唯一基础的类。
对分类、子类型和重用的继承。
多重继承(重命名、选择、重定义、未定义、重复继承)的谨慎而有效的方法。
对自动编写正确健壮的软件、自动调试它并自动将其文档化的支持。
用来从异常事件完好地恢复规范的异常处理方法。
在类型系统中没有漏洞以保证安全的静态键入。
确保灵活性和安全性的动态绑定。
用于描述灵活容器结构的受限制和不受限制的一般性。
开放式体系结构,可以很容易地访问用其它语言,如 C、Microsoft Visual C++ ® 等编写的软件。
为了解此语言的语法和风格(力求清晰而简洁),以下是一个简单类 COUNTER 的概况,该类说明一个计数器:
indexing
描述:“可以每次加 1 递增、递减和复位的计数器”
class
COUNTER
feature -- 存取
item: INTEGER
-- 计数器的值
feature -- 元素的改变
increment is
-- 将计数器的值加一。
do
item := item + 1
end
decrement is
-- 将计数器的值减一。
do
item := item - 1
end
reset is
-- 将计数器的值复位为 0。
do
item := 0
end
end -- 类 COUNTER
在运行时,此类会有实例;每个实例是一个代表不同计数器的对象。要创建一个计数器,请声明相应的实体,
my_counter: COUNTER
创建相应的对象(其中 create 是对象创建操作),
create my_counter
然后将此类的操作(其特性)应用到对象:
my_counter.increment
...
my_counter.decrement
...
print (my_counter.item)
这些操作将在其它类的特性中出现,被称为 COUNTER 类的用户。对此示例的其它注释;所有的值在缺省情况下都是初始化的,因此每个计数器对象都在值、项目初始化为 0 时开始生命(最初不需要调用复位)。而且,项目是一个属性,是以只读模式导出的 - 客户可以说打印 (my_counter.item ),但不能说 my_counter.item := 657 ,因为这样就违反了“信息隐藏”。当然,类作者可能决定通过添加如下属性来提供此功能:
set (some_value: INTEGER) is
-- 将计数器的值设置为 some_value。
do
item := some_value
end
在这种情况下,客户只使用 my_counter.set (657 )。但这是 COUNTER 类作者的决定:应该给他们的客户提供多少功能。类开始的索引子句不影响它的语义(相应的运行时对象的属性),只是将额外文档附加到类。
Eiffel 有独特的设计方法和语言,通过构造诸如类不变量、前置条件和后置条件之类的构造强制执行“按合同设计”。例如,假定希望我们的计数器总是非负,类将有一个不变量:
indexing ... class
COUNTER
feature
...
invariant
item = 0
end
特性递减现在需要一个前置条件,以确保客户没有尝试非法操作。关键字“require”引入前置条件:
decrement is
-- 将计数器的值减一。
require
item 0
do
item := item - 1
ensure
item = old item - 1
end
关键字“ensure”引入后置条件。
前置条件告诉客户:“您确认计数器绝对是正数否则不要考虑调用我”,后置条件说:“如果您的操作正确(遵守前置条件),我的承诺是:将计数器的值减一”。
不变量添加的承诺:“并且我的所有操作将保持计数器为正数或零”。前置条件、后置条件和不变量称为断言。
Eiffel# 与 Eiffel
Eiffel 的此简介提供它集成到 Microsoft .NET Framework 中的几个有趣问题。因为通用语言的运行时被设计为仅支持单一继承,所以最有挑战性的也许就是对多重继承的支持。由于 Eiffel# 必须仅使用通用语言运行时,因此它必须遵守 .NET Framework 对象模型,从而禁止有效类或部分延迟类的多重继承。然而可以多重继承纯延迟类;这时候纯