Retrieve generic trait parameter on concrete inheritor via macro - scala

I have a simple subtyping relation that I've set up as follows:
trait Foo[T] {
def a: Int
def b: String
def c: T
}
object Bar extends Foo[C] { /* implementation */ }
object Quux extends Foo[D] { /* implementation */ }
// ...
where C and D are concrete types. I also have a manager object that registers objects of type Foo[T] and needs to maintain generic type information in order to correctly call method c.
The scala compiler seems incapable of correctly inferring types here for my manager's register method, so I need to specify that manually. I.e., I can't do
Manager register Bar
but instead have to provide
Manager register[C, Bar.type] Bar
To make this a bit prettier, I'm writing a macro that does this automatically, but I'm stuck on retrieving the concrete type parameter of the trait the object inherits from. The basic form of the macro looks like this:
def macro_impl[T: c.WeakTypeTag](c: whitebox.Context)(a: c.Expr[T]): c.Expr[Unit] = {
import c.universe._
val typeIWant = weakTypeOf[T].???
c.Expr[Unit](q"com.example.Manager.register[${a.actualType}, ${typeIWant}]($a)")
}
I've been able to retrieve the list of supertypes of T, but I haven't been able to figure out how to get the type parameter for those types within the object declaration, i.e. I'm looking for U here: object ... extends Foo[U]). Is there a way to do this?
Edit: I can get the type information I want to show up in the console via reflection:
scala> typeOf[Bar].typeSymbol.info
res1: reflect.runtime.universe.Type =
com.example.Foo[com.example.C] {
def <init>(): com.example.Bar
def a: scala.Int
def b: String
def c(event: com.example.C): scala.Unit
}
but I'm still not sure how to get information about the com.example.Foo[com.example.C] part of the signature. Not finding anything pertinent in the reflection API docs (particularly TypeApi) about how to do this.

Related

Context bound in Scala

I am learning Context bound in Scala.
In the below code, I am invoking multiplication operator on the integer parameter. But it errors out. 'a' is considered as type parameter; but it is actually not as per my understanding. Can someone please help.
scala> class Sample[T]
defined class Sample
scala> def method[Int:Sample](a:Int) = a * a
<console>:12: error: value * is not a member of type parameter Int
def method[Int:Sample](a:Int) = a * a
Thanks!
Context bounds are syntactic sugar for implicit generic parameters that are parameterized by some type you're using. This concept is also known as "type class". You define some generic trait, such as your Sample[T], and then you provide implicit(!) instances of that trait for various concrete values of T. We call them "type class instances".
Why implicit? It's an implementation detail that Scala uses to achieve the type class mechanism; type classes also exist in e.g. Haskell, but the mechanism itself is a bit different. Anyways, you can then define a method such as your def method which requires a type class instance for some type. And you can do this with context bound syntax, or with a more verbose and more explicit standard syntax for implicit parameters.
Your definition is using the context bound. But there is something wrong with your example, as indicated by the compilation error. Let's first see a proper example that uses the type class concept correctly.
// type class definition:
trait Sample[T] {
def getSample: T
}
// type class instance(s):
object Sample {
implicit val sampleInt: Sample[Int] =
new Sample[Int] { def getSample = 42 }
}
And now the usage:
import Sample._
// using the context bound syntax
def method1[T : Sample](t: T) = t.getSample
// not using the context bound syntax
def method2(t: T)(implicit ev: Sample[T]) = t.getSample
What we're doing is saying - there is some value t of type T, we don't know much about it, but what we do know is that there is a Sample type class instance available for it. This allows us to do t.getSample.
And now, to finally provide the answer to your problem:
In your code, you are mixing things up. Your T is actually called Int. You intended to use the Int type, but what you did instead is that you named your generic parameter Int. I could have answered this with way less text, but I figured perhaps you would find the bigger picture interesting, rather than just pointing out the mistake.
The type parameter named Int does not represent concrete integer type scala.Int. Instead it is just a confusing coincidence that the type parameter was given the same name Int as the concrete type. If you give it some other name such as T
def method[T: Sample](a: T): T = a * a
the error message should make more sense. Now we see * is not defined for T since Sample type class does not yet provide such capability. Here is an example of how correct syntactic usage might look usage
trait Sample[T] {
def mult(a: T, b: T): T
}
def method[T: Sample](a: T): T = implicitly[Sample[T]].mult(a, a)
def method[T](a: T)(implicit ev: Sample[T]): T = ev.mult(a, a)
You could also have a look at Numeric type class which provides such functionality out of the box
def method[T](a: T)(implicit num: Numeric[T]): T = num.times(a, a)
Your method has a type parameter called Int which shadows the actual Int, just like defining a normal variable would shadow something from an outer scope. The same would happen if you remove the context bound.
What you are probably trying to do is something closer to the following:
trait Sample[A] {
def someOperation(a1: A, a2: A): A
}
implicit object IntSample extends Sample[Int] {
override def someOperation(a1: Int, a2: Int): Int = a1 * a2
}
def method[T: Sample](t: T) = implicitly[Sample[T]].someOperation(t, t)
method(4) // compiles and returns 16
//method("4") // doesn't compile, no implicit instance of Sample[String] in scope
You can play around with this code here on Scastie.

