C#,Java和Scala的Closures / Lambdas /…方法的优缺点是什么?


30

我想知道C#和Scala之间在技术上的实现差异是什么,以及两种解决方案如何与布莱恩·格茨(Brian Goetz)发送给Project Lambda(JSR 335)邮件列表的Peek Past lambda电子邮件中表达的实现思想和关注点进行比较?

从电子邮件:

我们探索了“也许lambdas应该只是内部类实例,那真的很简单”之路,但最终走到了“函数是语言未来的更好方向”的位置。

并进一步:

世界的lambdas-are-objects视图与这个可能的未来冲突。对世界的lambda-are-functions视图并不了解,并且保留这​​种灵活性是不让lambda负担甚至带有客观性的负担的要点之一。

结论:

Lambdas-are函数打开了大门。Lambdas-are-objects将它们关闭。
我们更希望看到那些门保持打开状态。

有人在Reddit主题上发表了一些评论:

我实际上通过电子邮件向Neal Gafter发送了电子邮件,由于我对他的解释的有限理解,C#和当前的Java设计非常相似,因为Delegates实际上是对象而不是函数类型。似乎他认为Java应该从C#的lambda的缺点中学习并避免它们(就像C#从Java的缺点中获悉并在一开始就避免它们一样)。

为什么“ Lambdas-are-functions”方法比“ Lambdas-are-objects”在将来能提供更多的机会?有人可以解释存在什么差异以及它们如何影响代码的编写方式吗?

看到Scala中的事情“可行”,我一直在想,我缺少关于C#/ Java(8)中采用/提出的方法的某些东西,可能与对向后兼容性的关注有关吗?


1
这是有趣的。鉴于Java类型系统到目前为止还没有函数的概念,这意味着必须先引入这一点。这种语言可能会变得太复杂。
Ingo

某些接口的实例不应该起作用吗?他们有什么特别之处?
soc

Lisp / Scheme / Clojure可以对对象建模,而Java / C#不能对函数的任意嵌套进行建模。但是,Python似乎兼具两者的优点。
工作

Answers:


15

我认为关于对象与功能的讨论是一团糟。如果问题是“ lambda是函数还是对象?” 答案应该

这就是一流函数的意义:它们与任何其他类型都没有区别。Java已经设法设法忽略了Object和基本类型之间的差异(Scala甚至更好),因此lambda是Object的子类还是新的基本类型还是其他对于该语言而言并不重要。重要的是,您可以将lambda放入集合中,将它们传递给调用,调用它们,以及对对象或方法进行任何您想做的事情。

Scala通过使用一个包装器对象来实现此目的,该包装器对象具有一个apply可以称为just 的方法,该方法可以用just来调用()。这非常出色;很多时候,您甚至不需要关心是否有方法或正在调用函数对象的应用。


9

据我了解,更多是关于在主要语言级别上如何考虑 lambda 。如电子邮件所述,

您可能会认为当前的设计与lambda的对象框(SAM类型)紧密相关,因此无论如何都使它们成为有效的对象。但这已从表面区域被仔细隐藏,以使我们将来可以考虑“裸” lambda,或考虑lambda的其他转换上下文,或将lambda更紧密地集成到控制结构中。我们现在没有这样做,甚至没有具体的计划,但是将来有可能做到这一点是设计的关键部分。

我认为这很好地总结了您的问题。如果您声明“ lambdas是对象”,那么它们只是特定类的对象,您就只能这样做了。另一方面,如果声明“ lambdas are functions”,那么从语义上讲,您将拥有更丰富的竞争环境。Java 1.7可能会将它们编译为对象,因此在那时它们实际上是相同的。

但是Java 1.8或1.9可能会带来语言上的更改(例如,统一的结构类型),而不是使函数以更加灵活的方式使用。如果“ lambda是对象”,则这些更改将无法向后兼容,因此您必须完全引入一个新概念,以免破坏人们现有的代码。但是,如果javac只是将lambda悄悄地转换为幕后对象javac,那么只要语义仍然存在,新函数就可以将其转换为所需的内容。


