一个好的通用类型系统


29

人们普遍认为Java泛型在某些重要方面失败了。通配符和范围的组合导致了一些严重无法读取的代码。

但是,当我看其他语言时,似乎真的找不到程序员满意的通用类型系统。

如果我们将以下作为此类类型系统的设计目标:

  • 总是产生易于阅读的类型声明
  • 易于学习(无需复数协方差,逆方差等)
  • 最大化编译时错误的数量

有没有正确的语言?如果我使用google,我唯一看到的就是对类型系统如何吸收X语言的抱怨。这种类型的复杂性是通用类型固有的吗?我们应该放弃在编译时尝试100%验证类型安全性的想法吗?

我的主要问题是,就这三个目标而言,哪种语言“做到最好”是最好的。我意识到这是主观的,但到目前为止,我什至找不到一种语言,并非所有程序员都同意通用类型系统是一团糟。

附录:如前所述,子类型/继承和泛型的结合才是造成复杂性的原因,所以我真的在寻找一种将两者结合起来并避免复杂性激增的语言。


2
你是什么意思easy-to-read type declarations?第三个条件也是模棱两可的:例如,除非我可以在编译时计算索引,否则不让你索引数组,可以将数组索引超出范围的异常转化为编译时错误。同样,第二个标准排除了子类型化。这不一定是一件坏事,但您应该知道自己的要求。
2014年


9
@gnat,这绝对不是反对Java的。我几乎只用Java编程。我的观点是,泛型有缺陷(不是完全失败,但可能是部分失败)在Java社区中已被普遍接受,因此询问如何实现它们是一个逻辑问题。为什么他们做错了,别人做对了吗?还是实际上不可能获得完全正确的泛型?
彼得

1
如果每个人都只是从C#那里窃取信息,投诉就会减少。尤其是Java可以通过复制赶上来。相反,他们决定采用劣质的解决方案。Java设计委员会仍在讨论的许多问题已经在C#中确定并实现。他们甚至看起来都没有。
usr

2
@emodendroket:我认为我对C#泛型的两个最大抱怨是,没有办法应用“超类型”约束(例如Foo<T> where SiameseCat:T),并且不可能有不可转换为的泛型类型Object。恕我直言,.NET将从类似于结构的聚合类型中受益,但更多的是无约束的。如果KeyValuePair<TKey,TValue>是这样的类型,则IEnumerable<KeyValuePair<SiameseCat,FordFocus>>可以将强制转换为IEnumerable<KeyValuePair<Animal,Vehicle>>,但前提是不能将该类型装箱。
2014年

Answers:


24

尽管泛型在功能编程社区中已经成为主流,但将泛型添加到面向对象的编程语言中却带来了一些独特的挑战,特别是子类型化和泛型的交互。

但是,即使我们专注于面向对象的编程语言,尤其是Java,也可以设计出更好的泛型系统:

  1. 无论其他类型是什么,泛型类型都应该是可接受的。特别是,如果T是type参数,则以下表达式应在没有警告的情况下进行编译:

    object instanceof T; 
    T t = (T) object;
    T[] array = new T[1];
    

    是的,这需要泛型被仿造,就像语言中的其他所有类型一样。

  2. 泛型类型的协方差和协变应在其声明中指定(或从其声明中指定),而不是每次使用泛型类型时均应如此,因此我们可以编写

    Future<Provider<Integer>> s;
    Future<Provider<Number>> o = s; 
    

    而不是

    Future<? extends Provider<Integer>> s;
    Future<? extends Provider<? extends Number>> o = s;
    
  3. 由于泛型类型可能会变得很长,因此我们不必冗余地指定它们。也就是说,我们应该能够写

    Map<String, Map<String, List<LanguageDesigner>>> map;
    for (var e : map.values()) {
        for (var list : e.values()) {
            for (var person : list) {
                greet(person);
            }
        }
    }
    

    而不是

    Map<String, Map<String, List<LanguageDesigner>>> map;
    for (Map<String, List<LanguageDesigner>> e : map.values()) {
        for (List<LanguageDesigner> list : e.values()) {
            for (LanguageDesigner person : list) {
                greet(person);
            }
        }
    }
    
  4. 任何类型都应允许作为类型参数,而不仅仅是引用类型。(如果可以有int[],为什么不能有List<int>)?