Can I use Scala's Dynamic to programmatically create an object instance of some trait?

I have a list of method signatures of some trait T given as objects, similar to the following, ignoring arity:
case class Method[T,A,B](name: String, f: T => A => B)
So given some trait T, this could look like:
trait T{
def foo(i: Int): String
def bar(s: String): Unit
}
def methodsOfT: Seq[Method[T,_,_]] = Seq(
Method("foo", t => i => t.foo(i)),
Method("bar", t => s => t.bar(s))
)
I want to create an instance of type T, or of the class associated with T, whatever, that uses a dictionary of Method objects to implement T's interface.
It could look like the following (this won't compile):
def reify[T](impl: T, methods: Method[T,_,_]): T = (new Object with Dynamic {
def applyDynamic(method: String)(args: Any*): Any = {
//do something here
}
}).asInstanceOf[T] //<- will fail at runtime
Of course the returned object is of type Object, and cannot be cast to type/class T. Is there any way to work around this problem?
Why I want to do this
I have a trait T for which I want to create a remote invocation interface. On the client side, I need an instance of T that forwards method invocations over a network connection. I could implement this RemoteT. But the code is completely boilerplate.
new T {
def foo(i: Int): String =
methodsOfT.find(_.name == "foo").get.f(i).asInstanceOf[String]
def bar(s: String): Unit =
methodsOfT.find(_.name == "bar").get.f(s).asInstanceOf[Unit]
}
I think I could use macros to synthesize the method overrides and forward them to the network remote handler. But I'm still trying to avoid macros.
P.S.
The following question is very related. I'm currently exploring this approach:
Java Reflection: Create an implementing class
I believe similar thing is done in shapeless to implement lenses.
Here you can see that dynamics delegate creation of lens to an implicit - returned type is taken from functional depenencies (here: that mkLens.Out)
trait Lens[S, A] extends LPLens[S, A] { outer =>
...
def selectDynamic(k: String)
(implicit mkLens: MkSelectDynamicOptic[Lens[S, A], A, Symbol ## k.type, Nothing]): mkLens.Out = mkLens(this)
...
}
the Lens itself is not generated with macro, but with normal derivation, but you can use macro to generate implicit, it should be possible.
object Generic1 extends Generic10 {
...
implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] =
macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[t, U] })#λ]
...
}
A combination of macro + dynamics is used in HList.
object HList extends Dynamic {
...
/**
* Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows,
*
* {{{
* type ISB = HList.`Int, String, Boolean`.T
* }}}
*
* Literal types are allowed, so that the following is valid,
*
* {{{
* type ABC = HList.`'a, 'b, 'c`.T
* type TwoTrueStr = HList.`2, true, "str"`.T
* }}}
*/
def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.hlistTypeImpl
...
}
All in all, you should be able to achieve you goal. It all just depends on how exactly you want to instantiate you object - e.g. take implicit ClassTag and call constructor using reflection or maybe constructing HList and using Generic to turn it into an specific representation or maybe some something else.

Automatic higher kinded type inference within generic methods

I'm struggeling a bit with higher kinded types and complilers type inference...
I do have the following classes:
sealed trait Foo[A] {
#JsonProperty val payload : List[A] = Nil
}
class Baa extends Foo[MyCoolClassOne]
class FooBaa extends Foo[MyCoolClassTwo]
Now i have a function, that calls a REST-API to get either a JSON-response representing Baa or FooBaa (or other subclasses of Foo, just mention 2 of them for this example).
def getContent[A, F <: Foo[A]](url: String) : List[A] = {
// call API
// use com.fasterxml.jackson.databind.ObjectMapper to deserialize
// psuedo code...
val response = mapper.readValue(responseFromAPI, classTag.runtimeClass.asInstanceOf[Class[F]])
return response.payload
}
I could then call the API to get my content:
def getBaa(urlToBaa:String) = getContent[MyCoolClassOne, Baa](urlToBaa)
or
def getFooBaa(urlToFooBaa:String) = getContent[MyCoolClassTwo, FooBaa](urlToFooBaa)
The question
Why do i need to pass both classTags to funtion getContent?
How can i avoid this?
My thoughts
Foo is a sealed trait. There are (in this example) only 2 classes extending it. Both classes are extending Foo with a specific type. Why is the compiler unable to infer the type correct, if i would define the function somethign like this:
def getContent[F <: Foo[A]](url: String) : List[A] = { ... }
i know, that the compiler will look for a class 'A' in this case. But how could i tell him, that it is the typeinformation of the subclass of Foo.
Or to be more precise, i don't care about the method declaration, but to pass an 'obvious' typeinformation to the function, each time i call it, is very annoing.

