在Java 8中删除功能类型的原因


12

我一直试图理解为什么JDK 8 Lambda专家组(EG)决定不在Java编程语言中包括新的函数类型。

在邮件列表中,我找到了一个讨论删除函数类型的话题

许多语句对我来说是模棱两可的,这可能是由于缺乏上下文,在某些情况下,是因为我对类型系统的实现了解有限。

但是,我相信我可以安全地在此站点中提出几个问题,以帮助我更好地理解它们的含义。

我知道我可以在邮件列表中提出问题,但是该线程很旧,并且所有决策都已制定,因此我很可能会被忽略,尤其是看到这些人已经推迟了他们的计划。

在支持删除功能类型并支持使用SAM类型的回答中,Brian Goetz说:

没有修复。关于修正函数类型的实用性有很长的篇幅。如果不进行具体化,函数类型将受到阻碍。

我找不到他提到的话题。现在,我可以理解,结构函数类型的引入可能暗示着Java(通常是名义上的类型)系统中的某些复杂性,我无法理解的是参数化SAM类型在具体化方面有何不同。

难道他们都没有受到相同的修复问题吗?有谁知道功能类型在参数化方面与参数化SAM类型有何不同?

格茨在另一条评论中说:

有两种基本的键入方法:标称方法和结构方法。名词的标识基于其名称;结构类型的标识基于其组成(例如“ int,int的元组”或“ int到float的函数”。)大多数语言大多选择名词性或结构性;除了“边缘”外,没有多少语言能够成功地混合名义和结构类型。Java几乎完全是名义上的(有一些例外:数组是结构型的,但是在底部总是有名义上的元素类型;泛型也有名义上的和结构上的混合,实际上这是许多源代码的一部分)人们对泛型的抱怨。)将结构类型系统(函数类型)嫁接到Java上 标称类型的系统意味着新的复杂性和边缘情况。函数类型的好处值得吗?

那些拥有实施类型系统经验的人。您知道他在这里提到的这些复杂性或极端情况的任何例子吗?

老实说,当我认为像Scala这样完全基于JVM的编程语言支持结构类型(如函数和元组)时,即使存在底层平台的验证问题,我也对这些指控感到困惑。

不要误会我的意思,我并不是说功能类型应该比SAM类型更好。我只想了解他们为什么做出这个决定。


4
“将结构类型系统(函数类型)嫁接到Java的标称类型系统上意味着新的复杂性” -这很可能是用户必须学习更多使用该语言的复杂性。诸如简单易用的Java之类的东西变得复杂而又难以学习C ++之类的东西。邮件列表成员可能暗示对以前的“重大改进浪潮”的批评,其中一个著名的例子是MyBatis的Clinton Begin的Java 5烂透了
t

3
“简单易用的Java变得很复杂,很难学习C ++”:不幸的是,主流编程语言的一个问题是它们必须保持向后兼容性,因此它们往往变得太复杂。因此,恕我直言(拥有多年的C ++和Java经验)对此声明有些正确。我经常感到应该冻结Java,而应该开发一种新的语言。但是Oracle不能承担这样的风险。
Giorgio 2013年

4
@edalorzo:正如Clojure,Groovy,Scala和其他语言所示,可以(1)定义一种新语言(2)使用已经用Java编写的所有丰富的库和工具,而不会破坏向后兼容性(3) Java程序员可以自由选择是继续使用Java,切换到另一种语言还是同时使用两者。IMO无限期扩展现有语言是一种保持客户的策略,就像移动电话公司始终需要创建新模型一样。
Giorgio

2
Java的SAMbdas可以理解,原因之一是保持某些库(集合)向后兼容会很成问题。
PetrPudlák13年

Answers:


6

SAM方法实际上有点类似于Scala(和C ++ 11)对匿名函数(使用Scala的=>运算符或C ++ 11的[]()(lambda)语法创建)进行的操作。

在Java方面要回答的第一个问题是,让lambda语句的返回类型是新的原始类型(如intbyte)还是某种对象类型。在Scala中,存在没有基本类型-甚至一个整数是类的一个对象Int-与功能都没有什么区别,是类的对象Function1Function2等,这取决于参数的数量的函数采用。

C ++ 11,ruby和python同样具有lambda表达式,这些表达式返回可以显式或隐式调用的对象。返回的对象具有某种标准方法(例如#call,可用于将其作为函数调用。例如,C ++ 11使用std::function重载的类型,operator()因此从文本上看,对象的call方法的调用甚至看起来像函数调用一样。 :-)

针对Java的新建议比较混乱的地方是使用结构化类型,以允许将这种方法分配给另一个对象,例如Comparator,具有一个具有不同名称的单个main方法的对象。尽管从概念上讲这在某些方面有些棘手,但这确实意味着可以将结果对象传递给现有函数,这些函数采用一个对象来表示回调,比较器等,并希望能够调用定义明确的单个对象。方法,例如#compare#callback。C ++重写技巧operator()巧妙地规避了这个问题,甚至在C ++ 11之前也是如此,因为所有此类回调选项都可以以相同的方式调用,因此STL无需进行任何调整即可使用C ++ 11 lambda。sort等等。Java过去没有使用过此类对象的标准命名(也许是因为没有像操作符重载这样的技巧使单一方法变得显而易见),Java并不是那么幸运,因此这种破解阻止了它们不得不更改大量现有的API。 。


1
具有讽刺意味的是,如果具有无数不同的,不兼容的类型,全部代表某种“类似于函数的事物”,则可以通过尽早将标准函数类型添加到库中而完全避免这种问题,而不必使用实际的构造它们的文字语法。如果java.util.Function2<T1, T2, R>Java 1.0中有a ,则将没有Comparator接口,所有这些方法都将带有a Function2<T1, T2, int>。(好吧,Function2TT_int<T1, T2>由于原始元素的存在,会有大量的接口,但是你明白我的意思。)
JörgW Mittag
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.