I believe that 1 and 2 are compiled into the same bytecode (except for the class name that is generated in case 2). If Fooable exists only so that you can implicitly convert A to Fooable (and you will never directly create and use Fooable), then I would go with option 2.
However, if you control A (which means that A is not a java library class that you cannot subclass), I would consider using the attribute instead of implicit conversions to add behavior to A.
UPDATE : I have to revise my answer. I would use option 1 of your code, because option 2, it turns out, uses reflection (scala 2.8.1 on Linux).
I compiled these two versions of the same code, decompiled them in java using jd-gui, and here are the results:
source code with a named class
class NamedClass { def Foo : String = "foo" } object test { implicit def StrToFooable(a: String) = new NamedClass def main(args: Array[String]) { println("bar".Foo) } }
source code with anonymous class
object test { implicit def StrToFooable(a: String) = new { def Foo : String = "foo" } def main(args: Array[String]) { println("bar".Foo) } }
compiled and decompiled in java with java-gui. The "named" version generates the NamedClass.class class, which is decompiled into this java:
public class NamedClass implements ScalaObject { public String Foo() { return "foo"; } }
anonymous generates test class $$ anon $ 1, which decompiles into the following java
public final class test$$anon$1 { public String Foo() { return "foo"; } }
so nearly identical, except for the anonymous one, which is "final" (they apparently want to make sure you don't go out of their way to try and subclasses of the anonymous class ...)
however on the call site I get this java for the "named" version
public void main(String[] args) { Predef..MODULE$.println(StrToFooable("bar").Foo()); }
and this is for anonymous
public void main(String[] args) { Object qual1 = StrToFooable("bar"); Object exceptionResult1 = null; try { exceptionResult1 = reflMethod$Method1(qual1.getClass()).invoke(qual1, new Object[0]); Predef..MODULE$.println((String)exceptionResult1); return; } catch (InvocationTargetException localInvocationTargetException) { throw localInvocationTargetException.getCause(); } }
I googled a bit and found that others reported the same thing, but I did not find a deeper understanding of why this is the case.