程序设计语言与编译
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.11 类型等价

Pascal语言要求赋值语句的两边要有“相同的类型”。何谓相同的类型?这是一个语义问题。通常把它称为类型等价(Type Equivalence),或类型相容性(TyPe Compatibility)。本节讨论类型等价的非形式化规则,这些规则对如何使用类型检查给出了准确的规定。

若Tl和T2是两个类型,且T1的任何值都可以赋予T2类型的变量,反之亦然;类型T1的实参可对应类型T2的形参,反之亦然,则称类型T1和T2是相容的(Compatible)。

考虑Pascal说明

          type t=array[1..20]of integer;
          var a,b :array[1..20]of integer;
            c :t;
            d :record a :integer;
                    b :t
                end

可对其定义两种类型等价变量概念。

1.名字等价

若两个变量具有相同的用户定义类型名或内部类型名,则称它们具有相容的类型。上述程序中变量c和d.b具有相容的类型。若两个变量具有相容的类型,仅当它们的类型名是相同的,则称两个变量名字等价(Name Equivalence)。有人这样定义两个变量等价:出现在同一说明中的两个变量是等价的。根据这一定义,上述程序中的a和b是等价的。Ada语言就采用这样的名字等价定义。

2.结构等价

若两个变量的类型具有相同的结构,则它们具有相容的类型,并称两个变量结构等价(Structural Equivalence)。按照这一定义,用户定义类型名仅作为其代表的结构的缩写(或注释),而不引起任何新的语义特性。为了验证结构等价,只需用它们的定义来替换用户定义名,重复这一过程,直到没有用户定义类型名为止。若最后留下的结构描述正好是相同的,那么这两个变量是结构等价的。上例中a,b,c和d.b具有相容的类型,因为它们是结构等价的。当用指针建立递归类型定义时,结构等价定义可能导致无限循环。采用结构等价语言,通过提供相应的规则可防止这一问题的发生。ALGOL 68采用结构等价来定义类型的相容性;Pascal没有规定采用哪种类型的相容性概念,把它留给实现来确定。遗憾的是,这样做的结果使得一个Pascal程序可能被这一个编译器接受,而被另一个编译器拒绝。

在大多数情况下,原始Pascal定义的实现采用结构等价,选择名字等价的程序就是非法的。例如,赋一个整数值到一个被说明成整数子界的变量是非法的,除非语言定义了相应的转换。参数传递采用名字等价。ISO Pascal严格定义了主要基于名字等价的相容性。

Ada类型的相容性通过名字等价来定义,属于同一类型的不同子类型的对象都是相容的。在编译时尽可能检查界限,余下的在运行时检查。

ALGOL 68采用基于结构等价的类型相容性概念,尽量彻底忽略用户定义名字。因此,它的强类型特性是以纯静态类型概念为基础的。例如,ALGOL 68说明

          mode celsius = int;
          mode fahrenheit = int;

使celsius和fahrenheit具有相容的类型,因为它们是结构等价的。前者表示摄式温度,后者表示华氏温度,由于它们两者类型相容,所以,它们的变量可以相互赋值。这样可以使一个表示摄氏温度的变量值,合法地赋予表示华氏温度的变量,虽然这很可能是一个程序错误。Ada语言解决这个问题的办法是,定义两个INTEGER的派生类型:

          type CELSIUS is new INTEGER;
          type FAHRENHEIT is new INTEGER;

这使得两者的变量属于不同的类型,彼此的变量相互赋值是非法的。

名字等价的实现比较简单,而结构等价的实现需要的模式匹配过程可能十分复杂。