Handling by-name parameters in Scala macro - scala

I have a macro that does some analysis on nested function applications. It matches applications and retrieve the parameter types this way:
case q"$f[..$targs](..$args)(...$otherArgs)" =>
// retrieve the list of all parameter types
val paramTpes = f.tpe match {
case pmt: PolyType if pmt.paramLists.size == 0 =>
Seq()
case pmt: PolyType =>
pmt.paramLists(0) map {_.typeSignature
.substituteTypes(pmt.typeParams, targs map (_.tpe))}
case pmt: MethodType if pmt.paramLists.size == 0 =>
Seq()
case pmt: MethodType =>
pmt.paramLists(0) map (_.typeSignature)
}
Now, if there happen to be by-name parameters, what I get is some weird type that prints => T but cannot be matched with anything. There seem to be no facility in the reflection API to handle these properly.
What I would like to do is retrieve T in case it' a => T, because => T causes further problems in the generated code.

Usually, use the extractors. Sometimes I have to see what the runtime class is, to remember what extractor to use. I don't use the API every day.
scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._
scala> class X { def x(i: => Int) = i * 2 }
defined class X
scala> typeOf[X].member(TermName("x"))
res0: reflect.runtime.universe.Symbol = method x
scala> .typeSignature
res1: reflect.runtime.universe.Type = (i: => scala.Int)scala.Int
scala> res1 match { case MethodType(ps, res) => ps }
res2: List[reflect.runtime.universe.Symbol] = List(value i)
scala> .head
res3: reflect.runtime.universe.Symbol = value i
scala> .typeSignature
res4: reflect.runtime.universe.Type = => scala.Int
scala> res4.getClass
res5: Class[_ <: reflect.runtime.universe.Type] = class scala.reflect.internal.Types$ClassArgsTypeRef
scala> res4 match { case TypeRef(pre, sym, args) => sym }
res6: reflect.runtime.universe.Symbol = class <byname>
scala> res4 match { case TypeRef(pre, sym, args) => args }
res7: List[reflect.runtime.universe.Type] = List(scala.Int)
scala> definitions
res8: reflect.runtime.universe.DefinitionsApi = scala.reflect.internal.Definitions$definitions$#4e80a001
scala> definitions.By
ByNameParamClass ByteClass ByteTpe
scala> definitions.ByNameParamClass
res9: reflect.runtime.universe.ClassSymbol = class <byname>
I vaguely remember the special name, but do I get a stable prefix for pattern matching? I guess not.
scala> res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args }
<console>:20: error: stable identifier required, but scala.reflect.runtime.`package`.universe.definitions.ByNameParamClass found.
Note that method ByNameParamClass is not stable because its type, => reflect.runtime.universe.ClassSymbol, is volatile.
res4 match { case TypeRef(pre, definitions.ByNameParamClass, args) => args }
^
scala> val k = definitions.ByNameParamClass
k: reflect.runtime.universe.ClassSymbol = class <byname>
scala> res4 match { case TypeRef(pre, k, args) => args }
res11: List[reflect.runtime.universe.Type] = List(scala.Int)
scala>

Related

In scala, how to pattern match against an inlined expression?

In scala, a pattern matching for a class has to be conducted in the following way:
val clz: Class[_] = ???
clz match {
case v if clz == classOf[String] =>
// do something
case v if clz == classOf[Int] =>
// do something
//...
}
The boilerplate code v if clz == is really redundant and I'd like to have them removed or reduced, since functions like classOf[String] and classOf[int] can be inlined and used like constant. So how can I do this?
There is some support, mostly in relation to array element types:
scala> import reflect.ClassTag
import reflect.ClassTag
scala> val c: Class[_] = classOf[Int]
c: Class[_] = int
scala> (ClassTag(c): Any) match { case ClassTag.Boolean => "bool" case ClassTag.Int => "int" }
res0: String = int
but the use case is to simplify type tests
scala> def f[A: ClassTag] = ("abc": Any) match { case _: A => "A" case _ => "other" }
f: [A](implicit evidence$1: scala.reflect.ClassTag[A])String
scala> f[Int]
res1: String = other
scala> f[String]
res2: String = A
Maybe one argument for classTag not looking like a stable id is that classOf[C] evaluated in different classloaders don't compare equal.

no type parameters for method flatMap

