Bringing trait implementation members into scope using reflection - scala

I'm using reflection to parse all public variable accessors from classes extending a trait called Component with the following call:
def iterate[T <: Component : TypeTag : ClassTag](component: T) {
...
ru.typeOf[T].members.filter(...)
...
}
However, this only works if the class type implementing the Component trait is visible during the call:
val myComp: MyComponent = new MyComponent()
iterate(myComp) // works
val myComp: Component = new MyComponent()
iterate(myComp) // Doesn't work, no members of MyComponent found in scope
One solution would be to define the implementing type in the trait (MyComponent extends Component[MyComponent]), but since I'm digging around with reflection anyway I was wondering if the variables of MyComponent are accessible from behind the trait.

I think you can get Type from java.lang.Class. See the example below.
╰─$ scala
Welcome to Scala version 2.11.2 (OpenJDK 64-Bit Server VM, Java 1.7.0_65).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.reflect._
import scala.reflect.runtime.universe._
trait Component {
def parent: Int = 0
}
class MyComponent extends Component {
def child: Int = 0
}
def printRuntimeMemberNames(component: Component) = {
val cls = component.getClass
val mirror = runtimeMirror(cls.getClassLoader)
val symbol = mirror.staticClass(cls.getName)
val tpe = symbol.toType
val members = tpe.members
val memberNames = members.map(_.name.decodedName.toString)
println(memberNames.mkString(", "))
}
// Exiting paste mode, now interpreting.
import scala.reflect._
import scala.reflect.runtime.universe._
defined trait Component
defined class MyComponent
printRuntimeMemberNames: (component: Component)Unit
scala> val c: Component = new MyComponent
c: Component = MyComponent#3db7416a
scala> printRuntimeMemberNames(c)
<init>, child, parent, $init$, $asInstanceOf, $isInstanceOf, synchronized, ##, !=, ==, ne, eq, notifyAll, notify, clone, getClass, hashCode, toString, equals, wait, wait, wait, finalize, asInstanceOf, isInstanceOf

Related

Problem with bringing into scope scala implicit conversions

