Scala : get mixin interfaces at runtime - scala

I need to get all the interfaces at runtime from a given Class (all loaded in a ClassLoader).
For instance, if a class has been declared this way :
trait B
trait C
trait D
class A extends B with C with D
I want to get this information at runtime : A depends on B and C and D.
The java getInterfaces() (or the interfaces() from the clapper library) methods gives only the first dependency, namely: A depends on B.
Is there a way to achieve that ?
I guess by reflection but I don't know how ?

The solution I found with reflection :
import scala.reflect.runtime.{universe => ru}
val mirror = ru.rootMirror
val t = m.staticClass(classString).typeSignature
t.baseClasses

This question gives the answer:
import scala.reflect.runtime.universe._
trait B
trait C
class A extends B with C
val tpe = typeOf[A]
tpe.baseClasses foreach {s => println(s.fullName)}
// A, C, B, java.lang.Object, scala.Any
It works in the REPL, but when I put the code into a Scala script file and executed it, it didn't any longer:
typeOf[A]
// Compiler error: No TypeTag available for this.A
Using weakTypeTag instead didn't help either
weakTypeTag[A]
// Runtime error: scala.reflect.internal.FatalError:
// ThisType(free type $anon) for sym which is not a class
I got the same behaviour with Scala 2.10.0, 2.10.1 and 2.11.0-M2.

Related

Shapeless lenses in idea

I try to use shapless lenses of version 2.0.0 for scala 2.10.3
I have the code similar to this one:
import shapeless._
case class A(map: Map[String, String])
case class B(a: A)
val mapLens = lens[B] >> 'a >> 'map
the infered type in idea of mapLens is
AnyRef with Lens[B, Nothing] {val gen: LabelledGeneric.Aux[Nothing, ::[record.FieldType[Witness.Lt[Symbol]#T, Nothing], Nothing]]}
so if I want to change value of B instance
mapLens.set(b)(b.a.map + ("foo" -> "bar"))
I get a type mismatch error. How to fix this?
P.S. Here there is an example of using shapeless lenses. How does this lens[Person].address.street works? I mean how does compiler allow us to call methods of case class on instance of lense class? Because in LenseExamples object the >> operator is used
edit
Have tried in REPL and it works. Idea says that it
could not find implicit value for evidence parameter of type shapeless.LabelledGeneric[B]{type Repr = Out0}
The same complain emits gradle
Idea is wrong. You should report a bug against the Scala plugin.

Is "A with B" a type?

In Scala we use mix-in like this:
class C extends A with B
I understand this declaration as C is a subclass of A with B. Is this true? Or C is just subclass of both A and B(I don't think it's possible on JVM which doesn't support multi-inheritance)?
If A with B is a type, why doesn't this line work?
classOf[A with B]
Another reason why I consider A with B a type is the fact that it can be used in pattern match:
val c = new C
val u = c match { case a: A with B => 1 } // 1
Scala supports multiple inheritance via traits. Any class can extend 0 or 1 class, but can also "mix in" any number of traits. (There is a bit of compiler magic that rearranges things behind the scenes to conform to the JVM's limitations) The syntax is along the lines of
class MyClass extends [ClassOrTrait] with [Trait] with [AnotherTrait] with ...
So your class C definition is more like
class ((C extends A) with B) than like class (C extends (A with B))
A with B is a type, and can be used as a type alias, but the classOf method wants a class:
scala> type AB = A with B
defined type alias AB
scala> classOf[AB]
<console>:11: error: class type required but A with B found
classOf[AB]
^
vs
scala> class AB extends A with B
defined class AB
scala> classOf[AB]
res12: Class[AB] = class AB
I agree with #Dylan. A with B is only a type definition. However for it to work with classOf[T] , it needs to have a Java class or interface generated by Scala.
scala> trait A
defined trait A
scala> trait B
defined trait B
scala> trait AB extends A with B
defined trait AB
scala> class C extends A with B
defined class C
scala> type TypeAB = A with B
defined type alias TypeAB
scala> println(classOf[A])
interface $line3.$read$$iw$$iw$A
scala> println(classOf[B])
interface $line4.$read$$iw$$iw$B
scala> println(classOf[AB] )
interface $line5.$read$$iw$$iw$AB
scala> println(classOf[C])
class $line6.$read$$iw$$iw$C
scala> println(TypeAB)
<console>:8: error: not found: value TypeAB
println(TypeAB)
^
scala> classOf[TypeAB]
<console>:11: error: class type required but A with B found
classOf[TypeAB]
Also it is interesting that Scala does manage to match the with in case constructs.

Why are traits instantiable?

As far as I've learned, traits in Scala are similar to interfaces in Java except methods are allowed to have an implementation. Also, in contrast to Scala classes, you can't pass them arguments for construction.
So far, so good. But why am I allowed to instantiate them? Really, I don't see a good reason to allow this.
You don't really instantiate them. As you drew a parallel with Java, let's go further into it. You are able in Java to build a Anonymous class out of an abstract class or of an Interface. It is almost the same in Scala:
scala> trait A
defined trait A
scala> new A {}
res0: A = $anon$1#5736ab79
Note that the curly braces are mandatory when you create an object from a trait. For example, yon cannot do:
scala> new A
<console>:9: error: trait A is abstract; cannot be instantiated
new A
^
While it would works perfectly for a class:
scala> class B
defined class B
scala> new B
res2: B = B#213526b0
Of course if some elements in your trait are not implemented, you need to implement them when you create the object:
scala> trait C {def foo: Int}
defined trait C
scala> new C {}
<console>:9: error: object creation impossible, since method foo in trait C of type => Int is not defined
new C {}
^
scala> new C {def foo = 42}
res4: C = $anon$1#744957c7

Type from Scala reflection

Suppose that I have:
trait A
class B extends A
compiled into class files.
Later I load those using reflection:
val a = Class forName "A"
val b = Class forName "B"
Could anyone tell me how to check whether b is the subtype of a?
Use the isAssignableFrom method in Class:
a isAssignableFrom b
This returns true if b is a subclass/subinterface of a or b == a.
You can just call the getInterfaces method on b and iterate through the array to see if any of them equals a.

Scala semantics of equals/hashCode for case classes with traits

I am a newcomer to Scala. In 2.7.7, the following code
abstract class C
case class CC() extends C
trait T
val c1 = CC()
val c2 = new CC() with T
println(c1.hashCode == c2.hashCode,c1 equals c2)
prints
(false,true)
whereas I would have expected
(false,false)
What am I missing? Thanks in advance.
Case class equality (particularly in Scala 2.8) equality and hash codes are based upon tuple and/or product equality, and do not currently take the class into account. There was a recent discussion on this matter on the scala-debate mailing list here: http://old.nabble.com/Possible-Collision-Issue-with-Product.hashCode-td27026790.html
For what it's worth, here's what it currently looks like in 2.8:
Welcome to Scala version 2.8.0.Beta1-RC6 (Java HotSpot(TM) Client VM, Java 1.6.0_16).
Type in expressions to have them evaluated.
Type :help for more information.
scala> abstract class C
defined class C
scala> case class CC() extends C
defined class CC
scala> trait T
defined trait T
scala> val c1 = CC()
c1: CC = CC()
scala> val c2 = new CC() with T
c2: CC with T = CC()
scala> println(c1.hashCode == c2.hashCode,c1 equals c2)
(true,true)
This behaviour is expected for equals since the Scala compiler overrides the equals method for case classes.
I am however unsure why the hashCode is different in Scala 2.7.7. Your example results in (true, true) using Scala 2.8.