I'm a bit new to Scala and I'm trying to write a generic client for a RESTful api I would like to use. I'm able to provide concrete Reads[T] and Writes[T] for the specific case classes I would like to instantiate my client for, however the compiler expects to find a Reads[T] and Writes[T] for any type, not just the types I'm using. Some code to illustrate (I've omitted irrelevant sections):
My generic client:
class RestModule[T](resource: String, config: Config) ... with JsonSupport{
...
def create(item: T): Future[T] = {
val appId = config.apiId
val path = f"/$apiVersion%s/applications/$appId%s/$resource"
Future {
val itemJson = Json.toJson(item)
itemJson.toString.getBytes
} flatMap {
post(path, _)
} flatMap { response =>
val status = response.status
val contentType = response.entity.contentType
status match {
case Created => contentType match {
case ContentTypes.`application/json` => {
Unmarshal(response.entity).to[T]
}
case _ => Future.failed(new IOException(f"Wrong Content Type: $contentType"))
}
case _ => Future.failed(new IOException(f"HTTP Error: $status"))
}
}
...
}
JsonSupprt Trait:
trait JsonSupport {
implicit val accountFormat = Json.format[Account]
}
I'm only ever instantiating as RestModule[Account]("accounts",config) but I get the error
Error:(36, 32) No Json serializer found for type T. Try to implement an implicit Writes or Format for this type.
val itemJson = Json.toJson(item)
^
Why does the compiler think it needs a Writes for type T when T can only ever be of type Account? Is there any way to work around this?
The reason why the compiler doesn't like what you're doing is to do with how implicit parameters are resolved and more crucially when they are resolved.
Consider the snippet,
Object MyFunc {
def test()(implicit s: String): String = s
}
The implicit parameter only gets resolved by the parameter when the function is called, and basically is expanded as,
MyFunc.test()(resolvedImplicit)
In your particular case you actually call the function requiring the implicit and hence it looks for an implicit of T at that point in time. Since it can't find one in scope it fails to compile.
In order to solve this issue, simply add the implicit parameter to the create method to tell the compiler to resolve it when you call create rather than toJson within create.
Furthermore we can use scala's implicit rules to get the behaviour that you want.
Let's take your trait Reads,
trait Reads[A] {
}
object MyFunc {
def create[A](a: A)(implicit reads: Reads[A]): Unit = ???
}
as we said befeore you can call it if the implicit is in scope. However, in this particular case where you have predefined reads we can actually put it in the companion object,
object Reads {
implicit val readsInt: Reads[Int] = ???
implicit val readsString: Reads[String] = ???
}
This way when create is called, the user doesn't need to import or define any implicit vals when A is Int or String because scala automatically looks in the companion object for any implicit definitions if it can't find one in the current scope.
Related
Given a type which has a "converter", I would like to have automatic conversion on method call using this type's companion object. That is, given the following definition,
case class Converted(name: String)
trait Converter[A] {
def perform: Converted
}
implicit val StringConverter = new Converter[String] {
def perform = Converted("String")
}
make the following code to work:
implicit def toConverter(a: String.type): Converted =
implicitly[Converter[String]].perform // Error: `Found String.type, required AnyRef`
def f(needsConverted: Converted) = ???
f(String) // <- That's what I would like to be able to write.
But this fails and both attempts for conversion fail. Note that I cannot change f because it is provided by a third-party library and there are many of them.
Can I make f(String) compile using implicits?
If not possible for Strings, what about classes which do have a companion object, can I do this generically like:
object TheClass
case class TheClass()
implicit val TheClassConverter = new Converter[TheClass] {
def perform = Converted("TheClass")
}
implicit def toConverter[A: Converter](a: A.type): Converted =
implicitly[Converter[A]].perform // Error: `Not found value A`
implicit def toConverter(a: TheClass.type): Converted =
implicitly[Converter[TheClass]].perform // This works but is not generic
f(TheClass) // This works.
Can I make the first toConverter to compile ?
Instead of defining an implicit instance for the type MyClass you can define an implicit instance for the companion type MyClass.type.
implicit val TheClassConverter: Converter[MyClass.type] = new Converted[MyClass.type] {
def perform = Converted("MyClass")
}
Can I make f(String) compile using implicits?
No. You can define a value called String, of course, but it won't be related to the type String.
implicit toConverter[A: Converter](a: A.type): Converted =
implicitly[Converter[A]].perform
A in A.type must be a value; it is not related to the type parameter A.
In fact, so far as Scala's type system is concerned, there is no relationship between a class/trait and its companion object. So you can't do what you want generically.
Of course, if you don't insist on using () instead of [], it becomes trivial:
def f1[A: Converter] = f(implicitly[Converter[A]].perform)
f1[String]
f1[TheClass]
Not sure, what are you trying to accomplish, but following works for me
case class Converted(name: String)
trait Converter[A] {
def perform: Converted
}
implicit def toConverted(name: String) = Converted("String")
implicit def toIntConverted(int: Int) = Converted("Int")
def f(needsConverted: Converted): String = needsConverted.name
f("some")
f(5)
I want to define a function with implicit parameter in a way like this:
// imports to add scope of A
{
implicit a: A => {
// some action
}
}.apply()
// somewhere in the code
class A
val a: A = new A
But my Scala compiler doesn't compile it. It says: Cannot resolve reference apply with such signature. However, the parameter is implicit, so I guess compiler should look up in the scope and find an appropriate object.
Is it true? If not, then how can I fix it?
You can't. Only methods can have implicit parameters.
When you do this:
// val f: A => Unit =
{
implicit a: A => {
// some action
}
}
you're actually declaring an anonymous function of type A => Unit and you are declaring the argument a as implicit in the function body
You can achieve something close to what you want using the magnet pattern:
class A
case class Magnet()
object Magnet {
implicit def fromUnit(arg1: Unit)(implicit a: A) = Magnet()
}
object Test extends App {
implicit val a = new A
{
args: Magnet => {
//...
}
}.apply()
}
You'll get a deprecation warning though because the magnet must have at least one parameter and I used Unit, you should call it like .apply(()) to avoid it
As said by Giovanni: You can't have such a parameter.
However you can use implicitly to resolve implicits within your function:
case class Foo(text : String)
implicit val foo = Foo("World")
(() => {
val implFoo : Foo = implicitly[Foo]
println(s"Hello ${implFoo.text}")
}).apply()
(But to be honest this sounds like it can be written better and you're going into spaghetti code territory with what you're doing.)
I am currently struggling with spray-json writing a protocol for my data model. For deserialization of JSON data to my data transfer objects, a DAO has to be contacted to check if an appropriate object exists, otherwise a DeserializationException should be thrown.
So far, I have the following:
object MyJsonProtocol extends DefaultJsonProtocol {
implicit object MyDtoJsonFormat extends RootJsonFormat[MyDto] {
override def write(obj: MyDto): JsValue = // Serialization implementation
override def read(json: JsValue): MyDto = {
// parse the JSON, get some parameters, let them be a, b, c
dtoLookup(a, b, c) match {
case Some(dto: MyDto) => dto
case None => throw new DeserializationException("Cannot retrieve object from DAO")
}
}
}
def dtoLookup(a: SomeType, b: SomeOtherType, c: YetAnotherType)(implicit dao: MyDAO): Option[MyDto] = {
// lookup the MyDTO with the dao instance
}
}
My test looks like the following:
class MyJsonProtocolTest extends FlatSpec with Matchers {
implicit val MyDAO = // some test instance, can be a mock object
"The protocol" should "serialize a DTO" in {
val dto: MyDTO = ...
dto.toJson.compactPrint should be("{...}")
}
}
However, the compiler complains that it cannot find the implicit MyDAO when trying to compile the MyJSONProtocol. In When testing Spray services with Scalatest, how to introduce implicit values? I asked yesterday, I was suggested to pass in the implicit parameter directly into the method, but I cannot do this here because the read method is defined in the RootJsonFormat.
When I call the dtoLookup method directly from my test code, it succeeds.
So, how do I get the MyDAO instance into my special JSON format?
One option is to make the implicit parameter a constructor parameter to one of the classes being used. This might require that you turn one of your objects into a class. Then you can make an get method on the companion object of that class that uses an implicit in scope to construct the class with the desired argument.
This doesn't really have to do with spray or scalatest, rather it's just an issue with implicits and implicit scope. Here's a simplified version:
object MyJsonProtocol {
implicit object MyDtoJsonFormat {
def read(x: Int) = dtoLookup
}
def dtoLookup(implicit x: Int) = x + 1
}
And you might consider changing that to:
class MyJsonProtocol(implicit x: Int) {
implicit object MyDtoJsonFormat {
def read(x: Int) = dtoLookup
}
def dtoLookup = x + 1
}
object MyJsonProtol {
def get(implicit x: Int) = new MyJsonProtocol
}
And then you can use this with an implicit in scope:
class MyJsonProtocolTest {
implicit val x = 5
val proto = MyJsonProtol.get
val myReadValue = proto.MyDtoJsonFormat.read //6
}
You can read about the rules for implicit scopes here, especially relevant might be the "Where do Implicits Come From" section.
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 writing a generic value parser using Scala 2.10.
The input is a string and the output is a generic type, given by the user.
The only thing I can come up with is
val StringTYPE = classOf[java.lang.String]
def parseValue[T: ClassTag](str: String): T = {
implicitly[ClassTag[T]].runtimeClass match {
case java.lang.Integer.TYPE => str.toInt.asInstanceOf[T]
case java.lang.Long.TYPE => str.toLong.asInstanceOf[T]
case StringTYPE => str.asInstanceOf[T]
case _ => throw new Exception("Unknown type")
}
}
But it seems very verbose and complicated, so I'm wondering is there any simpler way to do this?
It seems strange to use a run-time error for a compile-time condition. Did you consider a type class?
trait Readable[T] {
def read(str: String): T
}
object Readable {
implicit object IntIsReadable extends Readable[Int] {
def read(str: String): Int = str.toInt
}
// ... provide similar objects for any types that can be "read" ...
// if possible, inside object Readable
// or inside the companion object of the type you want to make readable.
// Otherwise, ensure that the implicit is in scope when calling Read
}
def readValue[T: Readable](str: String): T = implicitly[Readable[T]].read(str)
The solution is given by Aaron, the proper way to do that is the type class.
Just to suggest minor improvements to your version (but do not do that) you could check directly with the ClassTag. Also, naming the implicit parameter might be easier than getting it back with implicitly:
def parseValue[T](str: String)(implicit tag: ClassTag[T]): T = {
if(tag == ClassTag.Int) str.toInt.asInstanceOf[T]
else if(tag == ClassTag.Long) ...
else if (tag == ClassTag(classOf[String]) …
else ???
}