Scala Type Classes Best Practices

I'm reading through and working my way through using type classes and I came across this way of defining type classes from the Shapeless guide:
So here goes the example:
object CsvEncoder {
// "Summoner" method
def apply[A](implicit enc: CsvEncoder[A]): CsvEncoder[A] =
enc
// "Constructor" method
def instance[A](func: A => List[String]): CsvEncoder[A] =
new CsvEncoder[A] {
def encode(value: A): List[String] =
func(value)
}
// Globally visible type class instances
}
What I do not understand is the need for the apply method? What is it doing in this context above?
Later on, the guide describes how I could create a type class instance:
implicit val booleanEncoder: CsvEncoder[Boolean] =
new CsvEncoder[Boolean] {
def encode(b: Boolean): List[String] =
if(b) List("yes") else List("no")
}
is actually shortened to:
implicit val booleanEncoder: CsvEncoder[Boolean] =
instance(b => if(b) List("yes") else List("no"))
So my question now is, how does this work? What I do not get is the need for the apply method?
EDIT: I came across a blog post that describes the steps in creating type classes as below:
Define typeclass contract trait Foo.
Define a companion object Foo with a helper method apply that acts like implicitly, and a way of defining Foo instances typically from a function.
Define FooOps class that defines unary or binary operators.
Define FooSyntax trait that implicitly provides FooOps from a Foo instance.
So what is the deal with point number 2, 3 and 4?
Most of those practices came from Haskell (basically an intention to mimic Haskell's type-classes is a reason for so much boilerplate), some of it is just for convenience. So,
2) As #Alexey Romanov mentioned, companion object with apply is just for convenience, so instead of implicitly[CsvEncoder[IceCream]] you could write just CsvEncoder[IceCream] (aka CsvEncoder.apply[IceCream]()), which will return you a required type-class instance.
3) FooOps provides convenience methods for DSLs. For instance you could have something like:
trait Semigroup[A] {
...
def append(a: A, b: A)
}
import implicits._ //you should import actual instances for `Semigroup[Int]` etc.
implicitly[Semigroup[Int]].append(2,2)
But sometimes it's inconvenient to call append(2,2) method, so it's a good practice to provide a symbolic alias:
trait Ops[A] {
def typeClassInstance: Semigroup[A]
def self: A
def |+|(y: A): A = typeClassInstance.append(self, y)
}
trait ToSemigroupOps {
implicit def toSemigroupOps[A](target: A)(implicit tc: Semigroup[A]): Ops[A] = new Ops[A] {
val self = target
val typeClassInstance = tc
}
}
object SemiSyntax extends ToSemigroupOps
4) You can use it as follows:
import SemiSyntax._
import implicits._ //you should also import actual instances for `Semigroup[Int]` etc.
2 |+| 2
If you wonder why so much boilerplate, and why scala's implicit class syntax doesn't provide this functionality from scratch - the answer is that implicit class actually provides a way to create DSL's - it's just less powerful - it's (subjectively) harder to provide operation aliases, deal with more complex dispatching (when required) etc.
However, there is a macro solution that generates boilerplate automatically for you: https://github.com/mpilquist/simulacrum.
One another important point about your CsvEncoder example is that instance is convenience method for creating type-class instances, but apply is a shortcut for "summoning" (requiring) those instances. So, first one is for library extender (a way to implement interface), another one is for a user (a way to call a particular operation provided for that interface).
Another thing to note is that in shapeless the apply method is not only for cuter syntax.
Take for instance this simplified version of shapeless' Generic and some case class Foo.
trait Generic[T] {
type Repr
}
object Generic {
def apply[T](implicit gen: Generic[T]): Generic[T] { type Repr = gen.Repr } = gen
/* lots of macros to generate implicit instances omitted */
}
case class Foo(a: Int, b: String)
Now when I call Generic[Foo] I will get an instance that is typed as Generic[Foo] { type Repr = Int :: String :: HNil }. But if I call implicitly[Generic[Foo]] all the compiler knows about the result is that it's a Generic[Foo]. In other words: the concrete type of Repr is lost and I can't do anything useful with it. The reason is that implicitly is implemented as follows:
def implicitly[T](implicit e: T): T = e
That method declaration basically says: if you ask for a T I promise to give you a T, if I find one, and nothing more. So that means you'd have to ask implicitly[Generic[Foo] { type Repr = Int :: String :: HNil }] and that defeats the purpose of having automatic derivation.
Quoting the guide immediately after the object CsvEncoder definition:
The apply method ... allows us to summon a type class instance given a target type:
CsvEncoder[IceCream]
// res9: CsvEncoder[IceCream] = ...

