为什么不能优化这种隐式转换的情况?

时间:2010-10-06 02:25:34

标签: scala implicit implicit-conversion structural-typing

为什么Scala无法优化以下内容:

一个。

implicit def whatever[A](a: A) = new { ... }

为:

class some$generated$name(a: A) {
  ...
}
implicit def whatever[A](a: A) = new some$generated$name(a)

为什么在这种情况下必须使用结构类型?我希望Scala编译器能够执行这种优化,因为写入样式 b 太难看了(因为,1。逻辑的局部性丢失了,2。你必须不必要地为这些额外的显式类创建名称) , a 的效果远远低于 b

2 个答案:

答案 0 :(得分:3)

我认为可以,这可以通过编译器插件完成,看起来像

@extension implicit def whatever[A](a: A) = new { ... }

但我不知道是否有人写过这样的插件......

更新:

如果我编译这个文件:

object Main {
  implicit def option[A](a: A) = new { def id = a }  

  def foo(x: String) = x.id
}

并反编译foo的代码,仍然涉及反射:

F:\MyProgramming\raw>javap -c Main$
Compiled from "Main.scala"
public final class Main$ extends java.lang.Object implements scala.ScalaObject{
public static final Main$ MODULE$;

public static {};
  Code:
   0:   new     #9; //class Main$
   3:   invokespecial   #12; //Method "<init>":()V
   6:   return

public static java.lang.reflect.Method reflMethod$Method1(java.lang.Class);
  Code:
   0:   getstatic       #20; //Field reflPoly$Cache1:Ljava/lang/ref/SoftReference;
   3:   invokevirtual   #27; //Method java/lang/ref/SoftReference.get:()Ljava/lang/Object;
   6:   checkcast       #29; //class scala/runtime/MethodCache
   9:   ifnonnull       29
   12:  new     #23; //class java/lang/ref/SoftReference
   15:  dup
   16:  new     #31; //class scala/runtime/EmptyMethodCache
   19:  dup
   20:  invokespecial   #32; //Method scala/runtime/EmptyMethodCache."<init>":()V
   23:  invokespecial   #35; //Method java/lang/ref/SoftReference."<init>":(Ljava/lang/Object;)V
   26:  putstatic       #20; //Field reflPoly$Cache1:Ljava/lang/ref/SoftReference;
   29:  getstatic       #20; //Field reflPoly$Cache1:Ljava/lang/ref/SoftReference;
   32:  invokevirtual   #27; //Method java/lang/ref/SoftReference.get:()Ljava/lang/Object;
   35:  checkcast       #29; //class scala/runtime/MethodCache
   38:  aload_0
   39:  invokevirtual   #38; //Method scala/runtime/MethodCache.find:(Ljava/lang/Class;)Ljava/lang/r
eflect/Method;
   42:  astore_1
   43:  aload_1
   44:  ifnull  49
   47:  aload_1
   48:  areturn
   49:  aload_0
   50:  ldc     #40; //String id
   52:  getstatic       #42; //Field reflParams$Cache1:[Ljava/lang/Class;
   55:  invokevirtual   #48; //Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class
;)Ljava/lang/reflect/Method;
   58:  astore_1
   59:  new     #23; //class java/lang/ref/SoftReference
   62:  dup
   63:  getstatic       #20; //Field reflPoly$Cache1:Ljava/lang/ref/SoftReference;
   66:  invokevirtual   #27; //Method java/lang/ref/SoftReference.get:()Ljava/lang/Object;
   69:  checkcast       #29; //class scala/runtime/MethodCache
   72:  aload_0
   73:  aload_1
   74:  invokevirtual   #52; //Method scala/runtime/MethodCache.add:(Ljava/lang/Class;Ljava/lang/ref
lect/Method;)Lscala/runtime/MethodCache;
   77:  invokespecial   #35; //Method java/lang/ref/SoftReference."<init>":(Ljava/lang/Object;)V
   80:  putstatic       #20; //Field reflPoly$Cache1:Ljava/lang/ref/SoftReference;
   83:  aload_1
   84:  areturn

public java.lang.Object option(java.lang.Object);
  Code:
   0:   new     #59; //class Main$$anon$1
   3:   dup
   4:   aload_1
   5:   invokespecial   #60; //Method Main$$anon$1."<init>":(Ljava/lang/Object;)V
   8:   areturn

public java.lang.String foo(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   invokevirtual   #69; //Method option:(Ljava/lang/Object;)Ljava/lang/Object;
   5:   astore_2
   6:   aconst_null
   7:   astore_3
   8:   aload_2
   9:   invokevirtual   #75; //Method java/lang/Object.getClass:()Ljava/lang/Class;
   12:  invokestatic    #77; //Method reflMethod$Method1:(Ljava/lang/Class;)Ljava/lang/reflect/Metho
d;
   15:  aload_2
   16:  iconst_0
   17:  anewarray       #71; //class java/lang/Object
   20:  invokevirtual   #83; //Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang
/Object;)Ljava/lang/Object;
   23:  astore_3
   24:  aload_3
   25:  checkcast       #85; //class java/lang/String
   28:  checkcast       #85; //class java/lang/String
   31:  areturn
   32:  astore  4
   34:  aload   4
   36:  invokevirtual   #91; //Method java/lang/reflect/InvocationTargetException.getCause:()Ljava/l
ang/Throwable;
   39:  athrow
  Exception table:
   from   to  target type
     8    24    32   Class java/lang/reflect/InvocationTargetException


}

比较
object Main2 {
  class Whatever[A](a: A) { def id = a }

  implicit def option[A](a: A) = new Whatever(a)

  def foo(x: String) = x.id
}

反编译:

F:\MyProgramming\raw>javap -c Main2$
Compiled from "Main2.scala"
public final class Main2$ extends java.lang.Object implements scala.ScalaObject{
public static final Main2$ MODULE$;

public static {};
  Code:
   0:   new     #9; //class Main2$
   3:   invokespecial   #12; //Method "<init>":()V
   6:   return

public Main2$Whatever option(java.lang.Object);
  Code:
   0:   new     #16; //class Main2$Whatever
   3:   dup
   4:   aload_1
   5:   invokespecial   #20; //Method Main2$Whatever."<init>":(Ljava/lang/Object;)V
   8:   areturn

public java.lang.String foo(java.lang.String);
  Code:
   0:   aload_0
   1:   aload_1
   2:   invokevirtual   #30; //Method option:(Ljava/lang/Object;)LMain2$Whatever;
   5:   invokevirtual   #34; //Method Main2$Whatever.id:()Ljava/lang/Object;
   8:   checkcast       #36; //class java/lang/String
   11:  areturn

}

F:\MyProgramming\raw>javap -c Main2$Whatever
Compiled from "Main2.scala"
public class Main2$Whatever extends java.lang.Object implements scala.ScalaObject{
public java.lang.Object id();
  Code:
   0:   aload_0
   1:   getfield        #14; //Field a:Ljava/lang/Object;
   4:   areturn

public Main2$Whatever(java.lang.Object);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #14; //Field a:Ljava/lang/Object;
   5:   aload_0
   6:   invokespecial   #22; //Method java/lang/Object."<init>":()V
   9:   return

}

答案 1 :(得分:2)

我也读过这个,并且经常想问同样的问题。但在2.8,我正在尝试:

object Main {
  implicit def whatever[A](a: A) = new { def foo = "bar" }  
}

当我javap它时:

public final class Main$$anon$1 extends java.lang.Object{
  public java.lang.String foo();
  public Main$$anon$1();
}

看起来好消息,不是吗?

更新您可以使用此trac item

跟踪此优化