Java 7当前Lambda提案的复杂性? (2010年8月)

时间:2010-08-04 18:01:22

标签: java extension-methods language-design closures java-7

有些人说每种编程语言都有其“复杂性预算”,可用于实现其目的。但是,如果复杂性预算耗尽,每一次微小变化都会变得越来越复杂,难以以向后兼容的方式实施。

从2010年8月开始阅读current provisional syntax for Lambda(≙Lambda表达式,异常透明度,防御方法和方法参考)后,我想知道在考虑此类更改时,Oracle的人员是否完全忽略了Java的复杂性预算。

这些是我正在考虑的问题 - 其中一些更多是关于语言设计的:

  • 拟议的新增内容是否与其他语言选择的方法相当?
  • 通常是否可以将这些添加内容添加到语言中,以保护开发人员免受实现的复杂性影响?
  • 这些新增内容是否已经达到Java-as-a-language演变的标志,或者在更改具有巨大历史的语言时是否会出现这种情况?
  • 在语言发展的这个阶段,其他语言采取了完全不同的方法吗?

谢谢!

5 个答案:

答案 0 :(得分:3)

模拟一些范围消歧构造,几乎所有这些方法都遵循lambda抽象的实际定义:

λx.E

按顺序回答您的问题:

我认为Java社区的提案没有任何特别的东西比其他任何东西更好或更差。正如我所说,它来自数学定义,因此所有忠实的实现都将具有几乎完全相同的形式。

强制要求语言的匿名一流函数往往最终成为一些程序员喜欢和经常使用的功能,而其他程序员则完全忽略 - 因此,给它一些不会混淆的语法可能是一个明智的选择。那些选择忽略这种特定语言特征的人。我认为隐藏实现的复杂性和细节是他们尝试使用与Java完美融合的语法,但对Java程序员没有真正的内涵。

他们可能希望使用一些不会使现有定义复杂化的语法,因此它们在可以选择用作运算符的符号中受到轻微约束。当然,Java坚持保持向后兼容会略微限制语言的演变,但我认为这不一定是件坏事。 PHP方法处于频谱的另一端(即“嘿伙计们,每当有新的点发布时让我们打破一切!”)。我不认为Java的演变本身是有限的,除了它的设计的一些基本原则 - 例如遵守OOP原则,基于VM。

我认为从Java的角度对语言演变做出强有力的陈述是非常困难的。它处于一个相当独特的位置。首先,它非常非常受欢迎,但它相对较老。在他们决定开始设计一种名为“C#”的语言之前,微软拥有至少10年的Java遗产的好处。 C编程语言基本上停止了演变。 C ++几乎没有发现任何主流接受的重大变化。 Java通过一个缓慢但一致的过程继续发展 - 如果有什么我觉得它比任何其他具有类似巨大安装代码库的语言一样能够继续发展。

答案 1 :(得分:3)

我没有关注Java 7 lambda的过程和演变 建议,我甚至不确定最新的提案措辞是什么。 将此视为咆哮/意见而不是真实陈述。也, 我已经很久没用过Java了,所以语法可能生锈了 在地方不正确。

首先,Java语言的lambda是什么?句法糖。而 一般来说,lambdas使代码能够创建小的函数对象 在某种程度上,在Java中已经预设了这种支持 语言通过使用内部类。

那么lambdas的语法有多好?它在哪里表现优异 以前的语言结构?哪里可能更好?