Simulate partial type parameter inference with implicits?

I'm making a simple dependency injection framework, for constructor injection, in Scala. The idea is that objects that are DI'd put their required services in their constructor like regular parameters, and implement a typeclass that determines which of their arguments are taken from the container and which are passed by the user on instantiation.
So, it should look something like:
trait Container {
private singletons: Map[Class, AnyRef]
def getSingleton[T: Manifest] =
singletons(implicitly[Manifest[T]].erasure).asInstanceOf[T]
... methods for adding singletons, etc ...
}
class Foo(arg: String, svc: FooService) {
...
}
trait Constructor[T] { ??? }
object FooConstructor extends Constructor[Foo] {
def construct(arg: String)(implicit container: Container) =
new Foo(arg, container.getSingleton[FooService])
}
Now basically I'd like to be able to have a method called construct, which I can call as construct[Foo]("asd") and get a new instance of Foo with "asd" passed in to the constructor, and FooService gotten from the local container and passed in to the constructor. The idea is that it should grab the instance of the Constructor type class for Foo and in a typesafe way, know the number and types of arguments it should have. Also, and this is the hard part, I don't want to have to write out the types of the arguments - just the object to be constructed.
I've tried a couple things:
trait Constructor1[T, A] {
def construct(arg: A): T
}
trait Constructor2[T, A1, A2] {
def construct(arg1: A1, arg2: A2): T
}
def construct[T, A](arg1: A): T = implicitly[Constructor1[T, A]].construct(arg1)
...
This approach doesn't work though because it seems like in order to "summon" the Constructor type class instance, we need to write the types of the arguments, which is a lot of nasty boilerplate:
construct[Foo, String]("asd") // yuck!
Is there a way to use type classes (or anything else) to sort of partially infer the type parameters? We have the types of the constructor parameters for Foo defined in the Constructor instance definition, so if we can summon the instance we should be able to just call construct and get the right argument types. The issue is getting that instance without having to specify the constructor type arguments. I've played around with a bunch of different ideas for this, and I feel like with Scala's power and bag of tricks there just has to be a way I can write construct[Foo]("asd") and have the argument list be type safe. Any ideas?
UPDATE: Thanks to Miles Sabin's excellent answer + a slight modification, here's a method that only requires one type parameter and works for all different argument list lengths. This is a pretty simple way to painlessly wire up dependencies, without the cost of reflection:
trait Constructor1[T, A] { def construct(arg1: A)(implicit c: Container): T }
trait Constructor2[T, A, B] { def construct(arg1: A, arg2: B)(implicit c: Container): T }
implicit object FooConstructor extends Constructor1[Foo, String] {
def construct(arg1: String)(implicit c: Container) =
new Foo(arg1, c.getSingleton[FooService])
}
implicit object BarConstructor extends Constructor2[Bar, String, Int] {
def construct(arg1: String, arg2: Int)(implicit c: Container) =
new Bar(arg1, arg2, c.getSingleton[FooService])
}
class Construct[T] {
def apply[A](arg1: A)(implicit ctor: Constructor1[T, A], container: Container) =
ctor.construct(arg1)
def apply[A, B](arg1: A, arg2: B)(implicit ctor: Constructor2[T, A, B], container: Container) =
ctor.construct(arg1, arg2)
}
def construct[T] = new Construct[T]
construct[Foo]("asd")
construct[Bar]("asd", 123)
Type parameter inference in Scala is an all or nothing affair: if you explicitly supply any of the type arguments for a type parameter block then you must supply them all. Consequently, if you want to supply only some of a set of type arguments you must arrange for them to belong to separate type parameter blocks.
The way to do that in this case is to split the construct method into two stages: the first, which takes an explicit type argument and returns a function-like value; and a second, which applies the function-like value to the arguments for which you want the types to be inferred.
Here's how it might go,
// Function-like type
class Construct1[T] {
def apply[A](arg1: A)(implicit ctor : Constructor1[T, A]): T =
ctor.construct(arg1)
}
def construct[T] = new Construct1[T]
The result of invoking construct[Foo] is a value of type Construct1[Foo]. This has an apply method with a type parameter, which can be inferred, and an implicit parameter whose type is determined by both T and A. The invocation you want to make now looks like,
construct[Foo].apply("asd") // T explicit, A inferred as String
Scala's semantic sugaring rules around apply applies here which mean that this can be rewritten as,
construct[Foo]("asd")
which is exactly the result you want.
trait Construct[T, A] {
def apply(arg: A): T
}
class Constructor[T]{
def apply[A](arg : A)(implicit construct : Construct) = construct(arg)
}
object Constructor {
def apply[T] = new Constructor[T]
}
Constructor[T]("arg")