I was playing with implicits but I got some behaviour that I don't understand.
I defined a simple class and its companion object (just to make a quick test on implicits) as follows
class SimpleNumber(val numb: Int) {
def sum(n: Int) = numb + n
}
object SimpleNumber {
implicit def stringToInt(s: String) = s.toInt
}
The method stringToInt is supposed to work in the event I call the sum method by passing a string instead of an int, so that it can be converted to an int (it's just for testing purposes, so I don't need to check errors or exceptions).
If I paste the above code in the repl (:paste), I get this warning
warning: implicit conversion method stringToInt should be enabled
by making the implicit value scala.language.implicitConversions visible.
This can be achieved by adding the import clause 'import scala.language.implicitConversions'
or by setting the compiler option -language:implicitConversions.
So I moved to VSCode and pasted in the same code, to see if I could get some more info via metals plugin, but that warning doesn't even pop out. Then I created a new object that extends the App trait to test the code like this
object TestDriver extends App{
val a = new SimpleNumber(4)
println(a.sum("5"))
}
but I received the following error
type mismatch; found : String("5") required: Int
I tried importing the implicitConversions as the repl suggested, first in the companion object and then in the TestDriver object, but to no avail. Then I imported the implicit method directly in the TestDriver object, and that worked.
import SimpleNumber.stringToInt
object TestDriver extends App{
val a = new SimpleNumber(4)
println(a.sum("5"))
}
Why doesn't the import scala.language.implicitConversions work as I thought it would? I'm using scala 2.13.3
Why doesn't the import scala.language.implicitConversions work as I thought it would?
import scala.language.implicitConversions is just to signal that implicit conversions are defined in a code, not to bring specific ones to a scope. You can do
import SimpleNumber._
to bring stringToInt to the local scope.
Where does Scala look for implicits?
Should I use method overload then?
Depends on your goal. Implicit conversions (which are normally not recommended) are not just for method overloading. In your example String can be used in all places where Int is expected (this is just for example, normally standard types like Int, String, Function shouldn't be used for implicits, use custom types for implicits). If you used implicit conversions just for method overloading then yes, you should prefer the latter. Don't forget that method overloading can be done not only as
class SimpleNumber(val numb: Int) {
def sum(n: Int): Int = numb + n
def sum(n: String): Int = numb + n.toInt
}
but also with a type class
class SimpleNumber(val numb: Int) {
def sum[A: ToInt](n: A): Int = numb + n.toInt
}
trait ToInt[A] {
def toInt(a: A): Int
}
object ToInt {
implicit val int: ToInt[Int] = identity
implicit val str: ToInt[String] = _.toInt
}
implicit class ToIntOps[A](val a: A) extends AnyVal {
def toInt(implicit ti: ToInt[A]): Int = ti.toInt(a)
}
or magnet
import scala.language.implicitConversions
import Predef.{augmentString => _, _} // to avoid implicit ambiguity
class SimpleNumber(val numb: Int) {
def sum(n: ToInt): Int = numb + n.toInt()
}
trait ToInt {
def toInt(): Int
}
object ToInt {
implicit def fromInt(i: Int): ToInt = () => i
implicit def fromStr(s: String): ToInt = () => s.toInt
}
Notice that you don't have to import ToInt.
Overloading methods based on generics
Type erasure problem in method overloading

Scala: How can an import prevent finding an implicit value?

I could use suggestions debugging an implicit:
I want to use the implicit, x:
type T
trait HasT {
implicit def x: T = ...
}
But I also need a wildcard import from some package foo. I've tried two different ways of introducing both:
class UseT extends HasT {
import foo._
implicitly[T] // fails! "could not find implicit value"
// use foo stuff
}
and
class UseT {
object hasT extends HasT
import hasT.x
import foo._
implicitly[T] // fails! "could not find implicit value"
}
Both fail with "could not find" (not "ambiguous implicits values").
This happens while implicit identifier x: T is accessible at the point of method call via either inheritance or importing.
My workaround is to rebind x to an implicit val before the import. Both of the following work:
implicit val x2: T = implicitly[T]
import foo._
implicitly[T] // works!
and
implicit val x2: T = x
import foo._
implicitly[T] // works!
What value could possibly be in foo to cause this behavior?
My first guess is that there is some competing implicit in foo, but if it were higher priority, the following implicitly would still work, and if it were an ambiguous implicit, I'd be getting a different a different error.
edit: Miles Sabin's guess was correct! I found the shadowing implicit: timeColumnType. I still don't completely understand how this works given Som Snytt's observation that the shadowing implicit was wildcard imported (lower priority) while the shadowed was inherited (part of highest priority), so I'll leave the whole post here for posterity.
retracted: A second guess, offered by miles sabin, is implicit shadowing. I've since clarified my post to exclude that possibility. That case would be consistent with my errors if I had tried package hasT extends HasT; import hasT._, but As som-snytt points out, those two cases would not result in shadowing.
In my specific case, this can be confirmed by changing the name of the implicit I'm trying to use.
(This is false. I likely missed a publishLocal or reload while using this test to verify.)
context: I'm actually trying to use slick. The implicit T above is actually a column type mapping:
import slick.driver.JdbcProfile
class Custom { ... } // stored as `Long` in postgres
trait ColumnTypes {
val profile: JdbcProfile
import profile.api._ // this is `foo` above
type T = profile.BaseColumnType[Custom]
implicit def customColumnType: T =
MappedColumnType.base[Custom, Long](_.toLong, Custom.fromLong)
}
class DatabaseSchema(val profile: JdbcProfile) extends ColumnTypes {
// `implicitly[T]` does not fail here.
import profile.api._ // this is also `foo` above
// `implicitly[T]` fails here, but it's needed for the following:
class CustomTable(tag: Tag) extends Table[Custom](tag, "CUSTOMS") {
// following fails unless I rebind customColumnType to a local implicit
def custom = column[Custom]("CUSTOM")
def * = custom
}
}
The type of api/foo is JdbcProfile.API. The offending implicit is probably here, but I can't tell why. I'll try blocking some of those from being imported and see if I can narrow it down.
I think it's most likely that foo contains a definition named x. When (wildcard) imported from foo it shadows the local definition,
scala> object foo { val x: Boolean = true }
defined object foo
scala> implicit val x: Int = 23
x: Int = 23
scala> implicitly[Int]
res0: Int = 23
scala> import foo._
import foo._
scala> implicitly[Int]
<console>:17: error: could not find implicit value for parameter e: Int
implicitly[Int]
^
This is clearly a bug in implicit search.
First, eligible are all identifiers x that can be accessed at the
point of the method call without a prefix and that denote an implicit
definition or an implicit parameter. An eligible identifier may thus
be a local name, or a member of an enclosing template, or it may be
have been made accessible without a prefix through an import clause.
In the example, unprefixed x refers to the inherited symbol. X.x is not accessible without a prefix.
Implicit search is fumbling the import.
$ scala
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { def x: Int = 42 }
trait T { def x: Int = 17 }
object Y extends T {
import X._
def f = x
}
// Exiting paste mode, now interpreting.
defined object X
defined trait T
defined object Y
scala> Y.f
res0: Int = 17
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { implicit def x: Int = 42 }
trait T { implicit def x: Int = 17 }
object Y extends T {
import X._
def f: Int = implicitly[Int]
}
// Exiting paste mode, now interpreting.
<pastie>:19: error: could not find implicit value for parameter e: Int
def f: Int = implicitly[Int]
^
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { implicit def x: Int = 42 }
trait T { implicit def x: Int = 17 }
object Y extends T {
import X.{x => _, _} // avoids bug, but is redundant
def f: Int = implicitly[Int]
}
// Exiting paste mode, now interpreting.
defined object X
defined trait T
defined object Y
scala>
The other example using the REPL is scoped this way:
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { def x: Int = 42 }
object Y { implicit def x: Int = 17 }
object Z {
import Y.x
def f = {
import X._
x
}
}
// Exiting paste mode, now interpreting.
<pastie>:19: error: reference to x is ambiguous;
it is imported twice in the same scope by
import X._
and import Y.x
x
^
Where x is not available at all, and the implicit is correctly excluded.
Just to confirm:
$ scala -Xlog-implicits
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { implicit def x: Int = 42 }
trait T { implicit def x: Int = 17 }
object Y extends T {
import X._
def f: Int = implicitly[Int]
}
// Exiting paste mode, now interpreting.
<console>:17: x is not a valid implicit value for Int because:
candidate implicit method x in object X is shadowed by method x in trait T
def f: Int = implicitly[Int]
^
<console>:17: x is not a valid implicit value for Int because:
candidate implicit method x in object X is shadowed by method x in trait T
def f: Int = implicitly[Int]
^
<console>:17: error: could not find implicit value for parameter e: Int
def f: Int = implicitly[Int]
^
scala>
Probably https://issues.scala-lang.org/browse/SI-9208

How to fix this typeclass example?

This is a follow-up to my previous question:
Suppose I create the following test converter.scala:
trait ConverterTo[T] {
def convert(s: String): Option[T]
}
object Converters {
implicit val toInt: ConverterTo[Int] =
new ConverterTo[Int] {
def convert(s: String) = scala.util.Try(s.toInt).toOption
}
}
class A {
import Converters._
def foo[T](s: String)(implicit ct: ConverterTo[T]) = ct.convert(s)
}
Now when I tried to call foo in REPL it fails to compile:
scala> :load converter.scala
Loading converter.scala...
defined trait ConverterTo
defined module Converters
defined class A
scala> val a = new A()
scala> a.foo[Int]("0")
<console>:12: error: could not find implicit value for parameter ct: ConverterTo[Int]
a.foo[Int]("0")
^
import Converters._ in class A does not cut it. You can remove it and the code will still compile. The moment the compiler needs to find in actual implicit is not in class A, where foo is just declared.
The compiler needs to find a ConverterTo[Int] in implicit scope at the moment you call a.foo[Int](..) that is in the REPL. So this is where the import needs to be.
Had object Converters and trait ConverterTo been named the same (so there would be a companion object) the import would not be needed.

Given an object, how can I instantiate a new object whose class is the same plus one additional trait

If I have some object x, and I want to create a new instance with the same class as x, I can say:
x.getClass.newInstance
If x was of some (unknown) class T, the new instance is also of class T.
But I actually want to create a new instance which is T with A. In other words, I want to do something like:
(x.getClass with A).newInstance
But that doesn't work. Is it possible to do this?
First of all, you cannot just add a trait or interface to existing class because JVM classes are static - you have to create a subclass of both. But you cannot dynamically create classes without manually fiddling with byte code, not in Scala at least. To create new object of a class you have to define this class first, and it is only possible when you know in advance which classes you're extending. So no, it is impossible (at least, extremely inconvenient).
Depending on your concrete use case, however, it is possible to emulate this, for example, with composition plus implicit conversion:
implicit class SomeClassAView(x: SomeClass) extends A {
// Implement A methods using x object
}
def expectingA(x: A) { ... }
val x: SomeClass = ...
expectingA(x) // x will be implicitly converted to SomeClassAView which extends A
If the T is unknown, then compilation on the fly is handled handily:
apm#mara:~/goof$ scalam -cp /tmp
Welcome to Scala version 2.11.0-M7 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> new ts.X {}
res0: ts.X = $anon$1#13ba518f
scala> import tools.reflect.ToolBox
import tools.reflect.ToolBox
scala> import reflect.runtime._
import reflect.runtime._
scala> import universe._
import universe._
scala> val tb = currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl#62920919
scala> tb.eval(tb.parse("new ts.X with ts.Y {}"))
res2: Any = __wrapper$1$88859f071ea8497cb9bf4b87aa027c85.__wrapper$1$88859f071ea8497cb9bf4b87aa027c85$$anon$1#5fa8881b
scala> res2.asInstanceOf[ts.X with ts.Y]
res3: ts.X with ts.Y = __wrapper$1$88859f071ea8497cb9bf4b87aa027c85.__wrapper$1$88859f071ea8497cb9bf4b87aa027c85$$anon$1#5fa8881b
There is an issue to make REPL-compiled classes visible to the toolbox.
For now, roll your own:
scala> val rtm = runtimeMirror($intp.classLoader)
rtm: reflect.runtime.universe.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader#5349c9cb of type class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)] and parent being scala.reflect.internal.util.ScalaClassLoader$URLClassLoader#115f5925 of type class scala.reflect.internal.util.ScalaClassLoader$URLClassLoader with classpath [file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/resources.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jsse.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jce.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/charsets.jar,file:/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rhino.jar,file:/home/apm/scala-2.11.0-M7/lib/akka-actors.jar,file:/hom...
scala> val rtb = rtm.mkToolBox()
rtb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl#58f59add
scala> :pa -raw
// Entering paste mode (ctrl-D to finish)
package foo
class Foo
// Exiting paste mode, now interpreting.
scala> rtb.eval(rtb.parse("new foo.Foo"))
res6: Any = foo.Foo#7c20db7f

How are final val defined inside a trait treated by Scala Compiler?

I use very often the selfless trait pattern and I need to use "expensive" constants inside the trait:
I would like to have a single instance of these values, which might require several steps to be computed, in all my application.
However, the selfless trait pattern results in the following design:
A trait MyStuff
An object MyStuff extends MyStuff
Clearly, putting constants inside the object and using them inside a trait creates a cyclic dependency. Putting them on the trait however , makes possible for all the classes extending the trait to override them, and therefore they are certainly not an application-wide singleton.
Is the Scala compiler "clever enough" to makes final vals inside a trait become "old java public static final" ?
No, scala will not translate a final val inside a trait to the equivalent of a java static final, because the final val will need to be an instance member (not a static member) of the inheriting class.
scala> trait myStuff { final val Test="test" }
defined trait myStuff
scala> class t extends myStuff
defined class t
scala> t.Test
<console>:8: error: not found: value t
t.Test
^
// we need an instance of t to access Test
scala> new t
res2: t = t#35612600
scala> res2.Test
res3: String = test
if you're using selfless trait and you can't store your final val in MyStuff's companion object (because you're using it in the trait itself), you could probably just create another object for your final val.
//your expensive constant is here
scala> object MyConstant {final val C="C"}
defined module MyConstant
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait MyStuff {
import MyConstant._
def doStuff = C
}
object MyStuff extends MyStuff
// Exiting paste mode, now interpreting.
defined trait MyStuff
defined module MyStuff
// let's test importing the companion object of the selfless trait
scala> import MyStuff._
import MyStuff._
scala> doStuff
res4: String = C
What's an example of the cyclic dependency you're concerned about?
Usually that's solved through appropriate use of defs in the trait or lazy vals.
Here's an example issue that is induced by default args (which are synthesized in the companion object).
But if you need eagerness, you can always define early, définition en avance:
scala> :pa
// Entering paste mode (ctrl-D to finish)
trait Foo {
val v = 2 * Foo.w
}
object Foo extends {
private val w = 3
} with Foo
// Exiting paste mode, now interpreting.
defined trait Foo
defined object Foo
scala> Foo.v
res11: Int = 6
If calculating w uses members of Foo, though, you'd have to go lazy:
trait Foo {
val v = 2 * Foo.w
def x = 7
}
object Foo extends Foo {
lazy val w = 3 * x
}
This is the second time today I've needed the one-question FAQ, but I haven't looked for its new home yet.
(Edit: why, here it is.)
As analogue of public static final you should use a companion object like this:
trait MyStuff
object MyStuff {
val publicStaticFinal = ...
}
In this case scalac creates a singleton object (public static final MyStuff$ MODULE$) with method public int publicStaticFinal(). You could make this method final if you want to.
For public final - use final val:
trait MyStuff
final val publicFinal = ...
}
In this case scalac creates an interface with public abstract int publicFinal() and implements it in every ancestor of MyStuff as public final int publicFinal().