I want an object to implement the trait Iterable and pass an additional implicit parameter to the implemented method:
object MyRepository extends Iterable[Something] {
def iterator(implict entityManager: EntityManager): Iterator[Something] = ...
}
Obviously this doesn't work because the iterator method has no implicit parameter and is hence not implemented by the method shown above.
An example use case is the map method which I want to apply to the repository values:
def get = Action {
Transaction { implicit EntityManager =>
val result = MyRepository.map(s => s ...)
}
}
Is there some way to implement the Iterable trait and capture the implicit pramameter?
Given that Iterable.iterator does not have this implicit in its signature, you cannot expect to be able to implement this method while adding this implicit: that would be another method (specifically, another overload).
However, if MyRepositorywas a class rather than an object, you could capture the implicit in the class constructor.
And if you want to keep the same use style (as in MyRepository.map{ ... } rather than new MyRepository.map{ ... }), what you can do is to provide an implicit conversion from the object to the class.
Here is an example:
object MyRepository {
class MyRepositoryIterable(implicit entityManager: EntityManager) extends Iterable[Something] {
def iterator: Iterator[Something] = ???
}
implicit def toIterable(rep: MyRepository.type)(implicit entityManager: EntityManager): MyRepositoryIterable = new MyRepositoryIterable
}
What happens now when you do MyRepository.map(...) is that the object gets implicitly converted into an instance of MyRepositoryIterable which captures the implicit EntityManager value. The MyRepositoryIterable is the class that actually implements Iterable.
Related
Imagine I have a service:
class ServiceA(serviceB: ServiceB) {
import Extractor._
def send(typeA: A) = serviceB.send(typeA.extract)
}
object Extractor {
implicit class Extractor(type: A) {
def extract = ???
}
}
I want the extract method to be an implicitly defined because it doesn't directly relate to A type/domain and is a solution specific adhoc extension.
Now I would like to write a very simple unit test that confirms that serviceB.send is called.
For that, I mock service and pass a mocked A to send. Then I could just assert that serviceB.send was called with the mocked A.
As seen in the example, the send method also does some transformation on typeA parameter so I would need to mock extract method to return my specified value. However, A doesn't have extract method - it comes from the implicit class.
So the question is - how do I mock out the implicit class as in the example above as imports are not first class citizens.
If you want to specify a bunch of customised extract methods, you can do something like this:
sealed trait Extractor[T] {
// or whatever signature you want
def extract(obj: T): String
}
object Extractor {
implicit case object IntExtractor extends Extractor[Int] {
def extract(obj: Int): String = s"I am an int and my value is $obj"
}
implicit case object StringExtractor extends Extractor[String] {
def extract(obj: String): String = s"I am "
}
def apply[A : Extractor](obj: A): String = {
implicitly[Extractor[A]].extract(obj)
}
}
So you have basically a sealed type family that's pre-materialised through case objects, which are arguably only useful in a match. But that would let you decouple everything.
If you don't want to mix this with Extractor, call them something else and follow the same approach, you can then mix it all in with a context bound.
Then you can use this with:
println(Extractor(5))
For testing, simply override the available implicits if you need to. A bit of work, but not impossible, you can simply control the scope and you can spy on whatever method calls you want.
e.g instead of import Extractor._ have some other object with test only logic where you can use mocks or an alternative implementation.
We've got several types of resources and we wanted to make a method to check if a resource is healthy or not. Given that the type of resources are very heterogeneous we didn't want to use standard subclassing and we decided to use a typeclass:
trait CanHealthCheck[T] {
def isHealthy(t: T): Boolean
}
We also have a utility method to be able to check if a given resource is alive/healthy or not
object LivenessChecker {
def isAlive[T](t: T)(implicit canHealthCheck: CanHealthCheck[T]): Boolean = {
canHealthCheck.isHealthy(t)
}
}
We've got a repository layer to access to the data. We would like to express the idea that a given abstract repository must be "health checkable" but to leave the implementation details to the subclasses implementing the trait:
trait UserRepository {
def findSomeUser(): User = ???
implicit def isHealthCheckable: CanHealthCheck[UserRepository]
}
The problem arises when we want to subclass UserRepository with a particular implementation, given that CanHealthCheck is not covariant on the type T.
class DbUserRepository extends UserRepository {
def ping: Boolean = ???
override implicit val isHealthCheckable: CanHealthCheck[UserRepository] =
new CanHealthCheck[DbUserRepository] {
def isHealthy(db: DbUserRepository) = db.ping
}
}
And this is an example of some dummy function that acts on the abstract repository while trying to check if the repository is alive:
def someDummyFunction(userRepository: UserRepository) = {
if(LivenessChecker.isAlive(userRepository)) // This won't compile
userRepository.findSomeUser()
}
The idea is that our application uses the UserRepository trait and not the implementation, and thus we cannot check whether the repository is alive or not. How can we continue using the repository abstraction layer and be able to check if a given (abstract) repository is alive? Is the typeclass pattern the correct pattern to use here?
There is something a bit fishy with isHealthCheckable inside UserRespository. The isHealthy method, when called, would have two instances of UserRepository available: of course, the one passed as the t argument, but also, the UserRepository.this of the enclosing instance.
This is a sign of something wrong. Either the method should be written somewhere else, so that it does not get enclosing this, or it should not get the argument
That second option is consistent with using UserRepository the object-oriented, subtyping way. Also, it is consistent with your idea that every UserRepository must be heath-checkable. Just do
trait UserRepository {
...
def isHealty: Boolean
}
It is fine to call that directly, userDirectory.isHealthy. But you can then also easily implement the type class:
object UserRepository {
implicit val canHealthCheck = new CanHealthCheck[UserRepository] {
def isHealthy(repository: UserRepository) = repository.IsHealthy
}
}
also note that it was not clear at all how the implicit instance method would have come into the implicit scope. With the companion object, it works fine.
Use "type bounds".
I couldn't test this, but to get the code to compile, you could do something like:
class DbUserRepository[U <: UserRepository] extends UserRepository {
def ping: Boolean = ???
implicit val isHealthCheckable: CanHealthCheck[U] =
new CanHealthCheck[U] {
def isHealthy(db: U) = db.ping
}
}
trait UserRepository {
def findByFirstName(firstName: String): Seq[User]
}
trait UserBusinessDelegate extends UserRepository {
abstract override def findByFirstName(firstName: String) = {
super.findByFirstName(firstName)
}
}
class MockUserRepository extends UserRepository {
override def findByFirstName(firstName: String) = {
// whatever
}
}
val userRepository = new MockUserRepository with UserBusinessDelegate
userRepository.findByFirstName("John") // OK
However, if I change UserBusinessDelegate as follows:
trait UserBusinessDelegate {
self: UserRepository =>
override def findByFirstName(firstName: String): Seq[User] = {
self.findByFirstName(firstName) // requires explicit return type, thinks this is a recursive call
}
}
val userRepository = new MockUserRepository with UserBusinessDelegate
userRepository.findByFirstName("John") // StackOverflow!!!
I understand stackable pattern and hence how the first case works. My question is why the 2nd doesn't.
In the second snippet you have a recursive call without an exit condition:
override def findByFirstName(firstName: String): Seq[User] = {
self.findByFirstName(firstName)
}
This will always call findByFirstName from UserBusinessDelegate (because you're using self, which basically says that this object will have this kind of behaviour at runtime, not that it's parent will have it and therefore we should call parent's method) creating a new stack frame with each call -> stack overflow.
In the second snippet UserBusinessDelegate's findByFirstName will be called and then you call MockUserRepository's method from it using super -> no recursion -> no stack overflow. You can check Scala's stackable trait pattern for more info.
#Edit: to make it more clear, in the snippet that throws a SO exception the findByFirstName method from MockUserRepository won't be called because you are overriding it in UserBusinessDelegate therefore the anonymous class created with new MockUserRepository with UserBusinessDelegate will only contain the overriden method and that's why the SO, is that clear?
Why would you assume that the method from MockUserRepository would get invoked?
#Edit2: the code doesn't compile without override because self: UserRepository => tells the compiler that a method with such a signature will already be there at runtime and you cannot have 2 methods with the same signature. The first example works only because it's a stackable trait, such traits are dynamically bound and can modify the behaviour but have to call super at some point (which normally isn't allowed without the abstract override modifier, I really recommend going through the link I posted about stackable pattern).
Maybe someone else knows a way, from what I know there's no way to call the mock method unless you change the method name in UserBusinessDelegate and drop the override, then you can call self.findByFirstName and it will call the method from MockUserRepository.
I can't understand why I need () and hence where MyTypeQueOrdering goes.
Here is header of PriorityQueue, found on official github:
class PriorityQueue[A](implicit val ord: Ordering[A])
Here is my try (which works):
class MyType{
}
object MyTypeQueOrdering extends Ordering[MyType]{
def compare (n1:MyType, n2:MyType) = -1
}
class MyTypeQue extends PriorityQueue[MyType]()(MyTypeQueOrdering){
}
... but I can't figure out why I need (). Does PriorityQueue[MyType]() return something?
Try making MyTypeQueOrdering an implicit object:
object Implicits {
//implicit objects can't be top-level ones
implicit object MyTypeQueOrdering extends Ordering[MyType] {
def compare(n1: MyType, n2: MyType) = -1
}
}
This way you can omit both parentheses:
import Implicits._
class MyTypeQue extends PriorityQueue[MyType] { ... }
The reason you need the empty parentheses in your example is because PriorityQueue[MyType](MyTypeQueOrdering) would assume you're trying to pass the ordering as a constructor parameter. So that's why you need to explicitly show no-arg instantiation and then passing the ordering
I'm writing a Play! 2.1 application using ReactiveMongo. each persistable case class has an object that holds 2 implicit objects, implementing BSONReader[...] and BSONWriter[...], and each case class has methods to return these:
trait Persistable {
implicit def getReader: BSONReader[Persistable]
implicit def getWriter: BSONWriter[Persistable]
val collectionName: String
}
case class MyObj () extends Persistable {
override val collectionName: String = MyObj.collectionName
override def getReader: BSONReader[MyObj] = MyObj.MyObjBSONReader
override def getWriter: BSONWriter[MyObj] = MyObj.MyObjBSONWriter
}
object MyObj{
val collectionName: String = "MyObj"
implicit object MyObjBSONReader extends BSONReader[MyObj] {
def fromBSON(document: BSONDocument): MyObj = {
val doc = document.toTraversable
new MyObj(
)
}
}
implicit object MyObjBSONWriter extends BSONWriter[MyObj] {
def toBSON(myObj: MyObj) = {
BSONDocument(
)
}
}
for some reason, getReader seems to work fine, but getWriter errors:
overriding method getWriter in trait Persistable of type =
reactivemongo.bson.handlers.BSONWriter[models.persistable.Persistable];
method getWriter has incompatible type
what am i doing wrong? both seem to have similar signatures.
another hint is that if i remove the return type from getWriter, i get complie time error in eclipse:
type mismatch; found : models.persistable.MyObj.MyObjBSONWriter.type required:
reactivemongo.bson.handlers.BSONWriter[models.persistable.Persistable]
UPDATE:
I did as #AndrzejDoyle said below, but then the implementation of Persister, which was the heart of this exercise, complains:
def insert(persistable: Persistable) = {
val collection = db(persistable.collectionName)
import play.api.libs.concurrent.Execution.Implicits._
implicit val reader = persistable.getReader
implicit val writer = persistable.getWriter
collection.insert(persistable)
}
error:
trait Persistable takes type
parameters
It is due to covariance and contravariance.
The mongodb reader is defined as BSONReader[+DocumentType]. The + in the generic parameter, means that this class is covariant in that parameter. Or more fully,
If B is a subclass of A, then BSONReader[B] is a subclass of BSONReader[A].
Therefore you can use a BSONReader[MyObj] everywhere that a BSONReader[Persistable] is required.
On the other hand, the writer is contravariant: BSONWriter[-DocumentType]. This means that
If B is a subclass of A, then BSONWriter[B] is a superclass of BSONWriter[A].
Therefore your BSONWriter[MyObj] is not a subclass of BSONWriter[Persistable], and so cannot be used in its place.
This might seem confusing initially (i.e. "why does contravariance make sense when it's 'backwards'?"). However if you think about what the classes are doing, it becomes clearer. The reader probably produces some instance of its generic parameter. A caller then might expect it to produce a Persistable - if you have a version that specifically produces MyObjs instead then this is fine.
The writer on the other hand, is probably given an object of its generic parameter. A caller with a BSONWriter[Persistable] will call the write() method, passing in an instance of Persistable to be written. Your implementation can only write instances of MyObj, and so it doesn't actually match the interface. On the other hand, a BSONWriter[Object] would be a subclass of any BSONWriter, since it can (from a type perspective) accept any type as an argument.
The fundamental problem seems to be that your Persistable trait is looser than you intended. You probably want each implementation to return a reader and writer parameterized on itself, rather than on Persistable in general. You can achieve this via self-bounded generics:
trait Persistable[T <: Persistable[T]] {
implicit def getReader: BSONReader[T]
implicit def getWriter: BSONWriter[T]
val collectionName: String
}
and then declare the class as MyObj[MyObj]. Now the reader and writer are expected to be parameterised on MyObj, and your existing implementations will compile.