Method parameter of dependent type of another implicit method parameter - is it possible? - scala

(A longish) illustration:
// Base trait for different domains. Domains hold value-like things,
// which have some known relationships between them.
trait Domain {
type Data
type IntData <: Data
type PairData <: Data
def select(query: Query, data: Data): Data = ???
}
// Base trait for queries. Queries operate in a
// specific (but arbitrary) domain.
sealed trait Query {
def select[D <: Domain](domain: D)(data: domain.Data): domain.Data =
domain.select(this, data)
}
// Specific queries
case object IdQuery extends Query
case class SuccQuery(val q: Query) extends Query
// ...
// Specific domains
object Values extends Domain {
sealed abstract class Data
case class IntData(val data: Int) extends Data
case class PairData(val a: Data, val b: Data) extends Data
}
object Paths extends Domain {
// ...
}
object Test {
def test {
val query: Query = ???
val value: Values.Data = ???
val path: Paths.Data = ???
val valueResult = query.select(Values)(value)
val pathResult = query.select(Paths)(path)
}
}
This is a complete working code. In the example, I have a fixed case-hierarchy of structured queries which need to operate on different domains somehow. The common parts of the domains are part of the Domain trait.
Let's look at the select definition in the Query trait: it takes a specific domain (which should be a stable value), and data of a dependent type of this domain. The client passes both the specific domain and the data to the select method. This is an example of a method in which a parameter is of a dependent type of another (non-implicit) parameter.
I want to somehow "hide" the domain, so that only the data is passed (the domain being passed implicitly). But I can't quite nail it:
If I declare:
def select[D <: Domain](implicit domain: D)(data: domain.Data)
the compiler complains because implicit method parameters should come last.
If I swap the two parameters:
def select[D <: Domain](data: domain.Data)(implicit domain: D)
the compiler complains about domain being defined after being used:
illegal dependent method type: parameter appears in the type of another parameter in the same section or an earlier one
What can I do to make the domain parameter be passed implicitly?
More generally, is it possible to have a method parameter of a dependent type of another implicit method parameter?

I would suggest this workaround:
def select[D <: Domain](implicit domain: D) =
new Selector[D](domain)
class Selector[D <: Domain](domain: D) {
def data(data: domain.Data): domain.Data = ???
}
select.data(someData)

Related

Scala case class conversion

Is there a way to convert one case class to another when they have the same fields and inherit from the same trait, without providing a converter function (that would simply do the one to one field mapping)?
For example:
trait UberSomething {
val name: String
}
// these may be located in different files
case class Something(name: String) extends UberSomething
case class SomethingOther(name: String) extends UberSomething
val s = Something("wtv")
//s.asInstanceOf[SomethingOther] FAILS
First of all never define trait members as val if they are meant to be implemented at a later point.
trait UberSomething {
def name: String
}
// these maybe in different files
case class Something(name: String) extends UberSomething
case class SomethingOther(name: String) extends UberSomething
import shapeless._, ops.hlist.Align
Another approach I've seen somewhere on Stackoverflow before, so apologies for stealing street cred, is to use Align such that order of the fields wouldn't matter.
class Convert[Target] {
def apply[Source, HLS <: HList, HLT <: HList](s: Source)(implicit
// Convert the Source to an HList type
// include field names, e.g "labelled"
// Shapeless "generates" this using an implicit macro
// it looks at our type, extracts a list of (Name, Type) pairs
genS: LabelledGeneric.Aux[Source, HLS],
// Convert the Target o an HList type
// include field names, e.g "labelled"
// So again we have a (Name, Type) list of pairs this time for Target
genT: LabelledGeneric.Aux[Target, HLT],
// Use an implicit align to make sure the two HLists
// contain the same set of (Name, Type) pairs in arbitrary order.
align: Align[HLS, HLT]
) = genT from align(genS to s)
}
// Small trick to guarantee conversion only requires
// a single type argument, otherwise we'd have to put something
// in place for HLS and HLT, which are meant to be path dependant
// and "calculated" by the LabelledGeneric.Repr macro so it wouldn't work as it breaches the "Aux pattern", which exposes a type member materialized by a macro in this case.
// HLT and HLS come from within genS.Repr and genT.Repr.
def convert[T] = new Convert[T]
This is a bit better as the HList params are nicely masked as part of apply so you don't trip yourself up.
val sample = Something("bla")
convert[SomethingOther](sample) // SomethingOther("bla")
Let's review this line: genT from align(genS to s).
First genS to s converts the Source instance to a LabelledGeneric, e.g an HList with field info.
Align aligns the types and fields of the created HList for the Source type to match the Target type.
genT from .. allows us to create an instance of Target from an HList granted the compiler can "prove" the fields and types are "all there", which is something we already have with Align.
You can do that using implicit conversions, eg:
trait UberSomething {
val name: String
}
case class Something(name: String) extends UberSomething
case class SomethingOther(name: String) extends UberSomething
object Something {
implicit def somethingToSomethingOther(s:Something):SomethingOther = SomethingOther(s.name)
}
object SomethingOther {
implicit def somethingOtherToSomething(s:SomethingOther):Something = Something(s.name)
}
val s = Something("wtv")
val so:SomethingOther = s

