I believe 1 and 2 get compiled to the same bytecode (except for the class name that gets generated in case 2).
If Fooable exists only for you to be able to convert implicitly A to Fooable (and you're never going to directly create and use a Fooable), then I would go with option 2.
However, if you control A (meaning A is not a java library class that you can't subclass) I would consider using a trait instead of implicit conversions to add behaviour to A.
UPDATE:
I have to reconsider my answer. I would use variant 1 of your code, because variant 2 turns out to be using reflection (scala 2.8.1 on Linux).
I compiled these two versions of the same code, decompiled them to java with jd-gui and here are the results:
source code with 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 to java with java-gui. The "named" version generates a NamedClass.class that gets decompiled to this java:
public class NamedClass
implements ScalaObject
{
public String Foo()
{
return "foo";
}
}
the anonymous generates a test$$anon$1 class that gets decompiled to the following java
public final class test$$anon$1
{
public String Foo()
{
return "foo";
}
}
so almost identical, except for the anonymous being "final" (they apparently want to make extra sure you won't get out of your way to try and subclass an anonymous class...)
however at the call site I get this java for the "named" version
public void main(String[] args)
{
Predef..MODULE$.println(StrToFooable("bar").Foo());
}
and this for the 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 little and found that others have reported the same thing but I haven't found any more insight as to why this is the case.