Comparar objetos en Flutter con el paquete equatable

En este artículo, vamos a ver cómo funciona la igualdad en Flutter y Dart y como el paquete Equatable nos ayuda a tener un código más limpio sin necesidad de escribir tanto código repetitivo.

Ya sabemos que si queremos comparar dos variables podemos usar el operador ==. Por ejemplo, si queremos comparar dos cadenas de texto, el código es:

  final car1 = "Toyota";
  final car2 = "Toyota";
  print(car1 == car2); // Resultado: true

Y si queremos comparar dos números, el código es:

  final phone1 = 52123456;
  final phone2 = 52123456;
  print(phone1 == phone2); // Resultado: true

Veamos el resultado del código anterior en DartPad:

Comparar dos objetos de la misma clase

En los ejemplos anteriores vimos que es muy sencillo comparar dos variables usando == pero cuando queremos comparar dos objetos de la misma clase ya no es tan sencillo.

Si tenemos la siguiente clase:

class Car {
  final String brand;

  Car(this.brand);
}

Y creamos dos objetos:

  final car1 = Car('Toyota');
  final car2 = Car('Toyota');
  print(car1 == car2); // false

A simple vista podemos decir que car1 y car2 son iguales, pero no es cierto. El resultado de comparar car1 y car2 es false

Corramos el código anterior en DartPad:

¿Porque pasa esto si todos sus valores son iguales? La respuesta es simple, en Dart por defecto el operador == verifica la posición en memoria y no las propiedades de cada objeto. Y ya que car1 y car2 están en posiciones de memoria diferente, el resultado de la comparación es false.

Usando el constructor const

Utilizar el constructor const le dice a Dart que solo debe crear una instancia de una clase para un conjunto de valores dados en tiempo de compilación. Corramos el código anterior en DartPad pero esta vez utilizando constructores const:

Podemos ver que usar el constructor const resuelve el problema al comparar dos objetos, pero, esto solo funciona para objetos de los cuales conocemos su valor en tiempo de compilación. No hay forma de utilizar el constructor const en objetos creados en tiempo de ejecución. Es aquí donde entra el paquete Equatable

El paquete Equatable

Sin utilizar el paquete Equatable para comparar las propiedades de dos objetos y ver si son iguales tenemos que sobreescribir == y hashCode. El codigo de la clase Car sera:

class Car {
  final String brand;

  const Car(this.brand);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Car && 
    runtimeType == other.runtimeType && 
    brand == other.brand;

  @override
  int get hashCode => brand.hashCode;
}

Equatable es un paquete que simplifica el proceso de comparar dos objetos de la misma clase sin sobreescribir == y hashCode.

Internamente Equatable sobreescribe == y hashCode para que nosotros no tengamos que perder tiempo escribiendo codigo repetitivo.

Utilizando Equatable el codigo anterior sera:

import 'package:equatable/equatable.dart';

class Car extends Equatable {
  const Car(this.brand);
  
  final String brand;

  @override
  List<Object> get props => [brand];
}

y si agregamos mas propiedades como name el codigo sera:

class Car extends Equatable {
  const Car(this.brand, this.name);

  final String brand;
  final String name;

  @override
  List<Object> get props => [brand, name];
}

Corramos el codigo en DartPad para ver el resultado:

Imporante

Hay un Bug en DartPad que no permite correr el ejemplo con Equatable. https://github.com/dart-lang/dart-pad/issues/2356

Podemos ver que el resultado es true cuando los valores de las propiedades son los mismos. Intenta cambiando los valores de car2 ¿Cuál es el resultado?

Conclusiones

El paquete Equatable es muy importante si queremos comparar dos objetos por el valor de sus propiedades, sin el tendríamos que escribir mucho código repetitivo.

Comparte este artículo