Menu
Coddy logo textTech

Palabra clave covariant

Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 61 de 110.

Cuando sobrescribes un método en una subclase, Dart normalmente requiere que los tipos de parámetros coincidan exactamente. Pero a veces quieres que un método de una subclase acepte un tipo más específico que el padre. La palabra clave covariant permite esto.

Considera un escenario donde una clase Animal tiene un método que acepta otro 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');
  }
}

Sin covariant, Dart se quejaría de que Dog no es del mismo tipo que Animal. Al añadir covariant antes del parámetro, le dices a Dart: "Sé que esto es más específico y me aseguraré de que solo se pase el tipo correcto."

Esto es útil cuando las subclases lógicamente solo deberían trabajar con su propio tipo:

void main() {
  Dog dog1 = Dog();
  Dog dog2 = Dog();
  
  dog1.chase(dog2);  // Funciona: Perro persiguiendo a otro perro
}

Ten cuidado, no obstante: el uso de covariant traslada la seguridad de tipos al tiempo de ejecución. Si llamas al método a través de una referencia de padre con el tipo incorrecto, obtendrás un error en tiempo de ejecución en lugar de un error en tiempo de compilación. Úsalo cuando estés seguro de los tipos que se están pasando.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de compatibilidad de mascotas que utiliza la palabra clave covariant para asegurar que las mascotas solo puedan jugar con las de su propia especie. Crearás una jerarquía de mascotas donde cada tipo tiene un método playWith que acepta solo el mismo tipo de mascota.

Organizarás tu código en dos archivos:

  • pets.dart: Define tu jerarquía de mascotas aquí:
    • Una clase Pet con una propiedad String name y un constructor. Incluye un método playWith(Pet other) que imprima '$name plays with ${other.name}'
    • Una clase Cat que extienda de Pet y sobrescriba playWith usando la palabra clave covariant para aceptar solo un Cat. Debe imprimir '$name and ${other.name} chase yarn together'
    • Una clase Dog que extienda de Pet y sobrescriba playWith usando la palabra clave covariant para aceptar solo un Dog. Debe imprimir '$name and ${other.name} fetch the ball together'
    • Una clase Rabbit que extienda de Pet y sobrescriba playWith usando la palabra clave covariant para aceptar solo un Rabbit. Debe imprimir '$name and ${other.name} hop around together'
  • main.dart: Importa tu archivo de mascotas y demuestra cómo cada tipo de mascota juega exclusivamente con los de su propia especie:
    • Crea dos objetos Cat llamados 'Whiskers' y 'Mittens', luego haz que Whiskers juegue con Mittens
    • Crea dos objetos Dog llamados 'Buddy' y 'Max', luego haz que Buddy juegue con Max
    • Crea dos objetos Rabbit llamados 'Flopsy' y 'Cotton', luego haz que Flopsy juegue con Cotton

La palabra clave covariant permite que cada subclase reduzca el tipo de parámetro de Pet a su tipo específico, asegurando interacciones seguras entre tipos de mascotas de la misma especie.

Salida esperada:

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

Hoja de referencia

La palabra clave covariant permite que una subclase sobrescriba un método con un tipo de parámetro más específico que el de la clase padre.

Sin covariant, Dart requiere que los tipos de parámetros coincidan exactamente al sobrescribir métodos. Con covariant, puedes restringir el tipo de parámetro en la subclase:

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');
  }
}

Esto es útil cuando las subclases solo deben funcionar con su propio tipo:

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

Importante: El uso de covariant traslada la seguridad de tipos del tiempo de compilación al tiempo de ejecución. Si llamas al método a través de una referencia del padre con el tipo incorrecto, obtendrás un error en tiempo de ejecución en lugar de un error en tiempo de compilación.

Pruébalo tú mismo

import 'pets.dart';

void main() {
  // TODO: Crear dos objetos Cat llamados 'Whiskers' y 'Mittens'
  // Luego haz que Whiskers juegue con Mittens
  
  
  // TODO: Crear dos objetos Dog llamados 'Buddy' y 'Max'
  // Luego haz que Buddy juegue con Max
  
  
  // TODO: Crear dos objetos Rabbit llamados 'Flopsy' y 'Cotton'
  // Luego haz que Flopsy juegue con Cotton
  
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos