Scala generics in function return value - scala

I have these classes defined.
trait ResultTrait {
}
case class PostResult (
#Key("_id") id: String,
success: String,
errors: Seq[String] = Seq.empty
) extends ResultTrait
case class PostError (
message: String,
errorCode: String
) extends ResultTrait
This won't compile. It gives error "Required T, but found PostResult (or PostError)".
def postLead[T <: SFDCResult](accessToken: AccessToken):
Future[T] = {
// depends on response from request, return PostResult or PostError
}

As #Travis Brown has already stated, it looks like you're trying to express the variability of the return type (i.e. "it's either a PostResult or a PostError") through generics, when really all you need is the parent trait.
Assuming your SDFCResult was an anonymization error where you meant to use ResultTrait, I would use the following:
// Make the trait sealed so we can only have our two known implementations:
sealed trait ResultTrait {}
...
// Two subclasses as before
And then your method should just be:
def postLead(accessToken: AccessToken):Future[ResultTrait] = {
// depends on response from request, return PostResult or PostError
}

Related

How to invoke a method that expects a Type function with arguments

This is my code and I get following error when I try to invoke my m1 method:
trait Function4[-T1, -T2, -T3, -T4, +R] extends Function {
def apply(arg1: T1, arg2: T2, arg3: T3, arg4: T4): R
}
class Function(args: String*) extends Object {
}
class A extends Object {
type CallbackFunction = Function4[Object, Object, Object, Object, Promise[String]]
def m1(callback: CallbackFunction): Unit = {
}
def m2 = {
m1(
(a:Object, b:Object, c:Object, d: Object) => {
println("good here!")
}
)
}
}
Error is :
Type mismatch, expected: A.this.CallbackFunction, actual: (Object, Object, Object, Object) => Promise[String]
Actually your original code (revision 1) works fine in Scala 2.12, not work in Scala 2.11.
If you want you code work in Scala 2.11 you can rewrite code like this:
class A extends Object {
type CallbackFunction[A] = Function4[Object, Object, Object, Object, A]
def m1[A](callback: CallbackFunction[A]): Unit = {
}
def m2 = {
m1(
(a:Object, b:Object, c:Object, d: Object) => {
println("good here!")
}
)
}
}
Or change Function4[Object, Object, Object, Object, _] to Function4[Object, Object, Object, Object, Unit].
If you want you current code (revision 2) work, you only need to change Promise[String] to Unit.
Why is your code defining your own Function (which doesn't describe a function) and your own Function4 (when there is one in the standard library)?
If, as your comment to another answer says, "I can not change anything in my CallbackFunction, this is a library code", this very much looks like a library nobody should be using.
However, the direct answer to your question is that the argument you pass to m1 must be a function returning Promise[String]. Assuming Promise is the standard scala.concurrent.Promise instead of another type defined by the library, one possibility would be
(a:Object, b:Object, c:Object, d: Object) => Promise()
But that would only make it compile (so would passing null!); it isn't at all clear what you want to do.

How to create my own custom converts class

I have a very generic message object that I get back from a queue like:
case class Message(key: String, properties: Map[String, String])
I then have a bunch of very specific classes that represent a message, and I use properties.get("type") to determine which particular message it is:
sealed trait BaseMessage
case class LoginMessage(userId: Int, ....) extends BaseMessage
case class RegisterMessage(email: String, firstName: String, ....) extends BaseMessage
Now in my code I have to convert from a generic Message to a particular message in many places, and I want to create this in a single place like:
Currently I am doing something like:
val m = Message(....)
val myMessage = m.properties.get("type") match {
case Some("login") => LoginMessage(m.properties("userID"), ...)
case ...
}
What options do I have in making this less cumbersome in scala?
I don't know all your context here, but I can suggest using implicit conversions if you don't want to bring another library in your project. Anyway, implicit conversions can help you separate a lot the implementation or override it "on-the-fly" as needed.
We can start by defining a MessageConverter trait that is actually a function:
/**
* Try[T] here is useful to track deserialization errors. If you don't need it you can use Option[T] instead.
*/
trait MessageConverter[T <: BaseMessage] extends (Message => Try[T])
Now define an object that holds both the implementations and also enables a nice #as[T] method on Message instances:
object MessageConverters {
/**
* Useful to perform conversions such as:
* {{{
* import MessageConverters._
*
* message.as[LoginMessage]
* message.as[RegisterMessage]
* }}}
*/
implicit class MessageConv(val message: Message) extends AnyVal {
def as[T <: BaseMessage : MessageConverter]: Try[T] =
implicitly[MessageConverter[T]].apply(message)
}
// Define below message converters for each particular type
implicit val loginMessageConverter = new MessageConverter[LoginMessage] {
override def apply(message: Message): Try[LoginMessage] = {
// Parse the properties and build the instance here or fail if you can't.
}
}
}
That's it! It may not be the best solution as implicits bring complexity and they make code harder to follow. However, if you follow a well-defined structure for storing these implicit values and be careful how you pass them around, then you shouldn't have any issues.
You can convert the properties map to Json and read it as a case class. Assuming that the keys to the map have the same name as your case class fields you can write a formatter using playjson:
object LoginMessage {
implicit val fmtLoginMessage = Json.format[LoginMessage]
}
If the fields don't have the same name you will have to specify the reads object manually. Your code to convert it into a case class would be something like:
object BaseMessageFactory {
def getMessage(msg: Message): Option[BaseMessage] = {
val propertiesJson = Json.toJson(msg.properties)
msg.properties.get("type").mapĀ {
case "login" => propertiesJson.as[LoginMessage]
...
case _ => //Some error
}
}
}
The signature may differ depending on how you want to deal with error handling.

Generic function with implicit parameter

I have a situation where I am trying to create a generic function which should be able to take any instance of a class which specifies a certain implicit value in its companion object. I have replicated my problem below:
// Mocking up the library I am working with
trait Formatter[A] {
def output(o: A): String
def input(s: String): A
}
// Some models
trait Human
case class Child(name: String) extends Human
object Child {
implicit val f: Formatter[Child] = new Formatter[Child] {
override def output(c: Child): String = { ... }
override def input(s: String): Child = { ... }
}
}
case class Teen(name: String) extends Human
object Teen {
implicit val f: Formatter[Teen] = new Formatter[Teen] {
override def output(t: Teen): String = { ... }
override def input(s: String): Teen = { ... }
}
}
// The generic function
def gen[A <: Human](a: A)(implicit format: Formatter[A]) = {
// Do something with a formatter...
}
This all works fine, I can pass an instance of a Child or a Teen to my gen function:
gen(Child("Peter"))
gen(Teen("Emily"))
What I am having trouble with is that at run time I only know that the instance I am passing will be a subtype of a Human:
// Example of unknown subtype
val human: Human = Random.nextBoolean match {
case true => Child("Peter")
case false => Teen("Emily")
}
gen(human) // Error: Could not find implicit value for parameter format...
I understand that the error is because Human has no companion object and therefore it has no implementation of a Formatter.
How can I add a constraint to Human that says "anything extending Human will implement a new Formatter" ?
Your scenario fails because you should implement a Formatter[Human]. I think that what you want is that all the Human should be able to have this format "capability" instead.
At this point you have two options, one is to include in the Human trait a method for formatting (this implementation could be in the object if you want it static) or try a dsl approach where you will create a class with the responsibility to provide humans a new capability: "format".
The first approach could be something like this:
trait Human { def format:String }
case class Child(name: String) extends Human {
import Child._
override def format = Child.staticFormat(this)
}
object Child {
def staticFormat(c: Child): String = s"Child(${c.name})"
}
However I think "format" shouldn't be in the contract "Human" so I prefer the second approach:
trait Human
case class Child(name: String) extends Human
case class Teen(name: String) extends Human
import scala.language.implicitConversions
class HumanFormatter(human: Human) {
def format: String = human match {
case c: Child => s"Child(${c.name})"
case t: Teen => s"Teen(${t.name})"
}
}
object HumanDsl {
implicit def humanFormatter(human: Human): HumanFormatter = new HumanFormatter(human)
}
object Test extends App {
def human: Human = Random.nextBoolean match {
case true => Child("Peter")
case false => Teen("Emily")
}
import HumanDsl._
for(i <- 1 to 10) println(human.format)
}
What are the differences between both solutions?
In the first one you force all the new Human classes to implement a format method so you can assure that your code will work always. But at the same time... you are adding a Human a method that from my point of view is not necessary, I think a case class should have only the information needed and if you need to format/parse that class then is better to add this functionality just when needed (dsl approach).
In the other hand, with dsl you should update the formatter anytime a new Human class is created. So it means that the human.format method above will fail if a new Human class is created (you can always match _ to do a default behaviour or raise a custom error).
I think is a matter of design, I hope this would help you a little bit.
Edited:
just like a comment showed the Human trait could be sealed to ensure that the HumanFormatter pattern match doesn't compile if some class is not covered.
You don't need implicits for this.
Just make your subclasses point to the implementation directly:
trait Human[+A <: Human] {
def formatter: Formatter[A]
}
case class Child(name: String) extends Human[Child] {
def formatter = Child.f
}
// etc
def gen[A <: Human](a: A) {
// do something with a.formatter
}
Of course, Formatter needs to be covariant in A too. Otherwise, all bets are off: you simply cannot do what you want - there is nothing useful gen could do with it without knowing the specific type anyway.
If specifics of the concrete type are not needed in gen, you can still use implicits by enumerating them explicitly like this (but I don't really see why you would want that):
object Human {
implicit def formatter(h: Human): Formatter[_] = h match {
case Child(_) => Child.f
case Teen(_) => Teen.f
}
}
gen(h: Human)(implicit f: Formatter[_]) { ... }
Like I said, this does not seem very useful though, so not sure why you want want this over the above approach.

Scala: "No manifest available for type T"

I am working on a Lift project with mixed Scala and Java code.
On the Java side, I have the following relevant items:
interface IEntity
interface IDAO<T extends IEntity> {
void persist(T t);
}
On the Scala side, I have the following:
abstract class Binding[T <: IEntity] extends NgModel {
def unbind: T
}
class BasicService[E <: IEntity](serviceName: String, dataAccessObject: IDAO[E]) {
def render = renderIfNotAlreadyDefined(
angular.module("myapp.services")
.factory(serviceName,
jsObjFactory()
.jsonCall("persist", (binding: Binding[E]) => { //<---COMPILATION ERROR
try {
dataAccessObject.persist(binding.unbind)
Empty
} catch {
case e: Exception => Failure(e.getMessage)
}
})
)
)
}
This code will not compile. I get the following error at the point indicated above:
No Manifest available for Binding[E].
It is not clear at all to me why this occurs, but I am guessing it has something to do with this being a nested method invocation. The code compiles fine if I declare a member function with Binding[E] as a parameter, for example:
def someFunction(binding: Binding[E] = { // same code as above }
Why does this happen, and how can I work around it?
Turns out this is relatively easily solved by implicitly passing on the manifest for the type in question, either in the constructor or the method itself:
class BasicService[E <: IEntity](serviceName: String, dataAccessObject: IDAO[E])(implicit m: Manifest[Binding[E]]) {
or
def render(implicit m: Manifest[Binding[E]])

How to write a Service cappable of handling multiple parameter types in Scala?

I am designing an API. It basically looks like this:
trait Service {
def performUseCase[T](transferObjects: Iterable[TransferObject[T]])
}
trait TransferObject[T] {
def data: T
}
case class TransferObjectA[T](data: T) extends TransferObject[T]
case class TransferObjectB[T](data: T) extends TransferObject[T]
Note: If necessary I could change the implementation of the TransferObjects. Semantically important is:
There are at least two kinds of TransferObjects.
The transfer objects must build a sequential order in any way. It is not so important right now how that order is build: a Seq[TransferObject[_], or one transfer object referencing the next or however.
There will be different implementations of the Service trait. For each Service instance it must be specified which types this instance can handle.
Example: This Service val myService = MyService() can handle TransferObjects[MyTypeA] and TransferObjects[MyTypeB] etc.. When an API user tries to pass a TransferObjects[MyUnknownType] the compiler should throw an error.
I read about Scala's type system, about type classes (e.g. with implicits) and type declarations, but I don't understand all details, yet.
I tried to use an implementation of the Service trait with type specific handlers as type classes. MyHandler[MyTypeA], MyHandler[MyTypeB] etc. and using implicits to pass in the correct handler for the current parameter type. But the handlers should not be exposed to the API user. That is why I wonder if it is possible at all, to throw compiler errors if the user passes in parameters of types that the Service can't handle.
The real implementation is more complicated and currently broken. Maybe I can deliver some more code later.
Round-up:
So again: I want multiple Service instances. Each of them should be able to handle multiple parameter types. If a parameter of an unknown type is passed in, the compiler should throw an error. Type specific handlers are considered as implementation details and should remain hidden from API users.
How do I realize that?
you could use sealed trait TransferObject[T]{... and case class TransferObjectA(data: Int) extends TransferObject[Int] ... and inside of def performUseCase[T](transferObjects: Iterable[TransferObject[T]]) some
transferObject match{
case TransferObjectA(myInt) => ...
...
}//throws warning because of unmatched TransferObjectB on compile time because of sealed trait
also have a look at What is a sealed trait?
Here's a type class-based approach:
trait TransferObject[T] {
def data: T
}
case class TransferObjectA[T](data: T) extends TransferObject[T]
case class TransferObjectB[T](data: T) extends TransferObject[T]
trait Service {
protected[this] trait Handler[A] {
def apply(objs: Iterable[TransferObject[A]]): Unit
}
def performUseCase[A](objs: Iterable[TransferObject[A]])(
implicit handler: Handler[A]
) = handler(objs)
}
And then:
object MyIntAndStringService extends Service {
implicit object intHandler extends Handler[Int] {
def apply(objs: Iterable[TransferObject[Int]]) {
objs.foreach(obj => printf("Int: %d\n", obj.data))
}
}
implicit object stringHandler extends Handler[String] {
def apply(objs: Iterable[TransferObject[String]]) {
objs.foreach(obj => printf("String: %s\n", obj.data))
}
}
}
val ints = List(1, 2, 3).map(TransferObjectA(_))
val strings = List("A", "B", "C").map(TransferObjectA(_))
val chars = List('a', 'b', 'c').map(TransferObjectA(_))
And finally:
scala> MyIntAndStringService.performUseCase(ints)
Int: 1
Int: 2
Int: 3
scala> MyIntAndStringService.performUseCase(strings)
String: A
String: B
String: C
scala> MyIntAndStringService.performUseCase(chars)
<console>:14: error: could not find implicit value for parameter handler: MyIntAndStringService.Handler[Char]
MyIntAndStringService.performUseCase(chars)
^
As desired.