Scala - DSL: overloaded prefix function ambiguity - scala

In my DSL I want this functionality:
class Test {
val compA = dependant(true, true)(Component("parameters"))
//and this shortcut:
val compB = dependant Component("parameters")
}
where:
def dependant(onEnable: Boolean, onDisable: Boolean)(c: Component): Component = {
//...
}
def dependant(c: Component): Component = dependant(false, true)(c)
all is fine, however, I cannot use this syntax:
val compB = dependant Component("parameters")
because it says
ambiguous reference to overloaded definition, both method dependant in
class Test of type (onEnable: Boolean, onDisable: Boolean)(c:
Component)Component and method dependant in class Test of type (c:
Component)Component match expected type ?
But if I enclose the parameter in parenthesis:
val compB = dependant(Component("parameters"))
the error is gone. Obviously, the compiler fails in desugarating the parenthesisless case. Is this expected or am I doing something wrong? If this is expected, then Why? How can I reclaim the ability to use the method dependant as a prefix, without parenthesis?

In dependant Component("parameters") you are trying to use a prefix notation to call the dependant. Scala's support for prefix notation is limited.
See Scala - Prefix Unary Operators.
An alternative is to use a postfix notation (as in Component("parameters") dependant).
If you can modify the implementaiton of Componenet, this simply means adding the dependant methods to Component:
class Component(name: String) {
def dependant: Component = //...
def dependant(onEnable: Boolean, onDisable: Boolean): Component = {
//...
}
}
class Test {
val compA = Component("parameters") dependant(true, true)
val compB = Component("parameters") dependant
}
If you can't modify Component, you can use the "pimp my library idiom".
See http://www.decodified.com/scala/2010/12/02/the-quickpimp-pattern.html for a short introduction to this idiom (along with a warning on using an anonymous class as below):
case class Component(name: String)
implicit def toPostifxDependentOps( c: Component ) = new {
def dependant: Component = dependant(false, true)
def dependant(onEnable: Boolean, onDisable: Boolean): Component = {
//...
}
}
class Test {
val compA = Component("parameters") dependant(true, true)
val compB = Component("parameters") dependant
}

Writing myObject functionName paraminstead of myObject.functionName(param) works as expected if you propvide an object. If you don't, the compiler will be lost. For example:
scala> println("Hello")
Hello
scala> println "Hello"
<console>:1: error: ';' expected but string literal found.
println "Hello"
^
A possible workaround: create an object to wrap your method:
scala> case class Component(name: String, components: Option[Component] = None)
defined class Component
scala> object depends {def on(c: Component) = Component("dependant", Some(c))}
defined module depends
scala> depends on Component("foo")
res3: Component = Component(dependant,Some(Component(foo,None)))

Related

In scala macro, how to lift an object and use it in quasiquote at compile time?

The following code snippet is a short scala macro bundle definition from a thoughtworks project:
private[SelfType] final class Macros(val c: whitebox.Context) {
import c.universe._
def apply[A: WeakTypeTag]: Tree = {
val a = weakTypeOf[A]
val selfTypes: List[Type] = {
val selfTypeBuilder = List.newBuilder[Type]
def buildSelfTypes(t: Type): Unit = {
val dealiased = t.dealias
dealiased match {
case RefinedType(superTypes, refinedScope) =>
superTypes.foreach(buildSelfTypes)
case typeRef: TypeRef =>
val symbol = dealiased.typeSymbol
if (symbol.isClass) {
selfTypeBuilder += symbol.asClass.selfType.asSeenFrom(dealiased, symbol)
}
case _ =>
}
}
buildSelfTypes(a)
selfTypeBuilder.result()
}
val out = selfTypes match {
case Nil =>
definitions.AnyTpe
case _ =>
internal.refinedType(selfTypes, c.internal.enclosingOwner)
}
q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]"
}
}
(courtesy of https://github.com/ThoughtWorksInc/feature.scala/blob/4d19cc19016d85f26925895f43f618e1b7552d09/SelfType/src/main/scala/com/thoughtworks/feature/SelfType.scala)
The last line as a quasiquote seems to contain a lot of boilerplate text:
q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]"
Assuming that this macro bundle is defined inside a trait as part of a family polymorphism design pattern: there is no deterministic q"_root_.com.thoughtworks.feature.SelfType.make[$a, $out]", it has to be derived from an object variable vvv of the macro bundle when it is being compiled. How do I use this variable to make the quasiquote shorter and more adaptive?
There may be multiple methods to achieve this (e.g. for each implementation, define a Liftable for SelfType object). But that's even more boilerplate. I'm looking for the shortest solution. Ideally, something like this:
val sym = Term(vvv)
q"$sym.make[$a, $out]"
If you have a static reference (e.g. the type/companion is imported), you can do:
q"${symbolOf[SelfType.type]}.make[$a, $out]"
You can also use symbolOf[A].companion if you have A: WeakTypeTag but no info about its companion. That might not work if the compiler doesn't consider the object A a companion to class A
Found my first solution:
val name = SelfTypes.getClass.getCanonicalName.stripSuffix("$")
val tree = c.parse(name)
q"$tree.make[$a, $out]"
Not sure if it is the most efficient or idiomatic solution, I'll let the question hanging there for a while