对于初学者,我不喜欢有两种可用的语法 对于lambda函数(但这是在C#中,所以我猜我的 意见并不普遍。我想如果我们想要糖衣,那么 #(int x)(x*x)#(int x){ return x*x; }更甜,即使是return 双语法不添加任何其他内容。我本来希望的 第二种语法,在编写;@Shared的额外成本时更通用 短版本中的!

为了真正有用,lambdas可以从范围中获取变量 它们的定义位置和闭包。与...保持一致 内部类,lambdas仅限于捕获' 最终的'变量。与以前的功能一致 语言是一个很好的功能,但对于甜蜜,它会很好 能够捕获可以重新分配的变量。为了这个目的, 他们正在考虑上下文中存在的变量 使用#(int x)(x*x)!(5)注释将被 by-reference 捕获,允许 分配。对我而言,lambda如何使用变量似乎很奇怪 是在变量声明的地方确定而不是 lambda的定义。单个变量可以用于更多 而不是一个lambda,这会在所有这些中强制出同样的行为。

Lambdas尝试模拟实际的功能对象,但提案确实如此 不完全在那里:保持解析器简单,从现在开始 标识符表示已保留的对象或方法 一致并调用lambda需要在lambda之后使用25 名称:!将返回.execute。这带来了一种新的语法 用于与其他语言不同的lambda,其中 Lambda<Result,Args...>代表以某种方式作为虚拟通用Lambda的synonim 接口Lambda<Return>但是,为什么不把它完成呢?

可以创建新的通用(虚拟)接口Lambda<Return,Arg1>。它会 必须是虚拟的,因为接口不是真正的接口,而是a 这样的家庭:Lambda<Return,Arg1,Arg2>operator()! ......他们可以定义一次执行 方法,我想像C ++ interface Lambda<R> { R exec(); } interface Lambda<R,A> { R exec( A a ); } ,但如果是这样的话 一个负担然后任何其他名称都没关系,接受identifier!(args)作为一个 方法执行的快捷方式:

identifier.exec( args )

然后编译器只需将 #( int x )(x *x) // translated to new Lambda<int,int>{ int exec( int x ) { return x*x; } } 翻译成 @Shared,这很简单。翻译 lambda语法需要编译器识别正确的 接口正在实施,可以匹配为:

 new Lambda<int,int>{ int value = context_value;
     int exec( int x ) { return x * context_value; }
 };

这也允许用户定义可以使用的内部类 作为lambdas,在更复杂的情况下。例如,如果是lambda 捕获注释为 Lambda<int,int> array[10] = new Lambda<int,int>[10](); for (int i = 0; i < 10; ++i ) { array[i] = new Lambda<int,int>{ final int multiplier = i; int exec( int x ) { return x * multiplier; } }; } // note this is disallowed in the current proposal, as `i` is // not effectively final and as such cannot be 'captured'. Also // if `i` was marked @Shared, then all the lambdas would share // the same `i` as the loop and thus would produce the same // result: multiply by 10 --probably quite unexpectedly. // // I am aware that this can be rewritten as: // for (int ii = 0; ii < 10; ++ii ) { final int i = ii; ... // // but that is not simplifying the system, just pushing the // complexity outside of the lambda. 的变量所需的函数 只读方式,或维护捕获对象的状态 捕获的地方,Lambda的手动实现 可用的:

#(int x){ return x*x; }

以类似于当前Inner类定义的方式, 因此对于当前的Java用户来说是很自然的。这可以用, 例如,在循环中生成乘数lambdas:

{{1}}

这将允许使用lambda和接受lambdas的方法 使用新的简单语法:{{1}}或更多 针对糖衣的特定情况的复杂手动方法 干扰了预期的语义。

总的来说,我相信lambda提案可以改进 不同的方向,它添加语法糖的方式是一个 泄漏抽象(你在外部处理问题 特别是对于lambda而言,并没有提供较低的水平 接口使得用户代码在不使用的用例中不易读取 完全适合简单的用例。 :

答案 2 :(得分:1)

与其他语言的lambda表达相比,它并没有那么复杂。

考虑...

int square(x) {
    return x*x;
}

爪哇:

#(x){x*x}

的Python:

lambda x:x*x

C#:

x => x*x

我认为C#方法稍微直观一些。我个人更喜欢......

x#x*x

答案 3 :(得分:1)

也许这不是你问题的真正答案,但这可能与目标-c(当然,与Java相比具有非常狭窄的用户群)的方式相当于块(examples )。虽然语法不适合语言的其余部分(恕我直言),但它是一个有用的补充,并且语言特性方面增加的复杂性得到奖励,例如并发编程的复杂性较低(简单的事情,如数组上的并发迭代或复杂的技术,如Grand Central Dispatch)。

此外,许多常见任务在使用块时更简单,例如使一个对象成为同一个类的多个实例的委托(或者在Java术语 - “监听器”中)。在Java中,匿名类已经可以用于该原因,因此程序员知道这个概念,并且可以使用lambda表达式来节省几行源代码。

在objective-c(或Cocoa / Cocoa Touch框架)中,新功能现在通常只能使用块来访问,而且似乎程序员正在快速采用它(因为它们必须放弃与旧操作系统版本的向后兼容性) )。

答案 4 :(得分:1)

这真的非常接近新一代C ++(C ++ 0x)中提出的Lambda函数 所以我认为,甲骨文家伙在烹饪之前已经考虑过其他实现。

http://en.wikipedia.org/wiki/C%2B%2B0x

[](int x, int y) { return x + y; }