How to define implicit Writes in trait

I have multiple case classes representing values in DB for ex User which saves user based properties like name / age / address and CallLog which saves timestamp / status_of_call
What i want to achieve
I want to have a helper function which accepts list of models and checks if the list is empty then returns "error" otherwise should return json array of the list.
My Approach
I want to have a trait which groups certain models in it and the helper method will accept either the trait or List of it in order to check or may be have a generic which implements the trait.
Problem
Since implicit writes are tightly coupled with the model class, compiler throws the error on the line Json.toJson(list)
Things i have tried
Kept implicit in trait and got recursive type error
I am scala noob pardon me if this sounds silly
Thanks in advance
Since User, CallLog, etc. will be serialized differently, Each Writes[T] will be different for each implementation of your Model trait, so a Writes[Model] has to know about the implementation it is trying to serialize.
It is therefore not possible to have it part of the Model trait, because this information isn't known yet when you define it.
A workaround in your case would be to define your Writes[Model] in the scope of your helper function instead.
An implementation of your helper function could be like this :
import play.api.libs.json.{JsValue, Json, Writes}
sealed trait Model
case class User(name: String, age: String, address: String) extends Model
object User {
implicit val userWrites = Json.writes[User]
}
case class CallLog(timestamp: String, status_of_call: String) extends Model
object CallLog {
implicit val callLogWrites = Json.writes[CallLog]
}
implicit val modelWrites = new Writes[Model] {
override def writes(o: Model): JsValue = o match {
case u: User => Json.toJson(u)
case cl: CallLog => Json.toJson(cl)
}
}
def helper(models: Model*): Either[JsValue, String] = models match {
case Nil => Right("Error")
case _ => Left(Json.toJson(models))
}
helper(User("John", "32", "..."))
helper(User("John", "32", "..."), CallLog("now", "In progress"))

Context bounds for type members or how to defer implicit resolution until member instantiation