Is it possible to call a scala macro from generic scala code?

I'm trying to use Scala macros to convert untyped, Map[String, Any]-like expressions to their corresponding typed case class expressions.
The following scala macro (almost) gets the job done:
trait ToTyped[+T] {
def apply(term: Any): T
}
object TypeConversions {
// At compile-time, "type-check" an untyped expression and convert it to
// its appropriate typed value.
def toTyped[T]: ToTyped[T] = macro toTypedImpl[T]
def toTypedImpl[T: c.WeakTypeTag](c: Context): c.Expr[ToTyped[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
if (tpe <:< typeOf[Int] || tpe <:< typeOf[String]) {
c.Expr[ToTyped[T]](
q"""new ToTyped[$tpe] {
def apply(term: Any): $tpe = term.asInstanceOf[$tpe]
}""")
} else {
val companion = tpe.typeSymbol.companion
val maybeConstructor = tpe.decls.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}
val constructorFields = maybeConstructor.get.paramLists.head
val subASTs = constructorFields.map { field =>
val fieldName = field.asTerm.name
val fieldDecodedName = fieldName.toString
val fieldType = tpe.decl(fieldName).typeSignature
q"""
val subTerm = term.asInstanceOf[Map[String, Any]]($fieldDecodedName)
TypeConversions.toTyped[$fieldType](subTerm)
"""
}
c.Expr[ToTyped[T]](
q"""new ToTyped[$tpe] {
def apply(term: Any): $tpe = $companion(..$subASTs)
}""")
}
}
}
Using the above toTyped function, I can convert for example an untyped person value to its corresponding typed Person case class:
object TypeConversionTests {
case class Person(name: String, age: Int, address: Address)
case class Address(street: String, num: Int, zip: Int)
val untypedPerson = Map(
"name" -> "Max",
"age" -> 27,
"address" -> Map("street" -> "Palm Street", "num" -> 7, "zip" -> 12345))
val typedPerson = TypeConversions.toTyped[Person](untypedPerson)
typedPerson shouldEqual Person("Max", 27, Address("Palm Street", 7, 12345))
}
However, my problem arises when trying to use the toTyped macro from above in generic scala code. Suppose I have a generic function indirection that uses the toTyped macro:
object CanIUseScalaMacrosAndGenerics {
def indirection[T](value: Any): T = TypeConversions.toTyped[T](value)
import TypeConversionTests._
val indirectlyTyped = indirection[Person](untypedPerson)
indirectlyTyped shouldEqual Person("Max", 27, Address("Palm Street", 7, 12345))
Here, I get a compile-time error from the toTyped macro complaining that the type T is not yet instantiated with a concrete type. I think the reason for the error is that from the perspective of toTyped inside indirection, the type T is still generic and not inferred to be Person just yet. And therefore the macro cannot build the corresponding Person case class when called via indirection. However, from the perspective of the call-site indirection[Person](untypedPerson), we have T == Person, so I wonder if there is a way to obtain the instantiated type of T (i.e., Person) inside the macro toTyped.
Put differently: Can I combine the Scala macro toTyped with the generic function indirection and yet be able to figure out the instantiated type for type parameter T inside the toTyped macro? Or am I on a hopeless track here and there is no way to combine Scala macros and generics like this? In the latter case I would like to know if the only solution here is to push the macro usage so far "out" that I can call it instantiated as toTyped[Person] rather than as toTyped[T].
Any insights are very much appreciated. Thank you! :-)
Macros need to be expanded. Every time you use a function which body is a macro, Scala will have to generate the code and put it there. As you suspect, this is very very specific and contradict the idea of parametric polymorphism where you write code independent of specific knowledge about your type.
Type classes are one of solutions to the general problem when you want to have one generic (parametric) definition and multiple per-type implementations of certain parts of your algorithm. You basically, define something that you could consider interface which (most likely) need to follow some contract (speaking in OOP terminology) and pass this interface as as argument:
// example
trait SpecificPerType[T] {
def doSomethingSpecific(t: T): String
}
val specificForString: SpecificPerType[String] = new SpecificPerType[String] {
def doSomethingSpecific(t: String): String = s"MyString: $t"
}
val specificForInt: SpecificPerType[Int] = new SpecificPerType[Int] {
def doSomethingSpecific(t: Int): String = s"MyInt: $t"
}
def genericAlgorithm[T](values: List[T])(specific: SpecificPerType[T]): String =
values.map(specific.doSomethingSpecific).mkString("\n")
genericAlgorithm(List(1,2,3))(specificForInt)
genericAlgorithm(List("a","b","c"))(specificForString)
As you can see, it would be pretty annoying to pass this specific part around, which is one of the reasons implicits were introduced.
So you could write it using implicits like this:
implicit val specificForString: SpecificPerType[String] = new SpecificPerType[String] {
def doSomethingSpecific(t: String): String = s"MyString: $t"
}
implicit val specificForInt: SpecificPerType[Int] = new SpecificPerType[Int] {
def doSomethingSpecific(t: Int): String = s"MyInt: $t"
}
def genericAlgorithm[T](values: List[T])(implicit specific: SpecificPerType[T]): String =
values.map(specific.doSomethingSpecific).mkString("\n")
/* for implicits with one type parameter there exist a special syntax
allowing to express them as if they were type constraints e.g.:
def genericAlgorithm[T: SpecificPerType](values: List[T]): String =
values.map(implicitly[SpecificPerType[T]].doSomethingSpecific).mkString("\n")
implicitly[SpecificPerType[T]] is a summoning that let you access implicit
by type, rather than by its variable's name
*/
genericAlgorithm(List(1,2,3)) // finds specificForString using its type
genericAlgorithm(List("a","b","c")) // finds specificForInt using its type
If you generate that trait implementation using macro, you will be able to have a generic algorithm e.g.:
implicit def generate[T]: SpecificPerType[T] =
macro SpecificPerTypeMacros.impl // assuming that you defined this macro there
As far as I can tell, this (extracting macros into type classes) is one of common patterns when it comes to being
able to generate some code with macros while, still building logic on top of it
using normal, parametric code.
(Just to be clear: I do not claim that the role of type classes is limited as the carriers of macro generated code).

