I will let the code speak:
import scala.concurrent.Future
trait SomeRequest
trait SomeResponse
trait ApiStandard {
def apiCall[Req <: SomeRequest, Resp <: SomeResponse](request: Req): Future[Resp]
}
case class XXRequest() extends SomeRequest
case class XXResponse() extends SomeResponse
class XXStandard extends ApiStandard {
override def apiCall(request: XXRequest): Future[XXResponse] = ???
}
Basically I have a couple of data traits (SomeRequest, SomeResponse) and a behaviour trait ApiStandard. There are also case classes XXRequest and XXResponse which override the data traits. I am trying to create a concrete implementation of of ApiStandard called XXStandard. But it's not syntactically correct. Being a Scala beginner, I can't understand why.
Please throw some light.
Thanks.
ApiStandard defines a method apiCall that accepts a parameter that is more flexible than what XXStandard provides.
To illustrate,
If you have
val something: ApiStandard = ???
you know you can call
val req: SomeRequest
something(req)
If the ??? would be able to be new XXStandard(), and XXStandard only accepts XXRequests as it's argument to apiCall, this would be broken: there is no way to know req is in fact an XXRequest, and indeed, it doesn't have to be one.
Furtunately, this doesn't compile, because apiCall in XXStandard can't implement ApiStandard.apiCall.
To make XXStandard into something that can be a subtype of ApiStandard, apiCall in XXStandard has to take a type that is what you declared in your trait, or a supertype of that as its argument.
tl;dr:
Methods are contravariant in their parameter type.
Your definition of apiCall says it must work for any Req <: SomeRequest and Resp <: SomeResponse, so the caller can call it like (e.g.) apiCall[MyReq, SomeoneElsesResp](new MyReq). But the implementation in XXStandard doesn't work like this; it only supports a single request and response type. Assuming that's what you wanted, you need to move type arguments to ApiStandard:
trait ApiStandard[Req <: SomeRequest, Resp <: SomeResponse] {
def apiCall(request: Req): Future[Resp]
}
class XXStandard extends ApiStandard[XXRequest, XXResponse] {
override def apiCall(request: XXRequest): Future[XXResponse] = ???
}
Related
Say I have the following trait and class:
case class Result[A](
header: String,
data: A
)
trait WebClient {
def doSomething[A : TypeTag](name: String): Future[Result[A]]
}
In this example, doSomething is the polymorphic method in question. How can I create a MockWebClient which implements WebClient and have minimal behavior? (The most minimal behavior being doing nothing.) Preferably, I don't want to return a Future.failed because the result shouldn't signify a failure, semantically. Also, I don't want to change the A type of Result[A] to be covariant or contravariant (i.e. +A or -A) because it doesn't make a lot of sense in the context.
Here's my best attempt (which still doesn't compile). It uses a generic class with a generic factory to simulate the return value of the doSomething method. However, I cannot find the correct relationship between A and B:
class MockWebClient[A](val factory: () => Result[A]) extends WebClient {
override def doSomething[B >: A : TypeTag](name: String): Future[Result[B]] = {
Future.successful(factory())
}
}
Also, I have used mockito-scala, but it doesn't work because of type erasure. scalamock also seems interesting, but I would like to know if there is a way to make something similar to my solution work.
If you are sure data field will not be used in the test you could trick the compiler with null.asInstanceOf[A]
val mockWebClient = new WebClient {
override def doSomething[A](name: String): Future[Result[A]] =
Future.successful(Result(name, null.asInstanceOf[A]))
}
If A forms a Monoid you could do it in a type-safe manner with something like
import cats.Monoid
import cats.implicits._
trait WebClient {
def doSomething[A: Monoid](name: String): Future[Result[A]]
}
val mockWebClient = new WebClient {
override def doSomething[A: Monoid](name: String): Future[Result[A]] =
Future.successful(Result(name, implicitly[Monoid[A]].empty))
}
mockWebClient.doSomething[String]("woohoo")
So I have this simple Scala trait with a method that requires a type parameter specified.
The DAO class extends the trait and uses the trait's method. Even if I do not provide a concrete type to the method, the code still compiles, and I suppose this is achieved by Scala auto inferring the generic type (guessing what the type value should be)? Is it right?
And also how does Scala infer types in situations like this in general?
Thanks a lot!!
class DAO #Inject()(val configProvider: DatabaseConfigProvider) extends
ManagementAppDatabase {
private val users = TableQuery[UserTable]
def findUserByEmail(email: String): Future[Option[User]] = {
execute(users.filter(_.email === email).result.headOption)
}
}
trait ManagementAppDatabase {
val configProvider: DatabaseConfigProvider
def execute[T](dBIO:DBIO[T]): Future[T] = configProvider.get[JdbcProfile].db.run(dBIO)
}
It's not a guess, the compiler can infer the type in this case as the object passed to the method has the type defined:
def execute[T](dBIO:DBIO[T]): Future[T] = configProvider.get[JdbcProfile].db.run(dBIO)
So if you pass a type DBIO[Int], the compiler can fill in the rest:
def execute[Int](dBIO:DBIO[Int]): Future[Int] = configProvider.get[JdbcProfile].db.run(dBIO)
I'm new to Scala and new to higher kinded types. I want to write something like this;
trait Actor[E[Dependency] <: Event[Dependency]] {
def execute(dependency: Dependency): Unit
}
However I can't refer to the type parameter Dependency in the execute method - the compiler doesn't know it.
I'm aware I can solve it in the following way without HKTs, but this isn't what this question is about;
trait Actor[T <: Event[Dependency], Dependency] {
def execute(dependency: Dependency): Unit
}
I'd like to understand why it doesn't work with the higher kinded type syntax that I've tried? Is it possible at all to express this with HKTs? Is this a valid use-case for a HKT?
EDIT
A bit more information, Event looks like this;
trait Event[Data] {
val payload: Data
}
...and I'm looking to define an event and an actor like this;
case class FooEvent(payload: Foo) extends Event[Foo]
class FooActor extends Actor[FooEvent] {
def execute(dependency: Foo) = {}
}
I will try to improve Alexey's answer - he is right, but he is too short. But I must say that I'm not an expert in HKT and I think I'm only starting to understand the concept.
In your code E[Dependency] is the same as E[_] which says that you have E with some type as parameter. This means that you do not operate over Dependency as type. You also do not operate over E or E[Dependency] as the type either. E is a type constructor, and E[Dependency] is an existential type if I understood it correctly. Please note that
trait Actor[E[D] <: Event[D]] { def execute(d: E) {} }
or
trait Actor[E[D] <: Event[D]] { def execute(d: E[D]) {} }
won't compile either.
You need to specify the proper type as an argument for execute:
trait Actor[E[D] <: Event[D]] { def execute[B](d: E[B]) {} }
This one will compile as E[B] is the type in this context.
Updated:
Please take a look at this code:
trait Event[P] {
val payload: P
}
case class FooEvent(payload: Int) extends Event[Int]
trait BaseActor {
type E = Event[P]
type P
def execute(dep: P)
def runEvent(event: E)
}
trait IntActor extends BaseActor {
type P = Int
}
class FooActor extends IntActor {
def execute(dependency: P) = {}
def runEvent(event: E) = {}
}
val c = new FooActor()
c.runEvent(FooEvent(5))
c.execute(5)
Basically the trick is to define type P which is our Dependency and type E = Event[P] which is always Event[Dependency] then you can use the actor by defining P without defining E as it is already defined. Not sure whether it solves the issue, but it looks like a way to go to me. There are also too many types here, some like IntActor is not necessary. I've put them so it is easier to understand the example
However I can't refer to the type parameter Dependency in the execute method - the compiler doesn't know it.
You can't because it isn't a parameter of Actor. Consider
val actor = new Actor[Event] // E is Event
actor.execute(???) // what argument is this supposed to take? I.e. what is Dependency for Actor[Event]?
UPDATE: Given your edit, the [Dependency, T <: Event[Dependency]] option is precisely what you need. When you write Actor[E[Dependency] <: Event[Dependency]], this means E itself has to have a type parameter. And FooEvent doesn't, so Actor[FooEvent] won't compile.
UPDATE 2: You could try using type members as follows:
trait Event {
type Dependency
val payload: Dependency
}
trait Actor {
type E <: Event
def execute(e: E#Dependency)
}
class Foo
case class FooEvent(payload: Foo) extends Event {
type Dependency = Foo
}
class FooActor extends Actor {
type E = FooEvent
def execute(e: Foo) = {}
}
In Scala I want to return a instance of a class for a method defined in a trait which uses generics, the code example I have is this:
File 1
package packOne
import packTwo.A
trait MyTrait[T <: MyTrait[T <: A]] {
def otherFunct(): String
def funct[T <: A](): T
}
File 2
package packTwo
import packOne.MyTrait
abstract class A(someParameter: String) {}
class B(someParameter: String) extends A(someParameter) {}
object B extends MyTrait[B] { // <--- the B inside MyTrait here is the class not the object, or at least that is what I want
def otherFunct(): String = "Hello"
def funct[B](): C = new B("hi") // <--- I think here is the key
}
basically what I want is an interface that have method to return a concrete implementation of class A, in an implementing object (which happen to be a companion object for a class extending A).
Why do I want that to be on an object?, is because I want to call that method without the need of an instance (like an static method in java), so that I can call B.funct() and have an instance of B class kind of like a factory method, for other classes extending A for example a call to X.funct will return an instance of class X.
I have tried to remove the generic type from the function definition except on the return type of the function and just leave it in the trait definition (like def funct(): T) but that does not work either.
I am quite new to Scala so if you could explain it for dummies and avoid complex scala unique concepts I would appreciate
How about simply:
trait A
class B(someParameter: String) extends A
trait MyTrait[T <: A] {
def otherFunct: String //Parentheses on parameterless methods with no side effects and no serious computation are generally unidiomatic in Scala
def funct: T //Note, no generic parameter on this method
}
object B extends MyTrait[B] {
def otherFunct = "Hello"
def funct = new B("hi")
}
And then:
B.funct //returns a new `B`
The apply method is often used in this factory style (e.g. Seq.apply() which is equivalent to Seq())
I'm trying to achieve F-bounded polymorphism without using generics. I also need to use self-typing as I will be referencing this and expecting it to be typed as the subtype.
trait MyTrait[T] { self: Self => // Compilation error: cannot reference 'Self'
type Self <: MyTrait[T]
def doSomethingWithSubtype() {
...
}
}
I can achieve this quite easily using type parameters (i.e. generics), but would like to know if I'm missing something to make the above compile. Can you use abstract types in this way?
Similar questions:
These provide workarounds for similar problems, leading me to believe the above is impossible?
F-Bound Polymorphism with Abstract Types instead of Parameter Types?
F-bounded quantification through type member instead of type parameter?
You can self-type to an abstract type, with one tricky limitation: it has to be defined outside of your trait, but still in scope in a way that allows implementations to implement it with some type. You can do that by wrapping the whole thing into a trait:
trait MyTraitSystem {
type TraitImpl <: MyTrait
trait MyTrait { self: TraitImpl =>
def doSomething(t: TraitImpl): String
}
}
// with an example implementation of the trait:
object MyImpl extends MyTraitSystem {
case class TraitImpl(data: String) extends MyTrait {
def doSomething(t: TraitImpl): String = t.data + " " + data
}
}
This is equivalent to this version using a type parameter:
trait MyTrait[T <: MyTrait[_]] { self: T =>
def doSomething(t: T): String
}
// with an example implementation of the trait:
case class TraitImpl(data: String) extends MyTrait[TraitImpl] {
def doSomething(t: TraitImpl): String = t.data + " " + data
}
Apart from an import MyImpl._ for the abstract-type version, they can be used the same way:
scala> import MyImpl._
import MyImpl._
scala> val a = TraitImpl("hello")
a: MyImpl.TraitImpl = TraitImpl(hello)
scala> val b = TraitImpl("world")
b: MyImpl.TraitImpl = TraitImpl(world)
scala> b.doSomething(a)
res0: String = hello world
The abstract-type version is more verbose, but it works. You also need to carry around a MyTraitSystem in any method/class/... that needs to use TraitImpl so as to provide the type:
object SomewhereElse {
def doSomethingElse(s: MyTraitSystem)(t: s.TraitImpl) =
??? // s.TraitImpl is the implementation type
}
Compared to the type parameter version:
object SomewhereElse {
def doSomethingElse[T <: MyTrait[_]](t: MyTrait[T]) =
??? // T is the implementation type
}
This is probably only one of several ways to do this, but I don't think any way can match the conciseness of the type-parameter-based version.