I don't know why the following code can not compile, this is the error message:
Error:(29, 7) no type parameters for method flatMap: (f: String => Option[B])Option[B] exist so that it can be applied to arguments (String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec })
--- because ---
argument expression's type is not compatible with formal parameter type;
found : String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec }
required: String => Option[?B]
a.flatMap(codecClassName => {
^
and code
def f(a: Option[String]): Unit = {
a.flatMap(codecClassName => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
Some(codecClass)
})
}
This seems to be related to the fact that getClass and classOf are not returning the exact same thing. See Scala equivalent of Java java.lang.Class<T> Object for more details.
Looking around for a workaround I came across Scala Getting class type from string representation.
So how about:
val codecClass = Manifest.classType(codecFactory.getCodecClassByName(codecClassName))
This should work. flatMap involves both map and flatten, so it may need more type annotations in some cases. The overall code works after annotation of the function parameter, i.e. (codecClassName: String).
Note the other change -- that flatMap with an inner function returning an Option type is the same as a map if that function returns what's inside the Option (i.e. flattens the option) (see below).
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.io.compress.{CompressionCodec, CompressionCodecFactory}
...
def f(a: Option[String]): Option[Class[_ <: CompressionCodec]] = {
a.map((codecClassName: String) => {
val codecFactory = new CompressionCodecFactory(new Configuration())
val codecClass = codecFactory.getCodecClassByName(codecClassName)
if (codecClass == null) {
throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
}
codecClass
})
}
To show the relationship between flatMap and map as described above:
scala> val opt: Option[Int] = Some(1)
opt: Option[Int] = Some(1)
scala> opt.map((i: Int) => i + 1)
res0: Option[Int] = Some(2)
scala> val opt2: Option[Int] = None
opt2: Option[Int] = None
scala> opt.flatMap((i: Int) => Some(i + 1))
res1: Option[Int] = Some(2)
scala> opt2.map((i: Int) => i + 1)
res3: Option[Int] = None
scala> opt2.flatMap((i: Int) => Some(i + 1))
res2: Option[Int] = None

Composing functions that return an option

Suppose I have a few functions of type Int => Option[Int]:
def foo(n: Int): Int => Option[Int] = {x => if (x == n) none else x.some}
val f0 = foo(0)
val f1 = foo(1)
I can compose them with >=> as follows:
val composed: Int => Option[Int] = Kleisli(f0) >=> Kleisli(f1)
Suppose now I need to compose all functions from a list:
val fs: List[Int => Option[Int]] = List(0, 1, 2).map(n => foo(n))
I can do it with map and reduce:
val composed: Int => Option[Int] = fs.map(f => Kleisli(f)).reduce(_ >=> _)
Can it (the composed above) be simplified ?
If you want the composition monoid (as opposed to the "run each and sum the results" monoid), you'll have to use the Endomorphic wrapper:
import scalaz._, Scalaz._
val composed = fs.foldMap(Endomorphic.endoKleisli[Option, Int])
And then:
scala> composed.run(10)
res11: Option[Int] = Some(10)
The monoid for kleisli arrows only requires a monoid instance for the output type, while the composition monoid requires the input and output types to be the same, so it makes sense that the latter is only available via a wrapper.
[A] Kleisli[Option, A, A] is a Semigroup via Compose, so we can use foldMap1:
val composed: Int => Option[Int] = fs.foldMap1(f => Kleisli(f))
Interestingly this doesn't work, though if we pass the correct instance explicitly then it does:
scala> val gs = NonEmptyList(fs.head, fs.tail: _*)
gs: scalaz.NonEmptyList[Int => Option[Int]] = NonEmptyList(<function1>, <function1>, <function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int])
res20: scalaz.Kleisli[Option,Int,Int] = Kleisli(<function1>)
scala> gs.foldMap1(f => Kleisli(f))(Kleisli.kleisliCompose[Option].semigroup[Int]).apply(1)
res21: Option[Int] = None
I'm not sure where the instance that seems to take priority is coming from.

How to filter methods by return type with scala reflection?