In the following example, is there a way to avoid that implicit resolution picks the defaultInstance and uses the intInstance instead? More background after the code:
// the following part is an external fixed API
trait TypeCls[A] {
def foo: String
}
object TypeCls {
def foo[A](implicit x: TypeCls[A]) = x.foo
implicit def defaultInstance[A]: TypeCls[A] = new TypeCls[A] {
def foo = "default"
}
implicit val intInstance: TypeCls[Int] = new TypeCls[Int] {
def foo = "integer"
}
}
trait FooM {
type A
def foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
def foo: String = implicitly[TypeCls[A]].foo
}
class MyFooP extends FooP[Int]
class MyFooM extends FooM { type A = Int }
object Main extends App {
println(s"With type parameter: ${(new MyFooP).foo}")
println(s"With type member: ${(new MyFooM).foo}")
}
Actual output:
With type parameter: integer
With type member: default
Desired output:
With type parameter: integer
With type member: integer
I am working with a third-party library that uses the above scheme to provide "default" instances for the type class TypeCls. I think the above code is a minimal example that demonstrates my problem.
Users are supposed to mix in the FooM trait and instantiate the abstract type member A. The problem is that due to the defaultInstance the call of (new MyFooM).foo does not resolve the specialized intInstance and instead commits to defaultInstance which is not what I want.
I added an alternative version using type parameters, called FooP (P = Parameter, M = Member) which avoids to resolve the defaultInstance by using a context bound on the type parameter.
Is there an equivalent way to do this with type members?
EDIT: I have an error in my simplification, actually the foo is not a def but a val, so it is not possible to add an implicit parameter. So no of the current answers are applicable.
trait FooM {
type A
val foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
val foo: String = implicitly[TypeCls[A]].foo
}
The simplest solution in this specific case is have foo itself require an implicit instance of TypeCls[A].
The only downside is that it will be passed on every call to foo as opposed to just when instantiating
FooM. So you'll have to make sure they are in scope on every call to foo. Though as long as the TypeCls instances are in the companion object, you won't have anything special to do.
trait FooM {
type A
def foo(implicit e: TypeCls[A]): String = e.foo
}
UPDATE: In my above answer I managed to miss the fact that FooM cannot be modified. In addition the latest edit to the question mentions that FooM.foo is actually a val and not a def.
Well the bad news is that the API you're using is simply broken. There is no way FooM.foo wille ever return anything useful (it will always resolve TypeCls[A] to TypeCls.defaultInstance regardless of the actual value of A). The only way out is to override foo in a derived class where the actual value of A is known, in order to be able to use the proper instance of TypeCls. Fortunately, this idea can be combined with your original workaround of using a class with a context bound (FooP in your case):
class FooMEx[T:TypeCls] extends FooM {
type A = T
override val foo: String = implicitly[TypeCls[A]].foo
}
Now instead of having your classes extend FooM directly, have them extend FooMEx:
class MyFoo extends FooMEx[Int]
The only difference between FooMEx and your original FooP class is that FooMEx does extend FooM, so MyFoo is a proper instance of FooM and can thus be used with the fixed API.
Can you copy the code from the third party library. Overriding the method does the trick.
class MyFooM extends FooM { type A = Int
override def foo: String = implicitly[TypeCls[A]].foo}
It is a hack, but I doubt there is anything better.
I do not know why this works the way it does. It must be some order in which the type alias are substituted in the implicitly expression.
Only an expert in the language specification can tell you the exact reason.

scala: how to view subclass methods with a generic instantiation