所有这些都可以在C#中实现。


1
这还会摆脱自我指称的泛型吗?如果我想说一个可比较的对象可以将自己与任何相同类型或子类进行比较呢?能做到吗 或者,如果我编写了一个排序方法来接受具有可比较对象的列表,则所有这些方法都必须彼此可比。枚举是另一个很好的例子:Enum <E扩展了Enum <E >>。我并不是说类型系统应该能够做到这些,我只是很好奇C#如何处理这些情况。
彼得

1
Java 7的泛型类型推断C ++的自动帮助解决了其中的一些问题,但它们是语法糖,不会更改底层机制。

@Snowman Java的类型推断确实有些令人讨厌的极端情况,例如根本不使用匿名类,并且在将通用方法作为另一个通用方法的参数评估时,找不到通配符的正确界限。
2014年

@Doval就是为什么我说它可以帮助解决一些问题:它什么也不能解决,也不能解决所有问题。Java泛型有很多问题:尽管比原始类型好,但它们确实会引起很多麻烦。

34

在进行通用编程时,使用子类型会带来很多复杂性。如果您坚持使用带有子类型的语言,那么您必须接受随之而来的泛型编程存在一定的固有复杂性。某些语言比其他语言做得更好,但是到目前为止,您只能接受它。

例如,将其与Haskell的泛型进行对比。它们非常简单,如果您使用类型推断,就可以偶然编写正确的泛型函数。事实上,如果你指定一个类型,编译器常常对自己说,“好吧,我打算让这个普通的,但你问我,使其只为整数,所以不管。”

诚然,人们以惊人的复杂方式使用 Haskell的类型系统,这使它成为每个新手的祸根,但是底层的类型系统本身却优雅而令人钦佩。


1
感谢您的回答。本文从约书亚·布洛赫(Joshua Bloch)的一些泛型过于复杂的示例开始:artima.com/weblogs/viewpost.jsp?thread=222021。这是Java与Haskell在文化上的差异吗(在Haskell中此类构造会被认为是很好的),还是Haskell的类型系统在避免此类情况方面存在真正的差异?
彼得

10
@Peter Haskell没有子类型,就像Karl所说的那样,编译器可以自动推断类型,包括“类型a必须是某种整数”之类的约束。
2014年

换句话说,是协方差,例如Scala。
Paul Draper 2014年

14

大约20年前,在将泛型与子类型化结合方面进行了大量研究。由MIT的Barbara Liskov的研究小组开发的Thor编程语言具有“ where”子句的概念,可让您指定要参数化的类型的要求。(这类似于C ++尝试使用Concepts进行的操作。)

描述Thor的泛型以及它们如何与Thor的亚型相互作用的论文是:Day,M; 格鲁伯,R;Liskov,B;Myers,AC:子类型与where子句:约束参数多态性面向对象的Pro,Sys,Lang和Apps的ACM Conf(OOPSLA-10):156-158,1995年。

我认为,它们反过来又建立在1980年代后期对Emerald所做的工作的基础上。(我尚未阅读该著作,但参考文献是:Black,A; Hutchinson,N; Jul,E; Levy,H; Carter,L:Emerald中的Distribution and Abstract Types,_IEEE T.软件工程,13( 1):65-76,1987。

Thor和Emerald都是“学术语言”,因此他们可能没有得到足够的使用,人们无法真正了解where子句(概念)是否真正解决了任何实际问题。有趣的是,阅读Bjarne Stroustrup的文章,为什么第一次尝试用C ++进行概念失败了:Stroustrup,B:C ++ 0x“删除概念”决策Dobbs博士,2009年7月22日。(有关Stroustrup主页的详细信息。 )

人们似乎正在尝试的另一个方向是所谓的特质。例如,Mozilla的Rust编程语言使用特征。据我了解(可能是完全错误的),声明一个类满足一个特征非常像说一个类实现了一个接口,但是您说的是“行为像”而不是“是”。苹果公司新的Swift编程语言似乎正在使用类似的协议概念来指定对泛型参数的约束

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.