I'm trying to test whether a method's return type exactly matches a supplied type.
Somehow, I've found two String Types that are not equal.
class VarAndValue {
#BeanProperty
val value = "";
}
class ScalaReflectionTest {
#Test
def myTest(): Unit = {
val type1 = universe.typeOf[String]
// Get return value of VarAndValue.getValue
val type2 = universe.typeOf[VarAndValue].
declarations.
filter { m => m.name.decoded == "getValue" && m.isMethod }.
head.
asInstanceOf[universe.MethodSymbol].
returnType
println(type1) // String
println(type2) // String
println(type1.getClass())
println(type2.getClass()) // !=type1.getClass() !!
println(type1==type2) // False
}
}
yields...
String
String
class scala.reflect.internal.Types$TypeRef$$anon$3
class scala.reflect.internal.Types$TypeRef$$anon$6
false
How can I filter methods of a class by their return type? (It seems very difficult if I can test for equality of the return types).
Scala 2.10
UPDATE:
I can't drop into the Java reflection universe because this erased type information for generics like List[Int] (which become List[Object] is java-land where they're really List[java.lang.Integer]). I need my matched to pay attention to the generic parameter information that the scala type universe preserves.
Use =:= to compare types.
scala> import beans._
import beans._
scala> :pa
// Entering paste mode (ctrl-D to finish)
class VarAndValue {
#BeanProperty
val value = "";
}
// Exiting paste mode, now interpreting.
defined class VarAndValue
scala> import reflect.runtime._, universe._
import reflect.runtime._
import universe._
scala> val str = typeOf[String]
str: reflect.runtime.universe.Type = String
scala> val ms = typeOf[VarAndValue].declarations filter (m => m.isMethod && m.name.decoded == "getValue")
warning: there were two deprecation warnings; re-run with -deprecation for details
ms: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method getValue)
scala> val mm = ms.toList
mm: List[reflect.runtime.universe.Symbol] = List(method getValue)
scala> val m = mm.head.asInstanceOf[MethodSymbol]
m: reflect.runtime.universe.MethodSymbol = method getValue
scala> val t = m.returnType
t: reflect.runtime.universe.Type = java.lang.String
scala> println(t)
java.lang.String
scala> println(str)
String
scala> str == t
res2: Boolean = false
scala> str match { case `t` => }
scala.MatchError: String (of class scala.reflect.internal.Types$AliasNoArgsTypeRef)
... 33 elided
scala> str =:= t
res4: Boolean = true
scala> str match { case TypeRef(a,b,c) => (a,b,c) }
res5: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (scala.Predef.type,type String,List())
scala> t match { case TypeRef(a,b,c) => (a,b,c) }
res6: (reflect.runtime.universe.Type, reflect.runtime.universe.Symbol, List[reflect.runtime.universe.Type]) = (java.lang.type,class String,List())
Depending on what you're going for, consider that conforming types can have differing representations:
scala> typeOf[List[Int]]
res11: reflect.runtime.universe.Type = scala.List[Int]
scala> type X = List[Int]
defined type alias X
scala> typeOf[X].dealias
res12: reflect.runtime.universe.Type = List[scala.Int]
scala> res11 =:= res12
res13: Boolean = true
scala> res11 == res12
res14: Boolean = false
scala> typeOf[X] <:< res11
res15: Boolean = true
scala> typeOf[X] =:= res11
res16: Boolean = true
Turns out this is the way to compare types ...
type1 match {
case type2 => true
case _ => false
}
which gives a different answer than type1==type.
Scala is a strange beast.

HowTo get the class of _ :Any

I've wrapped a Message and would like to log which message I've wrapped.
val any :Any = msg.wrappedMsg
var result :Class[_] = null
The only solution I could find is matching everything:
result = any match {
case x:AnyRef => x.getClass
case _:Double => classOf[Double]
case _:Float => classOf[Float]
case _:Long => classOf[Long]
case _:Int => classOf[Int]
case _:Short => classOf[Short]
case _:Byte => classOf[Byte]
case _:Unit => classOf[Unit]
case _:Boolean=> classOf[Boolean]
case _:Char => classOf[Char]
}
I wonder if there's a better solution?
The following 2 approaches do not work :(
result = any.getClass //error
// type mismatch; found : Any required: ?{val getClass: ?}
// Note: Any is not implicitly converted to AnyRef.
// You can safely pattern match x: AnyRef or cast x.asInstanceOf[AnyRef] to do so.
result = any match {
case x:AnyRef => x.getClass
case x:AnyVal => /*voodoo to get class*/ null // error
}
//type AnyVal cannot be used in a type pattern or isInstanceOf
You can safely call .asInstanceOf[AnyRef] on any Scala value, which will box primitives:
scala> val as = Seq("a", 1, 1.5, (), false)
as: Seq[Any] = List(, 1, 1.5, (), false)
scala> as map (_.asInstanceOf[AnyRef])
res4: Seq[AnyRef] = List(a, 1, 1.5, (), false)
From there, you can call getClass.
scala> as map (_.asInstanceOf[AnyRef].getClass)
res5: Seq[java.lang.Class[_]] = List(class java.lang.String, class java.lang.Int
eger, class java.lang.Double, class scala.runtime.BoxedUnit, class java.lang.Boo
lean)
Tested with 2.8.0.RC6, I don't know it this worked in 2.7.7.
Definitely new in 2.8 are the companion objects for the classes derived from AnyVal. They contain handy box and unbox methods:
scala> Int.box(1)
res6: java.lang.Integer = 1
scala> Int.unbox(res6)
res7: Int = 1
Won't casting just do the trick, as suggested in the error message?
scala> val d:Double = 0.0
d: Double = 0.0
scala> d.asInstanceOf[AnyRef].getClass
res0: java.lang.Class[_] = class java.lang.Double
As of scala 2.10.0, getClass is available on Any (and not just on AnyRef), so you don't need to do any contorsion anymore and can just do any.getClass.
Note though that you still must be prepared to handlet the dual relation between primitive types and their boxed version.
By example getClass on an integer value will return either java.lang.Integer.TYPE (the class of the primitive Int type) or classOf[java.lang.Integer] depending on the static type of the value:
scala> 123.getClass
res1: Class[Int] = int
scala> val x : Int = 123
x: Int = 123
scala> x.getClass
res2: Class[Int] = int
scala> val x: AnyVal = 123
x: AnyVal = 123
scala> x.getClass
res3: Class[_] = class java.lang.Integer
scala> val x: Any = 123
x: Any = 123
scala> x.getClass
res4: Class[_] = class java.lang.Integer