Unable to extend type bounds in scala for implementations - scala

I want to define an abstract variable with type bound in trait and implement in the respective extended class. Something similar to this
trait Animal {
def makeSound(): Unit
}
class Lion extends Animal {
override def makeSound(): Unit = println("Roar")
def scarySound(): Unit = println("Rooooaaarrrrr")
}
trait AnimalCostume {
val animal: _ <: Animal
def locate(): Unit = {
animal.makeSound()
}
}
class LionCostume extends AnimalCostume {
override val animal = new Lion()
def scareEveryOne(): Unit = animal.scarySound()
}
The code is not compiling with the following exception
unbound wildcard type
val animal: _ <: Animal
Can you help in understanding how do I achieve something like this and why it is failing with error that type is not bounded if I have explicitly defined the upper bound here

Related

Scala: how to use an implicit class extension's implementation of a trait

I am trying to provide an extension to a class I can't modify using an implicit class. I have a trait HasFoo[A] that takes a type parameter. I then have a class (Processor) that expects an A that implements HasFoo[A]. The issue is that the compiler doesn't recognize that the Bar class is implementing HasFoo[Bar] via the implicit class extension.
The error is Type argument Bar does not conform to upper bound Playground.HasFoo[Bar]
Is there a way to get the compiler to recognize that the trait HasFoo[Bar] is implemented by the implicit class, or is there a better way to do this?
// Bar is an autogenerated class that I can't modify directly
final case class Bar(baz: String)
trait HasFoo[A] {
def foo: A
}
implicit class Ext(val bar: Bar) extends HasFoo[Bar] {
def foo: Bar = bar.copy(baz = s"${bar.baz} else")
}
class Processor[A <: HasFoo[A]]() {}
// This errors out because type `Bar` doesn't implement `foo`,
// even though the implicit extension does.
val process = new Processor[Bar]()
The class Bar implementing the method def foo from the trait HasFoo doesn't make Bar a subtype of HasFoo.
You can try to make HasFoo a type class rather than just OOP trait (replacing subtype polymorphism and F-bounded polymorphism with ad hoc polymorphism). Third-party classes like autogenerated Bar that can't be modified is exactly a use case for type classes.
// autogenerated class
final case class Bar(baz: String)
// type class
trait HasFoo[A] {
def foo(a: A): A
}
// extension method
implicit class Ext[A: HasFoo](a: A) {
def foo: A = implicitly[HasFoo[A]].foo(a)
}
// Bar is an instance of the type class
implicit val barHasFoo: HasFoo[Bar] = new HasFoo[Bar] {
override def foo(bar: Bar): Bar = bar.copy(baz = s"${bar.baz} else")
}
Bar("baz").foo
// replacing F-bound with context bound
class Processor[A: HasFoo]
val process = new Processor[Bar]
Some intros to type classes:
What are type classes in Scala useful for?
https://kubuszok.com/2018/implicits-type-classes-and-extension-methods-part-1/
https://tpolecat.github.io/2013/10/12/typeclass.html https://tpolecat.github.io/2015/04/29/f-bounds.html
https://books.underscore.io/shapeless-guide/shapeless-guide.html#sec:generic:type-classes (chapter 3.1)
https://www.baeldung.com/scala/type-classes
https://docs.scala-lang.org/scala3/book/types-type-classes.html
https://docs.scala-lang.org/scala3/reference/contextual/type-classes.html
https://gist.github.com/BalmungSan/c19557030181c0dc36533f3de7d7abf4#typeclasses
In principle you can have both type class and OOP trait (for example if you already have many implementations of the OOP trait and you don't want to modify them) although this seems to be overengineering
// autogenerated class
final case class Bar(baz: String)
// OOP trait
trait HasFoo[A] {
def foo: A
}
class HasFooImpl extends HasFoo[HasFooImpl] {
override def foo: HasFooImpl = new HasFooImpl
}
// type class
trait HasFooTC[A] {
def foo(a: A): A
}
implicit class Ext[A: HasFooTC](a: A) extends HasFoo[A] {
override def foo: A = implicitly[HasFooTC[A]].foo(a)
}
// all (F-bounded) implementations of the OOP trait are instances of the type class
implicit def hasFooSubtypes[A <: HasFoo[A]]: HasFooTC[A] = new HasFooTC[A] {
override def foo(a: A): A = a.foo
}
implicit val barHasFoo: HasFooTC[Bar] = new HasFooTC[Bar] {
override def foo(bar: Bar): Bar = bar.copy(baz = s"${bar.baz} else")
}
Bar("baz").foo // extension method
new HasFooImpl().foo // OOP method
class Processor[A: HasFooTC]
val process = new Processor[Bar]
val process1 = new Processor[HasFooImpl]
An alternative to the type class is another pattern, the magnet. Magnets are much less popular than type classes (implicit conversions should be used with caution although the above implicit class actually defined an implicit conversion too)
import scala.language.implicitConversions
// autogenerated class
final case class Bar(baz: String)
// magnet
trait HasFoo[A] {
def foo: A
}
// implicit conversion from Bar to the magnet
implicit def fromBar(bar: Bar): HasFoo[Bar] = new HasFoo[Bar] {
override def foo: Bar = bar.copy(baz = s"${bar.baz} else")
}
Bar("baz").foo
// replacing F-bound with view bound
class Processor[A](implicit ev: A => HasFoo[A])
val process = new Processor[Bar]
Group TypeClass instances by type parameter
Overloading methods based on generics
Type erasure problem in method overloading
How to make a typeclass works with an heterogenous List in scala
Generic function where the return type depends on the input type in Scala?
Problem with bringing into scope scala implicit conversions
https://kubuszok.com/2018/implicits-type-classes-and-extension-methods-part-3/#magnet-pattern
Scala generic method - No ClassTag available for T - when using Collection
Trying to extract the TypeTag of a Sequence of classes that extend a trait with different generic type parameters
As #LuisMiguelMejíaSuárez advices in comments, alternatively a wrapper can be used. This would also work if F-bounded Processor couldn't be modified.
// autogenerated class
final case class Bar(baz: String)
trait HasFoo[A] {
def foo: A
}
final case class BarWrapper(bar: Bar) extends HasFoo[BarWrapper] {
override def foo: BarWrapper = copy(bar = bar.copy(baz = s"${bar.baz} else"))
}
class Processor[A <: HasFoo[A]]
val process = new Processor[BarWrapper]

Getting type class instance through a parent type

I need to provide type class instances for a bunch of case classes all derived from a single trait, but as far as I understand Scala compiler expects an instance for a specific class and doesn't go up the inheritance hierarchy. So this code:
trait Base
sealed trait Child extends Base
case class Concrete() extends Child
trait Printable[A] {
def print(value: A): String
}
object WtfTrait {
def print[A](x: A)(implicit ev: Printable[A]) = {
println(ev.print(x))
}
implicit val printableBase = new Printable[Base] {
override def print(value: Base): String = value.toString
}
val x = Concrete()
print(x)
}
doesn't compile with an error reading could not find implicit value for parameter ev: Printable[Impl]. Is there a way to define a single type class instance for the base trait and avoid repitition maybe by using Shapeless or something.
Guess you mean Printable[Concrete] (that's to say a Show typeclass instance).
Need to update to printableBase definition as bellow:
trait Base
sealed trait Child extends Base
case class Concrete() extends Child
trait Printable[A] {
def print(value: A): String
}
object WtfTrait {
def print[A](x: A)(implicit ev: Printable[A]) = {
println(ev.print(x))
}
// HERE
implicit def printableBase[T <: Base] = new Printable[T] {
override def print(value: T): String = value.toString
}
val x = Concrete()
print(x)
}
Printable can be made contravariant by adding a - sign:
trait Printable[-A]
This makes Printable[X] a subtype of Printable[Y] if Y is a subtype of X. In particular, Printable[Base] is a subtype of Printable[Concrete] and can be used when the compiler looks for an implicit of that type.

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.

Abstract Over TypeClass

Starting with some simple code:
trait Moveable[A] {
def move(a: A): A
}
trait Animal {
def kick[A <: Animal: Moveable](a: A): A = implicitly[Moveable[A]] move a
}
object Cat {
implicit object CatMoveable extends Moveable[Cat] {
def move(cat: Cat): Cat = cat copy (pos = cat.pos + 4)
}
}
case class Cat(pos: Int) extends Animal
case class Dog(pos: Int) extends Animal
val someAnimal: Animal = Dog(0)
val kickedCat: Cat = someAnimal kick Cat(0)
println(kickedCat) // Cat(4)
I decided to distinguish between, let´s say, Quadruped and Biped animals:
trait FourFeetMoveable[A] {
def moveWithFourFeets(a: A): A
}
trait TwoFeetMoveable[A] {
def moveWithTwoFeets(a: A): A
}
trait Animal {
def kick[A <: Animal /*: ??? */](a: A): A
}
trait Quadruped extends Animal {
def kick[A <: Animal: FourFeetMoveable](a: A): A = implicitly[FourFeetMoveable[A]] moveWithFourFeets a
}
trait Biped extends Animal {
def kick[A <: Animal: TwoFeetMoveable](a: A): A = implicitly[TwoFeetMoveable[A]] moveWithTwoFeets a
}
object Chicken {
implicit object ChickenTwoFeetMoveable extends TwoFeetMoveable[Chicken] {
def moveWithTwoFeets(chicken: Chicken): Chicken = chicken copy (pos = chicken.pos + 2)
}
}
case class Dog(pos: Int) extends Quadruped
case class Chicken(pos: Int) extends Biped
val someAnimal: Animal = Dog(0)
val kickedChicken: Chicken = someAnimal kick Chicken(0)
println(kickedChicken) // Chicken(2)
A must have is to have two totally different typeclasses FourFeetMoveable and TwoFeetMoveable, so I can´t abstract over them with something like this:
trait Moveable[A] {
def move(a: A): A
}
So how can I abstract over the typeclasses used as a context bound at method kick in trait Animal(see the ???)?
EDIT
Sorry, I should have made my example clearer. Lets say the effect of being kicked can be some movement or some other action. I wanted to abstract over that effect with a typeclass.
In the following code I am showing what I mean and also used an abstract type member KickingEffect to abstract over the required typeclass, as 0__ proposed:
trait StumbleEffect[A <: Animal] {
def stumble(a: A): A
}
trait GlideEffect[A <: Animal] {
def glide(a: A): A
}
trait Animal {
type KickingEffect[A <: Animal]
def kick[A <: Animal: KickingEffect](a: A): A
}
trait Biped extends Animal {
type KickingEffect[A <: Animal] = StumbleEffect[A]
override def kick[A <: Animal: StumbleEffect](a: A): A = implicitly[StumbleEffect[A]] stumble a
}
trait Quadruped extends Animal {
type KickingEffect[A <: Animal] = GlideEffect[A]
override def kick[A <: Animal: GlideEffect](a: A): A = implicitly[GlideEffect[A]] glide a
}
object Dog {
implicit object DogGlideEffect extends GlideEffect[Dog] {
def glide(dog: Dog): Dog = dog copy (pos = dog.pos + 4)
}
}
case class Dog(pos: Int) extends Quadruped
case class Cat(pos: Int) extends Quadruped
case class Chicken(pos: Int) extends Biped
But then I ran into another problem, when it comes to sequences of animals:
type Beast[A <: Animal, KE[_ <: Animal]] = A { type KickingEffect[X <: Animal] = KE[X] }
val dogBeast: Beast[Dog, GlideEffect] = Dog(0) // fine
type GlideBeasts[A <: Quadruped] = Beast[A, GlideEffect]
val glideBeasts: Seq[GlideBeasts[Quadruped]] = Seq(Dog(0), Cat(0)) // fine
def kickAll[A <: Animal, KE[_ <: Animal], KA <: Animal](kicker: Beast[A, KE])(animals: Seq[KA])(implicit ev: kicker.KickingEffect[KA]): Seq[KA] = {
for (a <- animals) yield kicker kick a
}
val cat = Cat(0)
val dog = Dog(0)
kickAll(cat)(Seq(dog)) // wrong inferred kinds of type arguments
kickAll[Cat, GlideEffect, Dog](cat)(Seq(dog)) // missing implicit evidence
Like this?
trait Moveable[A] {
def move(a: A): A
}
trait FourFeetMoveable[A] extends Moveable[A]
trait TwoFeetMoveable[A] extends Moveable[A]
trait Animal {
type CanKick[A] <: Moveable[A]
def kick[A <: Animal : CanKick](a: A): A = implicitly[CanKick[A]] move a
}
trait Quadruped extends Animal {
type CanKick[A] = FourFeetMoveable[A]
}
trait Biped extends Animal {
type CanKick[A] = TwoFeetMoveable[A]
}
Regarding your edit: I would recommend at this point not to further try to model that with types, unless it is really an extremely crucial point in your application or a pure thought experiment. You can get easily overambitious with type-safe design, then the ratio between design effort and application value is getting to big; I would just drop some compile-time safety and go for pattern matching and runtime errors.
If you do want to follow the types route, as soon as you have collections, you will need something like HLists to preserve the individual types of the collection members.
Anyway, you can make your example work (with explicit type parameters):
def kickAll[A <: Animal, KE[_ <: Animal], KA <: Animal](
kicker: Beast[A, KE])(animals: Seq[KA])(implicit effect: KE[KA]): Seq[KA] = {
for (a <- animals) yield kicker kick a
}
val cat = Cat(0)
val dog = Dog(0)
kickAll(cat)(Seq(dog)) // still doesn't figure out the types
kickAll[Cat, GlideEffect, Dog](cat)(Seq(dog)) // ok!
As said, the tricky or impossible part comes when you try to do this with heterogeneous lists (e.g. requiring different effects). You might get away with using a helper type class for the elements of the sequence, instead, so that implicits can be resolved per item before.
As a side note, I found it always useful to not introduce type bounds till the moment they are really needed. Not only do you safe a lot of typing (no pun intended), but you keep options open (e.g. for later variance annotations). The following is totally sufficient:
trait StumbleEffect[A] {
def stumble(a: A): A
}
trait GlideEffect[A] {
def glide(a: A): A
}
trait Animal {
type KickingEffect[A]
def kick[A : KickingEffect](a: A): A
}
trait Biped extends Animal {
type KickingEffect[A] = StumbleEffect[A]
override def kick[A : StumbleEffect](a: A): A =
implicitly[StumbleEffect[A]] stumble a
}
trait Quadruped extends Animal {
type KickingEffect[A] = GlideEffect[A]
override def kick[A : GlideEffect](a: A): A = implicitly[GlideEffect[A]] glide a
}
etc.

Overriding higher-kinded abstract types in Scala

The following code shows a shallow hierarchy where a type representing a generic binary operation is used to substantiate a parameterized abstract type in another shallow container hierarchy:
trait BinaryOp[A] extends ((A,A) => A)
trait Plus[A] extends BinaryOp[A]
trait Minus[A] extends BinaryOp[A]
trait BaseOps {
type T[A] <: BinaryOp[A]
def apply[B](one: B, two: B)(op: T[B]) = op(one, two)
}
case object PlusOp extends BaseOps {
override type T[A] = Plus[A]
}
case object MinusOp extends BaseOps {
override type T[A] = Minus[A]
}
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
The idea is to be able to state an operation that may be valid for many different types up front, without being tied to a type-specific operation. If I define an expression class generically, all is well
case class Expr[T <: BaseOps](bo: T = PlusOp)
However for my use case it is undesirable for Expr to to be paremeterized:
case class Expr(bo: BaseOps = PlusOp)
The following code fails without a generic Expr:
object App {
val plus = new Plus[Int] {
def apply(i: Int, i2: Int) = i + i2
}
def main(a: Array[String]) {
val exp = Expr(PlusOp)
exp.bo(1,2)(plus)
}
}
The error:
found : App.plus.type (with underlying type java.lang.Object with Plus[Int])
required: exp.bo.T[Int]
exp.bo(1,2)(plus)
This makes it seem as if the type information from the abstract type T[A] <: BinaryOp[A] is not being substantiated with the information in the subtype PlusOp, which overrides the abstract type as T[A] = Plus[A]. Is there any way to work around this without making Expr generic?
With "-Ydependent-method-types",
def Expr(_bo: BaseOps = PlusOp) = new BaseOps {
override type T[A] = _bo.T[A]
val bo: _bo.type = _bo
}
But, I don't know what this precisely means...