斯卡拉可以被视为“抽象倒置”吗?

时间:2010-11-16 13:49:09

标签: oop scala programming-languages functional-programming abstraction

问候,

这是一个具有挑衅性的问题,旨在就如何在开发者社区中看到抽象反转进行辩论。我真的很想知道你的想法。

首先,这里引用维基百科给出的抽象反转例子: http://en.wikipedia.org/wiki/Abstraction_inversion

  

在面向对象的语言(如Java和C ++)中创建表示函数的对象是很麻烦的,其中函数不是第一类对象。在C ++中,可以通过重载()运算符来使对象“可调用”,但实际上仍然需要实现一个新类,例如STL中的Functors。

对于我来说,函数是Scala中的一等公民,但是当我们使用Scala生成Java字节码时,Scala会在Java上创建特定的类'以使函数式编程成为可能... 我们可以将其视为抽象反转?

同样适用于Clojure或JVM的任何功能语言......甚至Apache Collections,例如:

http://commons.apache.org/collections/apidocs/org/apache/commons/collections/Closure.html


顺便说一下,我不相信维基百科文章的客观性。例如,当谈到微内核中可能的抽象反转时,文章说'一个观点主体认为微内核设计是一个抽象反转',但在OOP中没有这样的功能类型声明

4 个答案:

答案 0 :(得分:9)

维基文章真的很弱(它代表了一个抽象反转本身吗?:),这个概念有点可疑。但它的基本要点似乎是抽象隐藏了一些基本元素,迫使该抽象的用户重新实现它。

例如,从谈话页面来看,这是一个更有趣的例子。假设CPU具有tan数学函数,但没有sincos,并且sincos的编程语言实现tan },但没有暴露tan本身。使用该语言的程序员将被迫以tansin来实现costan和{{1}}本身是以{{1}}实现的,因此表征抽象反转。

所以,回到Scala。当然,在Scala中使用函数的程序员不会引发抽象反转,因为他没有被迫重新实现作为Scala的原语可用的功能。

另一方面,有人可能会声称Scala将函数实现为类实例是抽象反转的一个实例。然而,要做到这一点,有两件事情也必须成立:

  1. JVM必须有一个“函数”原语。
  2. 这样的原语必须提供替代Scala正在做的事情。
  3. 究竟什么是功能?函数原语会是什么样的?在此上下文中,“功能”表示能够执行的数据。有人可能会说,所有汇编程序代码实际上都是能够执行的数据 - 只是它不可移植,而且不再是字节码,因此不符合设计原则。

    另一方面,Java中的所有方法都由标识符引用,Java通过该标识符定位要为给定对象的类层次结构执行的代码。虽然可以通过反射间接使用,但不会公开此标识符。如果它被公开,并且提供了一些功能来说“调用这段代码”,那么可以说可以构建一个函数。

    所以,我认为可以为1做一个案例。让我们继续下一步。

    如果Java 提供“方法”数据类型,Scala函数是否会停止成为类的实例?不,他们不会。 Scala的一个基本设计方面是正在运行的程序的每个元素都是一个对象。 Java已经具有的“原语”就好像它们是带有方法的普通对象一样,如果有一个“方法”原语,那么它就会出现。

    方法原语的一个可能后果是将方法提升为一等公民,但功能本身几乎不会改变。

答案 1 :(得分:5)

通过对象实现一个函数并不是因为这就是JVM上的可能,它切入了Scala的基本哲学。

一切是一个对象:函数,参与者,数字文字等。任何对象都可以应用(通过定义apply()方法),而不是实际的子类功能N

这种二元性在许多标准库API的设计中是基础,它允许例如映射既可以作为函数(映射键到值),也可以作为对象(键/值对的集合)。

Scala是一个真正的对象/功能混合体,两种范式都没有占主导地位。

答案 2 :(得分:2)

不,它不能被视为抽象反转。原因很简单:在Scala中,您有一个选择您更喜欢的抽象级别。大多数时候写

更方便
val f = 2 * (_:Int)
//--> f: (Int) => Int = 

f(21)
//--> res5: Int = 42

但以“长”的方式做到这一点没有问题:

val f = new Function1[Int,Int] { def apply(v:Int) = 2*v }
//--> f: java.lang.Object with (Int) => Int = 

f(21)
//--> res6: Int = 42

由于FunctionN是特征,因此可以使用混合继承,这可以避免像C ++中的Functors那样的情况。例如。你可以“改进”Java-Map作为一个函数:

class JavaMap[K,V] extends java.util.HashMap[K,V] with Function1[K,V] {
    def apply(k:K) = get(k)
}

val m = new JavaMap[Int, String]
m.put(5,"five")
m(5)
//--> res8: String = five

答案 3 :(得分:1)

我不相信。在Scala中实现第一类函数的方式就是实现细节。