Menu
Coddy logo textTech

Covariant Keyword

Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 61 of 110.

When you override a method in a subclass, Dart normally requires the parameter types to match exactly. But sometimes you want a subclass method to accept a more specific type than the parent. The covariant keyword allows this.

Consider a scenario where an Animal class has a method that accepts another Animal:

class Animal {
  void chase(Animal other) {
    print('Chasing an animal');
  }
}

class Dog extends Animal {
  @override
  void chase(covariant Dog other) {
    print('Dog chasing another dog');
  }
}

Without covariant, Dart would complain that Dog isn't the same type as Animal. By adding covariant before the parameter, you tell Dart: "I know this is more specific, and I'll ensure only the right type is passed."

This is useful when subclasses logically should only work with their own kind:

void main() {
  Dog dog1 = Dog();
  Dog dog2 = Dog();
  
  dog1.chase(dog2);  // Works: Dog chasing another dog
}

Be careful though - using covariant shifts type safety to runtime. If you call the method through a parent reference with the wrong type, you'll get a runtime error instead of a compile-time error. Use it when you're confident about the types being passed.

challenge icon

Challenge

Easy

Let's build a pet compatibility system that uses the covariant keyword to ensure pets can only play with their own kind. You'll create a hierarchy of pets where each type has a playWith method that accepts only the same type of pet.

You'll organize your code into two files:

  • pets.dart: Define your pet hierarchy here:
    • A Pet class with a String name property and a constructor. Include a method playWith(Pet other) that prints [name] plays with [other.name]
    • A Cat class that extends Pet and overrides playWith using the covariant keyword to accept only a Cat. It should print [name] and [other.name] chase yarn together
    • A Dog class that extends Pet and overrides playWith using the covariant keyword to accept only a Dog. It should print [name] and [other.name] fetch the ball together
    • A Rabbit class that extends Pet and overrides playWith using the covariant keyword to accept only a Rabbit. It should print [name] and [other.name] hop around together
  • main.dart: Import your pets file and demonstrate how each pet type plays exclusively with its own kind:
    • Create two Cat objects named 'Whiskers' and 'Mittens', then have Whiskers play with Mittens
    • Create two Dog objects named 'Buddy' and 'Max', then have Buddy play with Max
    • Create two Rabbit objects named 'Flopsy' and 'Cotton', then have Flopsy play with Cotton

The covariant keyword allows each subclass to narrow the parameter type from Pet to its specific type, ensuring type-safe interactions between pets of the same kind.

Expected output:

Whiskers and Mittens chase yarn together
Buddy and Max fetch the ball together
Flopsy and Cotton hop around together

Cheat sheet

The covariant keyword allows a subclass to override a method with a more specific parameter type than the parent class.

Without covariant, Dart requires parameter types to match exactly when overriding methods. With covariant, you can narrow the parameter type in the subclass:

class Animal {
  void chase(Animal other) {
    print('Chasing an animal');
  }
}

class Dog extends Animal {
  @override
  void chase(covariant Dog other) {
    print('Dog chasing another dog');
  }
}

This is useful when subclasses should only work with their own type:

void main() {
  Dog dog1 = Dog();
  Dog dog2 = Dog();
  
  dog1.chase(dog2);  // Works: Dog chasing another dog
}

Important: Using covariant shifts type safety from compile-time to runtime. If you call the method through a parent reference with the wrong type, you'll get a runtime error instead of a compile-time error.

Try it yourself

import 'pets.dart';

void main() {
  // TODO: Create two Cat objects named 'Whiskers' and 'Mittens'
  // Then have Whiskers play with Mittens
  
  
  // TODO: Create two Dog objects named 'Buddy' and 'Max'
  // Then have Buddy play with Max
  
  
  // TODO: Create two Rabbit objects named 'Flopsy' and 'Cotton'
  // Then have Flopsy play with Cotton
  
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming