0

I have the following code

class Person
class Warrior extends Person
trait Commander[A] {
  def giveOrder(to: A)
  def delegate(to: Commander[A])
}

val warCommander: Commander[Warrior] = new Commander[Warrior] {
  override def giveOrder(to: Warrior): Unit = ???
  override def delegate(to: Commander[Warrior]): Unit = ???
}

val president: Commander[Person] = new Commander[Person] {
  override def giveOrder(to: Person): Unit = ???
  override def delegate(to: Commander[Person]): Unit = ???
}

warCommander.giveOrder(new Person) // GOOD ERROR: Person is not a Warrior
president.giveOrder(new Person)
warCommander.delegate(president) // GOOD ERROR: Commander[Person] is not a Commander[Warrior]
president.delegate(warCommander) // UNWANTED ERROR: Commander[Warrior] is not a Commander[Person]

So the last error is not expected but if I make A to be covariant it errors out because then I could say

class Civilian extends Person
val a: Commander[Warrior] = new Commander[Person] { def giveOrder(to: Civilian) ...

which is very confusing, so I can accept that.

So at this point, how to remove the last error and let the compiler understand that a Warrior is a Person?

gurghet
  • 7,591
  • 4
  • 36
  • 63
  • 1
    Your example is a bit confusing... Who should be able to delegate to whom? Person should be able to delegate to another Person and all its subclasses (i.e. Warrior), but Warrior should not be able to delegate to Person? – slouc Sep 06 '19 at 15:13
  • Sorry, there is an error in my question – gurghet Sep 06 '19 at 15:15
  • Why should a `warCommander` (of type `Warrior`) be able to delegate to a `president` (of type `Person`)? Where did you state that intention in your code? – slouc Sep 06 '19 at 15:18
  • Yeah that's the error – gurghet Sep 06 '19 at 15:19
  • Sry I'm completely lost :) You correctly pointed out the three errors as reported by the compiler. Now, if I understand correctly, you would like the warrior -> president delegation to compile without error, right? But I don't see why would you even expect that to compile. Method `delegate` on some type `A` takes the `Commander[A]` as input, meaning that Warrior can only delegate to another Warrior. And if you want to use covariance, then Person should be able to delegate to Person and also a Warrior (because Warrior <: Person, and covariance gives us Commander[Warrior] <: Commander[Person]). – slouc Sep 06 '19 at 15:20
  • No, sorry, ahhh, so a `president` should be able to delegate to a `warCommander`, because a `Warrior` is a subtype of `Person`. Thanks for your patience :) – gurghet Sep 06 '19 at 15:23
  • 1
    Ok then, so it was the *last* error that you want to get rid of after all. – slouc Sep 06 '19 at 15:23

1 Answers1

1

If your intention is for some type A to be able to delegate to A and all types B that are a subtype of A, then you can achieve that without covariance (note the def delegate[B <: A](to: Commander[B])):

class Person
class Warrior extends Person
trait Commander[A] {
  def giveOrder(to: A)
  def delegate[B <: A](to: Commander[B])
}

val warCommander: Commander[Warrior] = new Commander[Warrior] {
  override def giveOrder(to: Warrior): Unit = ???
  override def delegate[B <: Warrior](to: Commander[B]): Unit = ???
}

val president: Commander[Person] = new Commander[Person] {
  override def giveOrder(to: Person): Unit = ???
  override def delegate[B <: Person](to: Commander[B]): Unit = ???
}

warCommander.giveOrder(new Person) // ERROR: Person is not a Warrior
president.giveOrder(new Person)    // OK
warCommander.delegate(president)   // ERROR: Commander[Person] is not a Commander[Warrior]
president.delegate(warCommander)   // OK
slouc
  • 9,508
  • 3
  • 16
  • 41
  • Your question was also correct (if a bit confusing) from the beginning :) I'm glad that after a bit of back-and-forth we managed to resolve it. Cheers – slouc Sep 06 '19 at 15:33