来自代表的C#!=中的lamda。编译器可以选择将它们编译为代理树或表达式树。两者都是确实的对象图,但他们不会被编译到一个 “特殊类”甚至也不是一类特定的继承树
符文FS

如果我理解正确,则将lambda编译为该对象的内部类,并将其与该对象相关联,因此将来如果Java要引入高阶函数(处于相同对象级别的函数),则您无法使用内部类实现,并且会出现不一致情况。我认为Java不会在不久的将来具有高阶函数。
mwolfetech 2011年

@mwolfetech:据我所知,它们已经计划在Java 8中使用防御方法。他们希望添加之类的东西foreachmapfilter到集合。
SOC

@soc好点了,它很难跟上JSR的数量以及它们是否实际上将完成并制作JDK的目标版本。看起来防御者方法可能是同一JSR的一部分。关于此JSR,我发现Brian Goetz的Lambda状态文章很有帮助-解释了SAM类型以及实现Lambda表达式的当前思路。
mwolfetech

“目前的想法”嗯,现在是不是从2010年起就已经过时了?
SOC

5

通常,他只是不想过早对某件事做出承诺。除了他提出的擦除方式,我看不出任何理由,但这确实是一个非常有力的理由。

我不喜欢函数类型-我喜欢函数类型-但是函数类型与Java类型系统的现有方面(擦除)打得很差。擦除的函数类型在两个方面都是最糟糕的。

在Scala的中考虑以下方法Regex

def replaceAllIn (target: CharSequence, replacer: (Match)  String): String
def replaceSomeIn (target: CharSequence, replacer: (Match)  Option[String]): String

如果他们只是这样,那会更简单:

def replace (target: CharSequence, replacer: (Match)  String): String
def replace (target: CharSequence, replacer: (Match)  Option[String]): String

不幸的是,这是不可能的,因为在擦除下这两个功能是相同的。但是,好的,这些函数做了一些不同的事情,因此使用不同的名称可能就足够了。

但是,a Match是非常有用的,但是在大多数情况下,您需要匹配的String或子组的列表。我们想要这样:

def replaceAllIn (target: CharSequence, replacer: (String)  String): String
def replaceAllIn (target: CharSequence, replacer: (Seq[String])  String): String
def replaceAllIn (target: CharSequence, replacer: (Match)  String): String

由于擦除,不可能。我之所以选择这个特定示例是因为我直接参与了该示例,但是我在Stack Overflow上至少看到了六个问题,人们问为什么这个确切的问题导致了重载是非法的。

然后,考虑到Scala的模式匹配和Java的instanceof擦除实际上是无用的。

我认为延迟功能类型直到解决此问题是公平的。毕竟,JVM上有很多语言支持它,而且Java并不是一种迅速发展的语言。


好吧,如果类型擦除是他们唯一的问题,那么他们打算做什么?Java 5已经
禁止

@soc我这么高兴我不是他们的鞋子!但是那是Sun,这是Oracle。Oracle从未在其主要产品的主要版本(甚至次要版本)之间进行重大更改方面具有任何竞争能力。
丹尼尔C.索布拉尔

也许他们应该更改语言的名称并开始开发新的语言,从而降低向后兼容性。这样一来,无需使用一门古老而又行之有效的语言,便可以享受一种新语言的好处。毕竟,这就是Scala和Clojure所做的。
乔治(Giorgio)

@Giorgio那将毫无意义。嗯,有些谁负责今天的Java是人做,但是,正如你所说的,还有替代品。但是负责Java的人必须改进Java本身- 毕竟他们要对此负责。唯一的选择是简单地删除Java,并放弃控制它所带来的所有好处。
Daniel C. Sobral

@Daniel C. Sobral:IMO编程语言有点像一件软件:刚开始时它可以是干净,设计良好的,但是您玩的越多,它就会变得越混乱。因此,我认为冻结Java作为一种语言并将开发重点集中在(1)创建新的库或改进现有的库,(2)改进JVM(如果可能),(3)开发新的语言符合开发人员的利益。 。但是正如您所说,有些人负责Java,并希望继续销售升级产品。因此,他们将对其进行扩展以使其保持“凉爽”。只是我的2美分。
乔治
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.