Can Scala be seen as an 'Abstraction Inversion'?
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 convin开发者_JS百科ced 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
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:
- There must be a "function" primitive available to JVM.
- 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.
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.
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
I believe not. The way first-class functions are implemented in Scala is just that, an implementation detail.
精彩评论