5

I have the following Kotlin code. A sealed class called Animal, and two object classes Dog and Cat inherits from the sealed class Animal. I am getting this error in the when clause in the is Cat case.

Incompatible types: Cat and Dog

Why is it giving this error? How can I use sealed class in Kotlin to this type operations? Is sealed class a good choice for doing polymorphism?

sealed class Animal {
  abstract fun speak()
}

object Dog : Animal() {
    override fun speak() { println("woof") }
}

object Cat : Animal() {
    override fun speak() { println("meow") }
}

fun main(args: Array<String>) {
    var i = Dog
    i.speak()
    when(i) {
        is Dog -> {
            print("Dog: ")
            i.speak()
        }
        is Cat -> {
            print("Cat: ")
            i.speak()
        }
    }
}
s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
s-hunter
  • 24,172
  • 16
  • 88
  • 130

2 Answers2

7

The missing part is var i: Animal = Dog

Basically compiler is complaining about types - Cat is not a subtype of the Dog (but they are both are subtypes of Animal, that's why if you explicitly set base type code will compile and work

ruX
  • 7,224
  • 3
  • 39
  • 33
  • Are there any benefits of using sealed class vs abstract class in this case? Is sealed class good for doing polymorphism like this? – s-hunter Jan 06 '18 at 00:19
  • @s-hunter, Sealed classes are appropriate when you have a closed set of types and want open functionality. The functionality you add would generally be implemented differently for every type in the set without requiring the types to conform to some common interface. – chris Jan 06 '18 at 00:22
  • @s-hunter well, sealed classes aren't really related with polymorhism, they just give semantics to describe finite hierarchy and use it, for example, in `when` construction – ruX Jan 06 '18 at 00:25
  • 1
    @ruX, It's still polymorphism. If you have an animal and a function that works for any animal, you call the function and the behaviour depends on the actual type of animal you have. You can change the actual type without changing the function call and get different behaviour. The main difference between this and inheritance-based polymorphism is that writing new functions doesn't require modifying anything, but adding new types does. – chris Jan 06 '18 at 00:29
1

Your code has two spots which the compiler, as a whole, does not really understand:

  1. Inside your when clause, you check whether your variable of type Dog really is Dog.
  2. Inside your when clause, you also check whether your variable of type Dog is a Cat.

It's a bit contradictory to the compiler since both types only share a super type with each other. The problem really is that your variable does not explicitly declare its type. As a result of assigning the Dog instance to your var i, the compiler infers its type, which of course is Dog. Everything afterwards makes sense: no need to check for the instance type, it definetly is a Dog.

To make the code work, you have to declare var i: Animal, explicitly typed. Also, always consider using val in favor of var.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196