开发者

Implicit def of Any to Function adds apply method to classes

开发者 https://www.devze.com 2023-02-05 23:14 出处:网络
Take a look at the following and see if you can make any sense of it: Welcome to Scala version 2.8.1.final (Java HotSpot(TM) Client VM, Java 1.6.0_17).

Take a look at the following and see if you can make any sense of it:

Welcome to Scala version 2.8.1.final (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class A
defined class A

scala> val a = new A
a: A = A@1643e4b

scala> a.apply("foo")
<console>:8: error: value apply is not a member of A
       a.apply("foo")
         ^

It looks completely normal up to here. But then we add an implicit conversion.

scala> implicit def anyToFunc(any: Any) = { x: String => "bar" }
anyToFunc: (any: Any)(String) => java.lang.String

scala> a.apply("foo")
res1: java.lang.String = bar

And suddenly A has a apply method that accepts an argument of same type that the function that the 开发者_如何学Pythonimplicit returns takes!

Let's inspect it a little more:

scala> class B { override def toString = "an instance of class B" }
defined class B

scala> implicit def anyToFunc(any: Any) = { x: String =>
     | println("any is " + any.toString)
     | println("x is " + x)
     | "bar" }
anyToFunc: (any: Any)(String) => java.lang.String

scala> val b = new B
b: B = an instance of class B

scala> b.apply("test")
any is an instance of class B
x is test
res8: java.lang.String = bar

Is this a "hidden feature"? If so, what are the uses for it?


You're calling apply on an object of type A. A does not have an apply method. However A is implicitly convertible to Function[String, String], which does have an apply method. Thus the implicit conversion is applied and apply is called on the converted object.

There's nothing magic or hidden about this feature. If an object doesn't have the method you're calling on it, but is implicitly convertible to one that does, it will be converted. It's exactly what implicit conversions are for.


any function created in scala is converted to a class with apply method. Then the shorthand for calling apply is omitting it.

class A{
    val a = (x:String) => x * 2
}
compile this and see, that there are two files created, A.class and A$$anonfun$1.class. Inspect the class file with javap and you'll see this
Compiled from "Fun.scala"
public final class A$$anonfun$1 extends scala.runtime.AbstractFunction1 implements java.io.Serializable{
    public static final long serialVersionUID;
    public static {};
    public final java.lang.String apply(java.lang.String);
    public final java.lang.Object apply(java.lang.Object);
    public A$$anonfun$1(A);
}
The important line is public final java.lang.String apply(java.lang.String);. This is called either by a("string") or a.apply("string").

Yes, you can convert anything into function with implicit defs, but it doesn't make much sense. It is usually used in different cases: pimp my library


It isn't so much a hidden feature as the expected behaviour of implicit definitions and the apply method. Critically, the apply method is a special method that gets invoked when you pass arguments directly to an object. So when, in your example, you do the following:

b.apply("Test")

This would be equivalent to b("test"). Function defines apply so we can do nice things like:

val addOne = (b : Int) => b + 1
addOne(10)

So, when you try to call apply on an instance of B, the compiler first looks whether B has a method apply, then looks whether a superclass of B has a method apply, then looks for an implicit to something that has a method apply. This is the purpose of implicit definitions. Since Function1 has an apply method, the implicit conversion is called and the function's apply method is also called.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号