I have the following where I set information and extractors for different schemes of data:
trait DataScheme {
type Type <: List[Any]
class ExtractorMethods(ticker: String, dataList: List[Type]) {
def getDatetime(datum: Type): Date = new Date(datum(columnIndex(Names.datetime)).toString)
def upperDatum(date: Date): Type = dataList.minBy(datum => getDatetime(datum) >= date)
def lowerDatum(date: Date): Type = dataList.maxBy(datum => getDatetime(datum) <= date)
}
}
trait IndexScheme extends DataScheme {
type Type = (Date, Double, Double, Double, Double, Long)
class ExtractorMethods(ticker: String, dataList: List[Type]) extends super.ExtractorMethods(ticker: String, dataList: List[Type]){
def testing12(int: Int):Int = 12
val test123 = 123
}
}
I want anything extending DataScheme to use its ExtractorMethods methods (e.g. lowerDatum) but also have its own methods (e.g. testing12).
There is a class definition for lists of data elements:
class Data[+T <: DataScheme](val ticker: String, val dataList: List[T#Type], val isSorted: Boolean)
(implicit m: Manifest[T], mm: Manifest[T#Type]) extends Symbols {
def this(ticker: String, dataList: List[T#Type])(implicit m: Manifest[T], mm: Manifest[T#Type]) = this(ticker, dataList, false)(m: Manifest[T], mm: Manifest[T#Type])
val dataScheme: T
val extractorMethods = new dataScheme.ExtractorMethods(ticker, dataList.asInstanceOf[List[dataScheme.Type]])
}
A Data class should make accessible the methods in ExtractorMethods of the scheme so they can be used in the main program through the instance of Data that has been defined. For example if sortedData is an instance of Data[IndexScheme], the following works:
val lowerDatum = sortedData.extractorMethods.lowerDatum(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2010-03-31 00:00:00"))
but this does not:
val testing = sortedData.extractorMethods.testing12(123)
because 'testing 123 is not a member of sortedData.dataScheme.extractorMethods'. So my question is how can the subclasses of ExtractorMethods in the subtraits of DataScheme like IndexScheme be made accessible? How is it possible using Manifests and TypeTags? Thanks.
So you want the generic class Data[DataScheme] or Data[IndexScheme] to have access to the methods of whichever type Data has been parameterised with. You've tried to do this several different ways, from the evidence in your code.
To answer your last question - manifests can't help in this particular case and TypeTags are only part of the answer. If you really want to do this, you do it with mirrors.
However, you will have to make some changes to your code. Scala only has instance methods; there are no such things as static methods in Scala. This means that you can only use reflection to invoke a method on an instance of a class, trait or object. Your traits are abstract and can't be instantiated.
I can't really tell you how to clean up your code, because what you have pasted up here is a bit of a mess and is full of different things you have tried. What I can show you is how to do it with a simpler set of classes:
import scala.reflect.runtime.universe._
class t1 {
class Methods {
def a = "a"
def b = "b"
}
def methods = new Methods
}
class t2 extends t1 {
class Methods extends super.Methods {
def one = 1
def two = 2
}
override def methods = new Methods
}
class c[+T <: t1](implicit tag: TypeTag[T]) {
def generateT = {
val mirror = runtimeMirror(getClass.getClassLoader)
val cMirror = mirror.reflectClass(typeOf[T].typeSymbol.asClass)
cMirror.reflectConstructor(typeOf[T].declaration(nme.CONSTRUCTOR).asMethod)
}
val t = generateT().asInstanceOf[T]
}
val v1 = new c[t1]
val v2 = new c[t2]
If you run that, you'll find that v1.t.methods gives you a class with only methods a and b, but v2.t.methods gives a class with methods one and two as well.
This really is not how to do this - reaching for reflection for this kind of job shows a very broken model. But I guess that's your business.
I stick by what I said below, though. You should be using implicit conversions (and possibly implicit parameters) with companion objects. Use Scala's type system the way it's designed - you are fighting it all the way.
ORIGINAL ANSWER
Well, I'm going to start by saying that I would never do things the way you are doing this; it seems horribly over-complicated. But you can do what you want to do, roughly the way you are doing it, by
Using mixins
Moving the extractorMethods creation code into the traits.
Here's a greatly simplified example:
trait t1 {
class Methods {
def a = "a"
def b = "b"
}
def methods = new Methods
}
trait t2 extends t1 {
class Methods extends super.Methods {
def one = 1
def two = 2
}
override def methods = new Methods
}
class c1 extends t1
val v1 = new c1
// v1.methods.a will return "a", but v1.methods.one does not exist
class c2 extends c1 with t2
val v2 = new c2
// v2.methods.a returns "a" and v2.methods.one returns 1
I could replicate your modus operandi more closely by defining c1 like this:
class c1 extends t1 {
val myMethods = methods
}
in which case v1.myMethods would only have methods a and b but v2.myMethods would have a, b, one and two.
You should be able to see how you can adapt this to your own class and trait structure. I know my example doesn't have any of your complex type logic in it, but you know better than I what you are trying to achieve there. I'm just trying to demonstrate a simple mechanism.
But dude, way to make your life difficult...
EDIT
There are so many things I could say about what is wrong with your approach here, both on the small and large scale. I'm going to restrict myself to saying two things:
You can't do what you are trying to do in the Data class because it is abstract. You cannot force Scala to magically replace an uninitialised, abstract method of a non-specific type with the specific type, just by littering everything with Type annotations. You can only solve this with a concrete class which provides the specific type.
You should be doing this with implicit conversions. Implicits would help you do it the wrong way you seem fixated on, but would also help you do it the right way. Oh, and use a companion object, either for the implicits or to hold a factory (or bot).

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.