Update: I suspect that what I want might not be possible, and I've written up a blog post with my reasoning (and some alternatives) here. I'd be very happy to be told that I'm wrong.
Suppose I want to create a instance of a trait using a factory method with a macro implementation. This method will take as an argument a path to a resource that the macro will read and parse (at compile time) into a map from strings to strings.
That part is all fairly straightforward. Now suppose I want to associate the resulting map with the instance I'm creating so that I can use it in subsequent macro calls involving that instance.
I crucially do not want the map to be a member of the instance, or to exist in any form at runtime. I also don't want to parse the same resource more than once. Here's a sketch of the kind of thing I'm aiming for:
import scala.language.experimental.macros
import scala.reflect.macros.Context
trait Foo {
def lookup(key: String): String = macro Foo.lookup_impl
}
object Foo {
def parseResource(path: String): Map[String, String] = ???
def apply(path: String): Foo = macro apply_impl
def apply_impl(c: Context)(path: c.Expr[String]): c.Expr[Foo] = {
import c.universe._
val m = path.tree match {
case Literal(Constant(s: String)) => parseResource(s)
}
val tree = reify(new Foo {}).tree
// Somehow associate the map with this tree here.
c.Expr(tree)
}
def lookup_impl(c: Context)(key: c.Expr[String]): c.Expr[String] =
/* Somehow read off the map and look up this key. */ ???
}
This seems to be the sort of thing that attachments are designed to help with (thanks to Eugene Burmako for the pointer), and I've got an attachment-based implementation that allows me to write the following:
Foo("whatever.txt").lookup("x")
Where apply_impl attaches the map to the tree and lookup_impl reads that attachment off the same tree, which it sees as its prefix. Unfortunately this is more or less useless, though, since it doesn't work in the foo.lookup("x") case, where the prefix tree is just the variable foo.
(Note that in my real use case Foo extends Dynamic, and I'm trying to give a macro implementation for selectDynamic instead of lookup, but that shouldn't be relevant here—I'm interested in the general case.)
Is there some way that I can use attachments to get what I want? Is there some other approach that would be more appropriate?
UPDATE I should read the question again after fiddling... :( I just reproduced what you have.
You were quite there I think. This works for me:
object Foo {
// Attachment.get somehow needs a wrapper class.
// Probably because of generics
implicit class LookupMap(m: Map[String, String]) {
def get(s: String) = m.get(s)
}
def parseResource(path: String): LookupMap = Map("test" -> "a")
def apply_impl(c: Context)(path: c.Expr[String]): c.Expr[Foo] = {
import c.universe._
val m = path.tree match {
case Literal(Constant(s: String)) => parseResource(s)
}
val tree = reify(new Foo {}).tree.updateAttachment(m)
c.Expr(tree)
}
def lookup_impl(c: Context { type PrefixType = Foo })
(key: c.Expr[String]): c.Expr[String] = {
import c.universe._
val m = c.prefix.tree.attachments.get[LookupMap].get
val s = key.tree match {
case Literal(Constant(s: String)) => m.get(s).get
}
c.Expr(Literal(Constant(s)))
}
}
Related
I have a generic class:
class GenericType[T] {
def func(t: T) = ???
}
I need to implement a function that takes a List[String] and outputs the corresponding GenericType[T]. For example, if a client passes in List("SomeType1", "SomeType2"), the function should return List(GenericType[SomeType1], GenericType[SomeType2]). Basically, there's a string that maps to a type.
I don't find a good way to represent the return type for such function. Seq[GenericType[_]] as the return type can be an option but it requires the client to cast it into corresponding subclasses to invoke func as the type info is lost.
Alternatively, a case class can be used but this is not flexible as I need to modify the case class every time a new subclass is added.
case class (s1: Option[GenericType[SomeType1]] = None, s2: Option[SomeType2] = None, ...)
I'm curious what's a good way to represent the return type?
The easiest is
def stringToGenericType(s: String): GenericType[_] = s match {
case "SomeType1" => new GenericType[SomeType1]
case "SomeType2" => new GenericType[SomeType2]
}
GenericType[_] (or GenericType[Any] if you make GenericType covariant: class GenericType[+T]) would be an honest return type. You can't know at compile time which specific GenericType[...] you return based on a runtime string. Anyway you can't avoid casting somewhere because you can't guarantee the type statically. Anyway this kind of programming can't be type-safe.
Since we're doing a choice based on a runtime string, compile-time techniques (macros, implicits, Shapeless) are off the table. (*)
Actually, currently you don't need even runtime reflection. Your class GenericType[T] and method func in it seem not to do anything at runtime differently depending on type T. GenericType[SomeType1] and GenericType[SomeType2] are just GenericType[_] at runtime. So even the following implementation is possible
def stringToGenericType(s: String): GenericType[_] = new GenericType[Any]
Another situation would be if you created instances of different classes
class GenericType1[T]
class GenericType2[T]
import scala.reflect.runtime
import scala.reflect.runtime.universe._
val runtimeMirror = runtime.currentMirror
def stringToGenericTypeX(s: String): Any = {
val classSymbol = runtimeMirror.staticClass(s)
val constructorSymbol = classSymbol.typeSignature.decl(termNames.CONSTRUCTOR).asMethod
runtimeMirror.reflectClass(classSymbol).reflectConstructor(constructorSymbol).apply()
}
or you called different methods
class GenericType[T] {
def func1(t: T) = ???
def func2(t: T) = ???
}
def callFuncX(methodName: String, t: Any) = {
val classSymbol = runtimeMirror.classSymbol(classOf[GenericType[_]])
val methodSymbol = classSymbol.typeSignature.decl(TermName(methodName)).asMethod
runtimeMirror.reflect(new GenericType[Any]).reflectMethod(methodSymbol).apply(t)
}
or something behaved at runtime differently depending on type T
class GenericType[T: ClassTag] {
def func(t: T) = println(classTag[T].runtimeClass)
}
import scala.tools.reflect.ToolBox
val toolbox = runtimeMirror.mkToolBox()
def stringToGenericType(s: String): GenericType[_] = {
toolbox.eval(q"new GenericType[${TypeName(s)}]").asInstanceOf[GenericType[_]]
}
(*) Well, actually the first pattern matching (as I wrote it) can be automated with a macro
// in a different subproject
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def stringToGenericType(s: String): GenericType[_] = macro stringToGenericTypeImpl
def stringToGenericTypeImpl(c: blackbox.Context)(s: c.Tree): c.Tree = {
import c.universe._
val cases = List("SomeType1", "SomeType2").map(str =>
cq"$str => new GenericType[${TypeName(str)}]"
)
q"$s match { case ..$cases }"
}
val s = "SomeTime1"
stringToGenericType(s)
// scalacOptions += "-Ymacro-debug-lite"
//s match {
// case "SomeType1" => new GenericType[SomeType1]()
// case "SomeType2" => new GenericType[SomeType2]()
//}
Does Scala have any equivalent to GCC's typeofextension? (Or C++ decltype?)
I'm generating code that references some external code (which may not be available yet), and I need a way to reference the type of that code in a method definition
For singleton objects, I could use Foo.type, but if Foo is an arbitrary expression, that doesn't work.
Update:
Here is a simplified example that shows the problem:
def f(x: typeof(Foo))(implicit M: Monoid[typeof(Foo)]) =
M.append(Foo, M.append(x, Foo))
The code I am working on doesn't know anything about Foo other than that it is a string representation of a Scala expression. It is outputting the above code to a .scala file which is to be later compiled as part of a separate project.
Of course the typeof(Foo) bits don't work. Using Foo.type would work only if Foo is a singleton.
Basically, I want to know if there is something I could substitute in place of typeof(Foo) that would work for arbitrary Scala expressions.
In Scala there is no typeof of that sort.
We can try to modify the method adding type parameter
def f[F](foo: F)(x: F)(implicit M: Monoid[F]) =
M.append(foo, M.append(x, foo))
and call it like f(Foo)(...), where Foo is the expression to be substituted, then F should be inferred upon compilation.
Otherwise I can imagine the following workflow. We could generate string represenation of the type of expression Foo from string represenation of Foo itself with Scalameta's SemanticDB and then insert string representation of expression Foo and this generated string represenation of the type.
One more option is to generate tree with macro annotation
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
class generate(foo: String) extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro generateMacro.impl
}
object generateMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val str: String = c.prefix.tree match {
case q"new generate($s)" => c.eval[String](c.Expr(s))
}
val tree = c.typecheck(c.parse(str))
val tpe = tree.tpe.widen
annottees match {
case q"$mods def $name[..$_](...$_): $_ = $_" :: _ =>
q"""
$mods def $name(x: $tpe)(implicit M: Monoid[$tpe]): $tpe =
M.append($tree, M.append(x, $tree))
"""
}
}
}
#generate("1 + 1")
def f(): Unit = ()
// def f(x: Int)(implicit M: Monoid[Int]): Int = M.append(2, M.append(x, 2))
https://github.com/travisbrown/type-provider-examples/
https://docs.scala-lang.org/overviews/macros/typeproviders.html
Actually I guess this is close to what was asked
class TypeOf[A](a: A) {
type T = A
}
val tp = new TypeOf(Foo)
def f(x: tp.T)(implicit M: Monoid[tp.T]) = M.append(Foo, M.append(x, Foo))
Do you have a reference class for the type you want to use? Else define a custom class, and use:
classOf [Class_Name]
is equivalent typeOf
And if you re trying to know the class of your custom object, then use:
object_name.getClass
I'm trying to remove some of the boilerplate in an API I am writing.
Roughly speaking, my API currently looks like this:
def toEither[E <: WrapperBase](priority: Int)(implicit factory: (String, Int) => E): Either[E, T] = {
val either: Either[String, T] = generateEither()
either.left.map(s => factory(s, priority))
}
Which means that the user has to generate an implicit factory for every E used. I am looking to replace this with a macro that gives a nice compile error if the user provided type doesn't have the correct ctor parameters.
I have the following:
object GenericFactory {
def create[T](ctorParams: Any*): T = macro createMacro[T]
def createMacro[T](c: blackbox.Context)(ctorParams: c.Expr[Any]*)(implicit wtt: WeakTypeType[T]): c.Expr[T] = {
import c.universe._
c.Expr[T](q"new $wtt(..$ctorParams)")
}
}
If I provide a real type to this GenericFactory.create[String]("hey") I have no issues, but if I provide a generic type: GenericFactory.create[E]("hey") then I get the following compile error: class type required by E found.
Where have I gone wrong? Or if what I want is NOT possible, is there anything else I can do to reduce the effort for the user?
Sorry but I don't think you can make it work. The problem is that Scala (as Java) uses types erasure. It means that there is only one type for all generics kinds (possibly except for value-type specializations which is not important now). It means that the macro is expanded only once for all E rather then one time for each E specialization provided by the user. And there is no way to express a restriction that some generic type E must have a constructor with a given signature (and if there were - you wouldn't need you macro in the first place). So obviously it can not work because the compiler can't generate a constructor call for a generic type E. So what the compiler says is that for generating a constructor call it needs a real class rather than generic E.
To put it otherwise, macro is not a magic tool. Using macro is just a way to re-write a piece of code early in the compiler processing but then it will be processed by the compiler in a usual way. And what your macro does is rewrites
GenericFactory.create[E]("hey")
with something like
new E("hey")
If you just write that in your code, you'll get the same error (and probably will not be surprised).
I don't think you can avoid using your implicit factory. You probably could modify your macro to generate those implicit factories for valid types but I don't think you can improve the code further.
Update: implicit factory and macro
If you have just one place where you need one type of constructors I think the best you can do (or rather the best I can do ☺) is following:
Sidenote the whole idea comes from "Implicit macros" article
You define StringIntCtor[T] typeclass trait and a macro that would generate it:
import scala.language.experimental.macros
import scala.reflect.macros._
trait StringIntCtor[T] {
def create(s: String, i: Int): T
}
object StringIntCtor {
implicit def implicitCtor[T]: StringIntCtor[T] = macro createMacro[T]
def createMacro[T](c: blackbox.Context)(implicit wtt: c.WeakTypeTag[T]): c.Expr[StringIntCtor[T]] = {
import c.universe._
val targetTypes = List(typeOf[String], typeOf[Int])
def testCtor(ctor: MethodSymbol): Boolean = {
if (ctor.paramLists.size != 1)
false
else {
val types = ctor.paramLists(0).map(sym => sym.typeSignature)
(targetTypes.size == types.size) && targetTypes.zip(types).forall(tp => tp._1 =:= tp._2)
}
}
val ctors = wtt.tpe.decl(c.universe.TermName("<init>"))
if (!ctors.asTerm.alternatives.exists(sym => testCtor(sym.asMethod))) {
c.abort(c.enclosingPosition, s"Type ${wtt.tpe} has no constructor with signature <init>${targetTypes.mkString("(", ", ", ")")}")
}
// Note that using fully qualified names for all types except imported by default are important here
val res = c.Expr[StringIntCtor[T]](
q"""
(new so.macros.StringIntCtor[$wtt] {
override def create(s:String, i: Int): $wtt = new $wtt(s, i)
})
""")
//println(res) // log the macro
res
}
}
You use that trait as
class WrapperBase(val s: String, val i: Int)
case class WrapperChildGood(override val s: String, override val i: Int, val float: Float) extends WrapperBase(s, i) {
def this(s: String, i: Int) = this(s, i, 0f)
}
case class WrapperChildBad(override val s: String, override val i: Int, val float: Float) extends WrapperBase(s, i) {
}
object EitherHelper {
type T = String
import scala.util._
val rnd = new Random(1)
def generateEither(): Either[String, T] = {
if (rnd.nextBoolean()) {
Left("left")
}
else {
Right("right")
}
}
def toEither[E <: WrapperBase](priority: Int)(implicit factory: StringIntCtor[E]): Either[E, T] = {
val either: Either[String, T] = generateEither()
either.left.map(s => factory.create(s, priority))
}
}
So now you can do:
val x1 = EitherHelper.toEither[WrapperChildGood](1)
println(s"x1 = $x1")
val x2 = EitherHelper.toEither[WrapperChildGood](2)
println(s"x2 = $x2")
//val bad = EitherHelper.toEither[WrapperChildBad](3) // compilation error generated by c.abort
and it will print
x1 = Left(WrapperChildGood(left,1,0.0))
x2 = Right(right)
If you have many different places where you want to ensure different constructors exists, you'll need to make the macro much more complicated to generate constructor calls with arbitrary signatures passed from the outside.
Ideally I'd like to be able to do the following in Scala:
import Builders._
val myBuilder = builder[TypeToBuild] // Returns instance of TypeToBuildBuilder
val obj = myBuilder.methodOnTypeToBuildBuilder(...).build()
In principle the goal is simply to be able to 'map' TypeToBuild to TypeToBuildBuilder using external mapping definitions (i.e. assume no ability to change these classes) and leverage this in type inferencing.
I got the following working with AnyRef types:
import Builders._
val myBuilder = builder(TypeToBuild)
myBuilder.methodOnTypeToBuildBuilder(...).build()
object Builders {
implicit val typeToBuildBuilderFactory =
new BuilderFactory[TypeToBuild.type, TypeToBuildBuilder]
def builder[T, B](typ: T)(implicit ev: BuilderFactory[T, B]): B = ev.create
}
class BuilderFactory[T, B: ClassTag] {
def create: B = classTag[B].runtimeClass.newInstance().asInstanceOf[B]
}
Note that the type is passed as a function argument rather than a type argument.
I'd be supremely happy just to find out how to get the above working with Any types, rather than just AnyRef types. It seems this limitation comes since Singleton types are only supported for AnyRefs (i.e. my use of TypeToBuild.type).
That being said, an answer that solves the original 'ideal' scenario (using a type argument instead of a function argument) would be fantastic!
EDIT
A possible solution that requires classOf[_] (would really love not needing to use classOf!):
import Builders._
val myBuilder = builder(classOf[TypeToBuild])
myBuilder.methodOnTypeToBuildBuilder(...).build()
object Builders {
implicit val typeToBuildBuilderFactory =
new BuilderFactory[classOf[TypeToBuild], TypeToBuildBuilder]
def builder[T, B](typ: T)(implicit ev: BuilderFactory[T, B]): B = ev.create
}
class BuilderFactory[T, B: ClassTag] {
def create: B = classTag[B].runtimeClass.newInstance().asInstanceOf[B]
}
Being able to just use builder(TypeToBuild) is really just a win in elegance/brevity. Being able to use builder[TypeToBuild] would be cool as perhaps this could one day work (with type inference advancements in Scala):
val obj: TypeToBuild = builder.methodOnTypeToBuildBuilder(...).build();
Here is a complete, working example using classOf: http://ideone.com/94rat3
Yes, Scala supports return types based on the parameters types. An example of this would be methods in the collections API like map that use the CanBuildFrom typeclass to return the desired type.
I'm not sure what you are trying to do with your example code, but maybe you want something like:
trait Builder[-A, +B] {
def create(x: A): B
}
object Builders {
implicit val int2StringBuilder = new Builder[Int, String] {
def create(x: Int) = "a" * x
}
def buildFrom[A, B](x: A)(implicit ev: Builder[A, B]): B = ev.create(x)
}
import Builders._
buildFrom(5)
The magic with newInstance only works for concrete classes that have a constructor that takes no parameters, so it probably isn't generic enough to be useful.
If you're not afraid of implicit conversions, you could do something like this:
import scala.language.implicitConversions
trait BuilderMapping[TypeToBuild, BuilderType] {
def create: BuilderType
}
case class BuilderSpec[TypeToBuild]()
def builder[TypeToBuild] = BuilderSpec[TypeToBuild]
implicit def builderSpecToBuilder[TypeToBuild, BuilderType]
(spec: BuilderSpec[TypeToBuild])
(implicit ev: BuilderMapping[TypeToBuild, BuilderType]) = ev.create
case class Foo(count: Int)
case class FooBuilder() {
def translate(f: Foo) = "a" * f.count
}
implicit val FooToFooBuilder = new BuilderMapping[Foo, FooBuilder] {
def create = FooBuilder()
}
val b = builder[Foo]
println(b.translate(Foo(3)))
The implicit conversions aren't too bad, since they're constrained to these builder-oriented types. The conversion is needed to make b.translate valid.
It looked like wingedsubmariner's answer was most of what you wanted, but you didn't want to specify both TypeToBuild and BuilderType (and you didn't necessarily want to pass a value). To achieve that, we needed to break up that single generic signature into two parts, which is why the BuilderSpec type exists.
It might also be possible to use something like partial generic application (see the answers to a question that I asked earlier), though I can't put the pieces together in my head at the moment.
I'll resort to answering my own question since a Redditor ended up giving me the answer I was looking for and they appear to have chosen not to respond here.
trait Buildable[T] {
type Result
def newBuilder: Result
}
object Buildable {
implicit object ABuildable extends Buildable[A] {
type Result = ABuilder
override def newBuilder = new ABuilder
}
implicit object BBuildable extends Buildable[B] {
type Result = BBuilder
override def newBuilder = new BBuilder
}
}
def builder[T](implicit B: Buildable[T]): B.Result = B.newBuilder
class ABuilder {
def method1() = println("Call from ABuilder")
}
class BBuilder {
def method2() = println("Call from BBuilder")
}
Then you will get:
scala> builder[A].method1()
Call from ABuilder
scala> builder[B].method2()
Call from BBuilder
You can see the reddit post here: http://www.reddit.com/r/scala/comments/2542x8/is_it_possible_to_define_a_function_return_type/
And a full working version here: http://ideone.com/oPI7Az
I'm attempting to write a macro that would wrap a function and deducting a parameter from the value its invocation will be assigned to.
object TestMacros {
def foo(name: String): String = name.toUpper
def bar = macro barImpl
def barImpl(c: Context): c.Expr[String] = {
import c.universe._
//TODO extract value name (should be baz)
c.Expr[String](Apply(
Select(newTermName("TestMacros"), newTermName("foo")), // Probably wrong, just typed it quickly for demonstration purposes
List(Literal(Constant("test"))))) // Should replace test by value name
}
}
object TestUsage {
val baz = bar // should be BAZ
}
I don't know if this is clear enough. I've investigated both c.prefix and c.macroApplication without success. I'm using Scala 2.10.2 without the macro-paradise compiler plugin.
This is very possible. I know, because I've done something like it before. The trick is to search the enclosing tree for a value whose right-hand side has the same position as the macro application:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object TestMacros {
def foo(name: String): String = name.toUpperCase
def bar = macro barImpl
def barImpl(c: Context): c.Expr[String] = {
import c.universe._
c.enclosingClass.collect {
case ValDef(_, name, _, rhs)
if rhs.pos == c.macroApplication.pos => c.literal(foo(name.decoded))
}.headOption.getOrElse(
c.abort(c.enclosingPosition, "Not a valid application.")
)
}
}
And then:
scala> object TestUsage { val baz = TestMacros.bar }
defined module TestUsage
scala> TestUsage.baz
res0: String = BAZ
scala> class TestClassUsage { val zab = TestMacros.bar }
defined class TestClassUsage
scala> (new TestClassUsage).zab
res1: String = ZAB
Note that you can apply foo at compile-time, since you know the name of the val at compile-time. If you wanted it to be applied at runtime that would also be possible, of course.
I had a similar problem when I wanted to simplify some property initializations. So your code helped me to find out how that is possible, but I got deprecation warnings. As scala macros evolve the enclosingClass got deprecated in Scala 2.11. The documentation states to use c.internal.enclosingOwner instead. The quasiquotes feature makes things easier now - my sample to retrieve just the name as in val baz = TestMacros.getName looks like this:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
object TestMacros {
def getName(): String = macro getNameImpl
def getNameImpl(c: Context)() = {
import c.universe._
val term = c.internal.enclosingOwner.asTerm
val name = term.name.decodedName.toString
// alternatively use term.fullName to get package+class+value
c.Expr(q"${name}")
}
}