Scala 可以被视为“抽象反转”吗?

发布于 2024-10-03 06:17:51 字数 954 浏览 3 评论 0原文

您好,

这是一个具有争议性的问题,旨在就开发人员社区如何看待抽象反转展开辩论。我真的很想知道你的想法。

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

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

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

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

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


顺便说一句,我不相信维基百科文章的客观性。例如,当谈到微内核中可能的抽象反转时,文章中说“A body of ideas indicates the microkernel design to be an abstraction inversion”,但 OOP 中的函数类型没有这样的声明

Greetings,

It's a provocative question, aiming to open debate about how abstraction inversion are seen among developer community. I'm really curious to know what you think.

First, here is a quote from the abstraction inversion exemples given by Wikipedia:
http://en.wikipedia.org/wiki/Abstraction_inversion

Creating an object to represent a function is cumbersome in object-oriented languages such as Java and C++, in which functions are not first-class objects. In C++ it is possible to make an object 'callable' by overloading the () operator, but it is still often necessary to implement a new class, such as the Functors in the STL.

For me functions are first-class citizen in Scala, but when we use Scala to generate Java bytecode, Scala create specific class 'on top' of Java to make functional programming possible... can we see this as an abstraction inversion ?

Same can apply to Clojure or any functionnal language for the JVM... or even Apache Collections, for exemple this:

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


BTW, I'm not convinced about the wikipedia article objectivity. For example when speaking about possible abstraction inversion in micro-kernel the article say 'A body of opinion holds the microkernel design to be an abstraction inversion' but no such statement for functional type in OOP

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

私藏温柔 2024-10-10 06:17:51

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

例如,从讨论页面来看,有一个更有趣的例子。假设 CPU 有 tan 数学函数,但没有 sincos,并且编程语言实现了 sincos 表示为 tan,但没有公开 tan 本身。使用该语言的程序员将被迫用 sincos 来实现 tan,而它们本身是用 sin 来实现的>tan,因此表征抽象反转。

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

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

  1. 必须有一个可供 JVM 使用的“函数”原语。
  2. 这样的原语肯定提供了 Scala 正在做的事情的替代方案。

到底什么是函数?函数原语会是什么样子?在本文中,“功能”意味着能够被执行的数据。有人可能会说,所有汇编代码实际上都是能够执行的数据——只是它不可移植,而且不是字节码,因此不符合设计原则。

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

因此,我认为可以证明 1 是正确的。让我们继续下一步。

如果 Java 确实提供了“方法”数据类型,那么 Scala 函数将不再是类的实例吗?不,他们不会。 Scala 的基本设计方面之一是正在运行的程序的每个元素都是一个对象。 Java 已经拥有的“原语”被呈现为好像它们是具有方法的普通对象,并且如果存在“方法”原语,那么它也会存在。

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

The wiki article is really weak (does it represent an abstraction inversion itself? :), and the very concept is a bit dubious. But the fundamental gist of it seems to be that some basic element is hidden by the abstraction, forcing users of that abstraction to re-implement it.

For instance, from the talk page, comes a much more interesting example. Suppose a CPU had a tan math function, but no sin or cos, and a programming language implemented sin and cos in terms of tan, but did not expose tan itself. A programmer using that language would be forced to implement tan in terms of sin and cos, which, themselves, are implemented in terms of tan, therefore characterizing abstraction inversion.

So, back to Scala. Naturally, a programmer using functions in Scala is not incurring in abstraction inversion, because he is not being forced to re-implement a functionality available as a primitive to Scala.

On the other hand, one might claim that Scala's implementation of functions as class instances is an instance of abstraction inversion. For that to be true, however, two things must also hold true:

  1. There must be a "function" primitive available to JVM.
  2. Such a primitive must have offered an alternative to what Scala is doing.

What, exactly, is a function? What would a function primitive look like? In this context, "function" means data that is capable of being executed. One might say that all assembler code, is, in fact, data that is capable of being executed -- only it is not portable, and, futhermore, not bytecode, therefore failing the design principles.

On the other hand, all methods in Java are referenced by an identifier, through which Java locates the code to be executed for a given object's class hierarchy. This identifier is not exposed, though it can be used indirectly through reflection. If it were exposed, and some functionality offered to say "call this code", then a function could arguably be constructed around that.

So, I think a case could be made for 1 to be true. Let's proceed to the next.

If Java did offer a "method" data type, would Scala functions cease to be instances of a class? No, they would not. One of the fundamental design aspects of Scala is that every element of a running program is an object. The "primitives" that Java already have are presented as if they were normal objects with methods, and if there was a "method" primitive, so would it.

One possible consequence of method primitives would be to elevate methods to first class citizens, but functions, themselves, would hardly change.

一笔一画续写前缘 2024-10-10 06:17:51

通过对象实现函数并不仅仅是因为这在 JVM 上是可能的,它直接切合了 Scala 的基本理念。

一切都是一个对象:函数、参与者、数字文字等。任何对象也可以适用(通过定义 apply() 方法),而无需实际成为对象FunctionN 的子类。

这种二元性是许多标准库 API 设计的基础,它允许将 Map 等视为函数(将键映射到值)和对象(键/值对的集合)。

Scala 是真正的对象/函数混合体,两种范式都不占主导地位。

Implementing a function via an object is not done simply because that's what's possible on the JVM, it cuts right to the underlying philosophy of Scala.

everything is an object: functions, actors, number literals, etc. It's also possible for any object to be appliable (by defining the apply() method) without actually being a subclass of FunctionN.

This duality is fundamental in the design of many standard library APIs, it allows for e.g. Maps to be viewed as both a function (mapping keys to values) and as a object (a collection of key/value pairs).

Scala is a true object/functional hybrid, with neither paradigm being dominant.

就像说晚安 2024-10-10 06:17:51

不,它不能被视为抽象反转。原因很简单:在 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++ 中的 Functor 那样的情况。例如,您可以将 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

No, it can't be seen as abstraction inversion. The reason is simple: In Scala you have a choice which abstraction level you prefer. Most of the time it's more convenient to write

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

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

but it is no problem to do it the "long" way:

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

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

As FunctionN are traits, it's possible to use mix-in inheritance, which allows you to avoid situations like the one for Functors in C++. E.g. you could "retrofit" a Java-Map as a function:

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
墨小墨 2024-10-10 06:17:51

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

I believe not. The way first-class functions are implemented in Scala is just that, an implementation detail.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文