Passing a Scala type to a function

I'm trying to implement basically the same thing that is discussed here, but in my specific situation, it's not working.
Currently I have a function that validates a JSON response from our server. The problem is, it has the JSON type hardcoded into the method:
def fakeRequest[A: Writes](target: () => Call, requestObject: A): Any = {
route(FakeRequest(target()).withJsonBody(Json.toJson(requestObject))) match {
// ... stuff happens
Json.parse(contentAsString(response)).validate[GPInviteResponse]
^
Note the hardcoded GPInviteResponse type.
So, to make this a totally generic and reusable method, it would be great to pass in the type that is being validated.
I tried this:
def fakeRequest[A: Writes, B](target: () => Call, requestObject: A, responseType: B): Any = {
route(FakeRequest(target()).withJsonBody(Json.toJson(requestObject))) match {
// ... stuff happens
Json.parse(contentAsString(response)).validate[B]
^
That almost works, but I get a No Json deserializer found for type B. Makes sense, so I changed it to:
def fakeRequest[A: Writes, B: Reads](target: () => Call, requestObject: A, responseType: B): Any = {
But, now I get No Json deserializer found for type controllers.GPInviteResponse.type. So the question is: Is it possible to pass a type like this (or is there some other magic to make it work)?
There is a deserializer defined for the type... I've re-read it half a dozen times to make sure there's no typo:
case class GPInviteResponse(inviteSent: Boolean, URL: Option[String], error: Option[GPRequestError] = None) {
def this(error: GPRequestError) = this(false, None, Option(error))
}
object GPInviteResponse {
implicit val readsInviteResponse = Json.reads[GPInviteResponse]
implicit val writesInviteResponse = Json.writes[GPInviteResponse]
}
Edit
Included below is a simplified test case that demonstrates the problem. At the moment, this won't compile (error is shown below). I think I understand why it won't work (vaguely) but I have no idea regarding a solution. My theory as to why it won't work: While the provided type GPInviteRequest does have an implicit Reads/Writes method, Scala cannot make the connection that an instance B is actually a GPInviteRequest so it concludes that B does not have Reads/Writes.
case class GPInviteResponse(inviteSent: Boolean)
object GPInviteResponse {
implicit val readsInviteResponse = Json.reads[GPInviteResponse]
implicit val writesInviteResponse = Json.writes[GPInviteResponse]
}
class TestInviteServices extends PlaySpecification {
"try to validate a type" in {
tryToValidate(GPInviteRequest(true))
}
def tryToValidate[B: Reads, Writes](i: B) = {
val json = Json.toJson(i).toString
Json.parse(json).validate[B].isSuccess must beTrue
}
}
The above test yields:
[error]
/Users/zbeckman/Projects/Glimpulse/Server-2/project/glimpulse-server/test/application/TestInviteServices.scala:46:
No Json serializer found for type B. Try to implement an implicit
Writes or Format for this type. [error] val json =
Json.toJson(i).toString [error] ^ [error]
/Users/zbeckman/Projects/Glimpulse/Server-2/project/glimpulse-server/test/application/TestInviteServices.scala:133:
No Json deserializer found for type controllers.GPInviteResponse.type.
Try to implement an implicit Reads or Format for this type. [error]
fakeRequest(controllers.routes.GPInviteService.invite, i,
GPInviteResponse) match { [error] ^
Your error message:
No Json serializer found for type B. Try to implement an implicit Writes or Format for this type.
In this function, how is the toJson method supposed to know how to serialize your type B?
def tryToValidate[B: Reads, Writes](i: B) = {
val json = Json.toJson(i).toString
Json.parse(json).validate[B].isSuccess must beTrue
}
You haven't pulled in a writer/reader into scope, the compiler doesn't know where to look for one and that's why it's telling you to implement one. Here's a quick solution
case class GPInviteResponse(inviteSent: Boolean)
object GPInviteResponse {
implicit val format = Json.format[GPInviteResponse]
}
def tryToValidate[B](i: B)(implicit format: Format[B]) = {
val json = Json.toJson(i).toString
Json.parse(json).validate[B]
}
Note: using the format method is equivalent to defining both a reads and writes.
Now, there is an implicit formatter for B in scope, so the compiler knows where to find it and injects it into the validate method which takes a reader implicitly:
// From play.api.libs.json
def validate[T](implicit rds: Reads[T]): JsResult[T] = rds.reads(this)
Edit
You can add type parameters to your function and then reference them in the validate[T] method, like so:
// Define another case class to use in the example
case class Foo(bar: String)
object Foo {
implicit val format = Json.format[Foo]
}
def tryToValidate[B, C](implicit f1: Format[B], f2: Format[C]) = {
val j1 = """{"inviteSent":true}"""
val j2 = """{"bar":"foobar"}""" //
Json.parse(j1).validate[B]
Json.parse(j2).validate[C]
}
// Example call
tryToValidate[GPInviteResponse, Foo]
Try it this way :
def tryToValidate[B](i: B)(implicit format : Format[B]) = {
val json = Json.toJson(i).toString
Json.parse(json).validate[B].isSuccess must beTrue
}

Proxy class support

Is there Scala way for runtime generation of proxy classes? not DynamicProxy but runtime types that extend provided class/interface and pass all calls through provided callback.
Java world uses cglib/javassist for that, but what is the best way to proxy in Scala?
def makeProxy[T](interceptor: Interceptor, implicit baseClass: Manifest[T]): T
Google says Scala macros can be used for this but I am unsure how.
Here is an example how (more-less) to do something like that with macro:
def testImpl[T : c.WeakTypeTag](c: Context): c.Expr[Any] = {
import c.universe._
val className = newTypeName(weakTypeTag[T].tpe.typeSymbol.name.toString) //not best way
val m = weakTypeOf[T].declarations.iterator.toList.map(_.asMethod) //`declaration` takes only current; `members` also takes inherited
.filter(m => !m.isConstructor && !m.isFinal).map { m => //all reflection info about method
q"""override def ${m.name} = 9""" //generating new method
}
c.Expr { q"""new $className { ..$m } """}
}
def t[T] = macro testImpl[T]
class Aaa{ def a = 7; def b = 8}
scala> t[Aaa].a
res39: Int = 9
scala> t[Aaa].b
res40: Int = 9
All such macro works only if overriden methods are not final as they can't change types (as it works in compile-time) - only create new and inherit. This example doesn't process classes with non-empty constructors and many other things. m here is instance of MethodSymbol and gives you full scala-style reflection about input class' method. You need only generate correct AST in response.
To read more about that:
macroses: http://docs.scala-lang.org/overviews/macros/overview.html
scala's runtime-reflection http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html
q"asiquotes" : http://docs.scala-lang.org/overviews/quasiquotes/expression-details.html
Another solution would be:
scala> def getClasss[T: ClassTag] = classTag[T].runtimeClass
getClasss: [T](implicit evidence$1: scala.reflect.ClassTag[T])Class[_]
Using this instance you can apply any asm/cglib/javassist or even DynamicProxy to it.

Any way to access the type of a Scala Option declaration at runtime using reflection?

So, I have a Scala class that looks like this:
class TestClass {
var value: Option[Int] = None
}
and I'm tackling a problem where I have a String value and I want to coerce it into that Option[Int] at runtime using reflection. So, in another piece of code (that knows nothing about TestClass) I have some code like this:
def setField[A <: Object](target: A, fieldName: String, value: String) {
val field = target.getClass.getDeclaredField(fieldName)
val coercedValue = ???; // How do I figure out that this needs to be Option[Int] ?
field.set(target, coercedValue)
}
To do this, I need to know that the field is an Option and that the type parameter of the Option is Int.
What are my options for figuring out that the type of 'value' is Option[Int] at runtime (i.e. using reflection)?
I have seen similar problems solved by annotating the field, e.g. #OptionType(Int.class). I'd prefer a solution that didn't require annotations on the reflection target if possible.
It's quite streightforward using Java 1.5 reflection API:
def isIntOption(clasz: Class[_], propertyName: String) = {
var result =
for {
method <- cls.getMethods
if method.getName==propertyName+"_$eq"
param <- method.getGenericParameterTypes.toList.asInstanceOf[List[ParameterizedType]]
} yield
param.getActualTypeArguments.toList == List(classOf[Integer])
&& param.getRawType == classOf[Option[_]]
if (result.length != 1)
throw new Exception();
else
result(0)
}
At the byte code level, Java hasn't got Generics. Generics are implemented with polymorphism, so once your source code (in this case Scala) is compiled, generic types disappear (this is called type erasure ). This makes no possible to gather Generic runtime type information via reflection.
A possible --though little dirty-- workaround is to obtain the runtime type of a property you know it has the same type as the Generic parameter. For Option instances we can use get member
object Test {
def main(args : Array[String]) : Unit = {
var option: Option[_]= None
println(getType(option).getName)
option = Some(1)
println(getType(option).getName)
}
def getType[_](option:Option[_]):Class[_]= {
if (option.isEmpty) classOf[Nothing] else (option.get.asInstanceOf[AnyRef]).getClass
}
}
class TestClass {
var value: Option[Int] = None
// ...
def doSomething {
value match {
case Some(i) => // i is an Int here
case None =>
// No other possibilities
}
}
}
The problem is that JVM implements generics through type erasure. So it's impossible to discover through reflection that the type of value is Option[Int] because at the run-time it actually isn't: it's just Option!
In 2.8 you should be able to use Manifests like this:
var value: Option[Int] = None
val valueManifest = implicitly[scala.reflect.Manifest[Option[Int]]]
valueManifest.typeArguments // returns Some(List(Int))