Scala - call method on upper bounded instance - scala

In the code below, there's a DogSearcher which has a method called fetch that expects a Ball. We could also have a CatSearcher with a fetch method that expected a Bell. The idea is that we can call fetch on an instance that inherits from PetSearcher and provide different arguments to it.
Any idea what I'm missing?
trait PetSearcher {
def search(what: Thing): Unit = {
println("default searching")
}
}
class DogSearcher extends PetSearcher {
def search(what: Ball): Unit = {
println("dog searching")
}
}
trait Thing {
val name: String
}
case class Ball(name: String) extends Thing
class Pet {
def fetch[S <: PetSearcher, F <: Thing](searcher: S, what: F): Unit = {
println(what)
searcher.search(what)
}
}
class Dog extends Pet {
val searcher = new DogSearcher()
val ball = new Ball("red")
def go(): Unit = {
fetch[DogSearcher, Ball](searcher, ball)
}
}
//should use DogSearcher but calls fetch on Search, not on DogSearcher.
// So prints default searching, not dog searching..
new Dog().go()

The search method of DogSearch does not override the search method of PetSearcher because the argument types are different (what is a Thing for PetSearcher but a Ball for DogSearcher - the fact that Ball extends Thing is not enough to make the function calls the same).
Let PetSearcher take a type parameter to define the type of what, then DogSearcher can override this (note the override keyword becomes necessary):
trait PetSearcher[T] {
def search(what: T): Unit = {
println("default searching")
}
}
class DogSearcher extends PetSearcher[Ball] {
override def search(what: Ball): Unit = {
println("dog searching")
}
}
To get it to compile, you also need to update the use of PetSearcher in Pet, by adding the type parameter F (the subtype of Thing that this Pet searches for) to the PetSearcher:
def fetch[S <: PetSearcher[F], F <: Thing](searcher: S, what: F): Unit = {

As an alternative to #JamesThorniley's answer, you could define search to accept anything which extends Thing:
trait PetSearcher {
def search[T <: Thing](what: T): Unit = {
println("default searching")
}
}
class DogSearcher extends PetSearcher {
override def search[T <: Thing](what: T): Unit = {
println("dog searching")
}
}
This outputs dog searching as desired.

Related

Aux-like pattern for path dependent types?

Goal: I would like to write
feedImplicitInstance[Cat](new CatFood())`
and have the same effect as
feedExplicitInstance(Cat.CatInstance)(new CatFood())
How can I do that ?
Is it possible to do that at all ?
This is what I tried (but it did not really work):
object DepType extends App{
println("bla")
def feedExplicitInstance[AnimalInstance]
(animal:AnimalTypeClass[AnimalInstance])(food:animal.FoodThatAnimalLikes) = {
animal.feed(food)
}
// Does not compile:
def feedImplicitInstance[AnimalInstance,Food](food:Food)
(implicit animal:AnimalTypeClass[AnimalInstance],aux:Cat.Aux[Food,AnimalInstance]) = {
animal.feed(food)
// Error:(17, 17) type mismatch;
// found : food.type (with underlying type Food)
// required: animal.FoodThatAnimalLikes
// animal.feed(food)
}
feedExplicitInstance(Cat.CatInstance)(new CatFood())
}
trait Food{
def eat():Unit
}
trait AnimalTypeClass [AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f:FoodThatAnimalLikes)=f.eat()
}
trait Cat
class CatFood extends Food{
override def eat(): Unit = println("meow")
}
object Cat {
type Aux[Food,Animal]= AnimalTypeClass[Animal] {type FoodThatAnimalLikes = Food}
implicit object CatInstance extends AnimalTypeClass[Cat]{
override type FoodThatAnimalLikes = CatFood
}
}
First of all, it makes more sense to put Aux in the AnimalTypeClass companion object, and switch the order of its type parameters. Though none of this is required to make it compile.
In order to enable your preferred calling convention of feedImplicitInstance[Cat](new CatFood()) feedImplicitInstance is allowed to have only one type parameter. But Food must be a type parameter because forward references like animal.FoodThatAnimalLikes in parameter lists are not allowed, as you probably noticed yourself. That's why you needed the Aux in the first place. To reconcile those conflicting constraints, you should manually implement a sort of type parameter currying. That's what the Feeder class in the following complete example is for:
object DepType extends App {
def feedExplicitInstance[AnimalInstance]
(animal: AnimalTypeClass[AnimalInstance])(food: animal.FoodThatAnimalLikes) = {
animal.feed(food)
}
class Feeder[AnimalInstance] {
def apply[F <: Food](food: F)(implicit animal: AnimalTypeClass.Aux[AnimalInstance, F]) =
animal.feed(food)
}
def feedImplicitInstance[AnimalInstance] = new Feeder[AnimalInstance]
feedExplicitInstance(Cat.CatInstance)(new CatFood())
feedImplicitInstance[Cat](new CatFood())
}
trait Food{
def eat(): Unit
}
class CatFood extends Food{
override def eat(): Unit = println("meow")
}
trait AnimalTypeClass[AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f: FoodThatAnimalLikes) = f.eat()
}
object AnimalTypeClass {
type Aux[A, F <: Food]= AnimalTypeClass[A] {type FoodThatAnimalLikes = F}
}
trait Cat
object Cat {
implicit object CatInstance extends AnimalTypeClass[Cat]{
override type FoodThatAnimalLikes = CatFood
}
}
If we define Aux like this:
object AnimalTypeClass {
type Aux[A, F] = AnimalTypeClass[A] { type FoodThatAnimalLikes = F }
implicit object CatInstance extends AnimalTypeClass[Cat] {
override type FoodThatAnimalLikes = CatFood
}
}
We can then summon the right implicit typeclass via a method:
def feed[A, F <: Food](f: F)(implicit animalTypeClass: AnimalTypeClass.Aux[A, F]) = {
animalTypeClass.feed(f)
}
And now this compiles and runs:
feed(new CatFood())
I changed the name of the generic type parameters a bit, but they're largely the same as in your example. Just note the implicit instance definition changes.
Using Yuval's answer, this is how my modified code looks like:
object DepType2 extends App{
println("bla")
def feedExplicitInstance[AnimalInstance]
(animal:AnimalTypeClass[AnimalInstance])(food:animal.FoodThatAnimalLikes) = {
animal.feed(food)
}
def feedImplicitInstance[AnimalInstance,Food](food:Food)
(implicit animal:AnimalTypeClass[AnimalInstance],aux:AnimalTypeClass.Aux[Food,AnimalInstance]) = {
aux.feed(food)
}
feedExplicitInstance(AnimalTypeClass.CatInstance)(new CatFood())
feedImplicitInstance(new CatFood())
}
trait Food{
def eat():Unit
}
trait AnimalTypeClass [AnimalInstance] {
type FoodThatAnimalLikes <: Food
def feed(f:FoodThatAnimalLikes)=f.eat()
}
trait Cat
class CatFood extends Food{
override def eat(): Unit = println("meow")
}
object AnimalTypeClass {
type Aux[Food,Animal]= AnimalTypeClass[Animal] {type FoodThatAnimalLikes = Food}
implicit object CatInstance extends AnimalTypeClass[Cat]{
override type FoodThatAnimalLikes = CatFood
}
}
So I had to change animal to aux in feedImplicitInstance and object Cat into object AnimalTypeClass and now everything works fine.
Of course the original question was a little bit trickier:
How can I write feedImplicitInstance[Cat](new CatFood()) ?
Jasper's answer is the answer for the original question. I have not understood his answer yet perfectly - I need to find some time to read carefully, hopefully very soon.

return class extending generic trait in Scala

Scala code:
trait Converter[S, T] {
def convert(source: S): T
}
class StringDuplicatorConverter extends Converter[Integer, String] {
override def convert(source: Integer): String = {
source.toString + source.toString
}
}
// whatever, the point is to show potentially many 'converters'
// from Integer (for example) to something
class SomeOtherConverter extends Converter[Integer, User] {
override def convert(source: Integer): User = {
User(source)
}
}
trait ConverterProvider {
def getConverter[N]: Converter[Integer, N]
}
class MyClass extends ConverterProvider {
override def getConverter[N]: Converter[Integer, N] = {
new StringDuplicatorConverter()
}
}
gives
Error:(17, 5) type mismatch;
found : StringDuplicatorConverter
required: Converter[Integer,N]
new StringDuplicatorConverter()
It may be that what you really want is for each ConverterProvider to provide a converter to a specific type (otherwise the definition of MyClass doesn't make much sense: it should return different converters for different N, not always StringDuplicatorConverter). If so, the correct definition is
trait ConverterProvider[N] {
def getConverter: Converter[Integer, N]
}
class MyClass extends ConverterProvider[String] {
override def getConverter: Converter[Integer, String] = {
new StringDuplicatorConverter()
}
}
Yes. A call to getConverter[N] is supposed to return something of type Converter[Integer,N] but StringDuplicatorConverter is type Converter[Integer,String]. Since N is not restricted to String, and thus they are different types, this won't compile.
If the compiler were given some guarantee that N is a, or super-type of, String then it would work. This can be done by making the return type covariant ...
trait Converter[S, +T] { ...
... and then defining getConverter, and the override, like this:
def getConverter[N >: String]: Converter[Integer, N]
Now it compiles and appears to work.
val mc = new MyClass
mc.getConverter.convert(7) // res0: String = 77

How to make method return type covariant

I have a following classes:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager[T <: Foo](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
And of course update function does not compiles:
Type missmatch found Foo required T
How to make def update: Foo covariant?
Looks like you want something like F-bounded polymorphism:
trait Foo[T <: Foo[T]] { self: T =>
def update: T
}
class ConcreteFoo extends Foo[ConcreteFoo] {
override def update = new ConcreteFoo
}
class FooManager[T <: Foo[T]](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
An alternative, and probably simpler, solution is to use an immutable Map, as Luka said. But then there's no need to have type parameters anymore:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager(private var _foos: immutable.Map[String, Foo]) {
def foos = _foos
def update(id: String): Unit = {
_foos = _foos.updated(id, _foos(id).update)
}
}
You could also keep your current solution and remove the type parameter. But then you have the slight inconvenience that you can't pass a mutable.Map[String,ConcreteFoo] to the constructor of FooManager.
I'd suggest going with an immutable Map instead. As only immutable collections can have covariant type parameters.
class FooManager[+T <: Foo](val foos: immutable.Map[String, T]) {
def update(id: String): FooManager[Foo] = {
new FooManager(foos.updated(id, foos(id).update))
}
}

Using implicits to inject a method at multiple levels of a trait hierarchy

I'm trying to take an existing hierarchy of traits (which I cannot control) and inject a method at the top level (and then override that method at each point in the hierarchy that needs custom treatment). These traits are used implicitly. Below is a trimmed down example that shows the trait hierarchy setup and implicit usage; and then my (failed) attempt to inject a method.
Define a Parent Trait with an unimplemented method, a Child Trait with a specified type and an implemented form of the method. Create an implicit of the Child Trait.
trait ParentTrait[T] {
def doSomething1(x: T): T
}
trait ChildTrait extends ParentTrait[Double] {
override def doSomething1(x: Double): Double = {
return x + 1.0
}
}
implicit object ChildTrait extends ChildTrait
Define a class and function to implicitly use Parent Trait and to call the method.
class Utilizer1() {
def utilize[T](x: T)(implicit trt: ParentTrait[T]): Unit = {
println(trt.doSomething1(x))
}
}
Call the method, specifying the type (Double) which will pick up Child Trait implicitly. (This works fine.)
new Utilizer1().utilize[Double](1.0)
Here's where things don't work: "inject" a new method onto the Parent Trait, and override it in the Child Trait. (Clearly this is not the correct way to do this - how to accomplish this part?)
implicit class BetterParentTrait[T](trt: ParentTrait[T]) {
def doSomething2(x: T): T = ???
}
implicit class BetterChildTrait(trt: ParentTrait[Double]) extends BetterParentTrait[Double](trt) {
override def doSomething2(x: Double): Double = {
return x + 2.0
}
}
Define a class and function to implicitly use Parent Trait and to call the SECOND method.
class Utilizer2() {
def utilize[T](x: T)(implicit trt: ParentTrait[T]): Unit = {
println(trt.doSomething2(x))
}
}
Call the method, specifying the type (Double). It DOES NOT pick up the Child Trait implicitly and instead throws an NotImplementedError. So it does find the doSomething2 method (there are no compilation errors) but it does not respect the hierarchy and uses the unimplemented form from the top level.
new Utilizer2().utilize[Double](1.0)
You are performing aggregation instead of inheritance.
BetterParentTrait[T](trt: ParentTrait[T])
It means utilize method will not see your implicit class as it has different parent / interface.
It has to implement ParentTrait class to be able implicitly passed to mentioned method.
implicit class BetterParentTrait[T] extends ParentTrait[T]{
def doSomething(x: T): T = ???
def doSomething2(x: T): T = ???
}
Does this help?
object MainUtilizers {
trait ParentTrait[T] {
def doSomething1(x: T): T
}
trait ChildTrait extends ParentTrait[Double] {
override def doSomething1(x: Double): Double = {
return x + 1.0
}
}
trait BetterParentTrait[T] {
def doSomething2(x: T): T = ???
}
trait BetterChildTrait extends BetterParentTrait[Double] {
override def doSomething2(x: Double): Double = {
return x + 2.0
}
}
//implicit object ChildTrait extends ChildTrait // Commented to avoid 2 implicits for ParentTrait[Double]
implicit object BetterChildTrait extends BetterChildTrait with ChildTrait
class Utilizer1() {
def utilize[T](x: T)(implicit trt: ParentTrait[T]): Unit = {
println(trt.doSomething1(x))
}
}
class Utilizer2() {
def utilize[T](x: T)(implicit trt: BetterParentTrait[T]): Unit = {
println(trt.doSomething2(x))
}
}
def main(args: Array[String]) {
new Utilizer1().utilize[Double](1.0)
new Utilizer2().utilize[Double](1.0)
}
}

How to specify the return type of a function to be a (arbitrary) monad?

In short, I want to declare a trait like this:
trait Test {
def test(amount: Int): A[Int] // where A must be a Monad
}
so that I can use it without knowing what monad that A is, like:
class Usecase {
def someFun(t: Test) = for { i <- t.test(3) } yield i+1
}
more details...
essentially, I want to do something like this:
class MonadResultA extends SomeUnknownType {
// the base function
def test(s: String): Option[Int] = Some(3)
}
class MonadResultB(a: MonadResultA) extends SomeUnknownType {
// added a layer of Writer on top of base function
def test(s: String): WriterT[Option, String, Int] = WriterT.put(a.test(s))("the log")
}
class Process {
def work(x: SomeUnknownType) {
for {
i <- x.test("key")
} yield i+1
}
}
I wanted to be able to pass any instances of MonadResultA or MonadResultB without making any changes to the function work.
The missing piece is that SomeUnknowType, which I guess should have a test like below to make the work function compiles.
trait SomeUnknowType {
def test(s: String): T[Int] // where T must be some Monad
}
As I've said, I'm still learning this monad thing... if you find my code is not the right way to do it, you're more than welcomed to point it out~
thanks a lot~~
Assuming you have a type class called Monad you can just write
def test[A:Monad](amount: Int): A[Int]
The compiler will require that there is an implicit of type Monad[A] in scope when test is called.
EDIT:
I'm still not sure what you're looking for, but you could package up a monad value with its corresponding type class in a trait like this:
//trait that holds value and monad
trait ValueWithMonad[E] {
type A[+E]
type M <: Monad[A]
val v:A[E]
val m:M
}
object M {
//example implementation of test method
def test(amount:Int):ValueWithMonad[Int] = new ValueWithMonad[Int] {
type A[+E] = Option[E]
type M = Monad[Option]
override val v = Option(amount)
override val m = OptionMonad
}
//test can now be used like this
def t {
val vwm = test(1)
vwm.m.bind(vwm.v, (x:Int) => {
println(x)
vwm.m.ret(x)
})
}
}
trait Monad[A[_]] {
def bind[E,E2](m:A[E], f:E=>A[E2]):A[E2]
def ret[E](e:E):A[E]
}
object OptionMonad extends Monad[Option] {
override def bind[E,E2](m:Option[E], f:E=>Option[E2]) = m.flatMap(f)
override def ret[E](e:E) = Some(e)
}