Dart Comparable Interface
last modified June 4, 2025
The Comparable interface in Dart defines how objects should be compared. It enables natural ordering of objects and is used by sorting algorithms.
Classes implementing Comparable must define the compareTo method. This method returns negative, zero, or positive values based on object ordering.
Basic Comparable Implementation
Here's a simple example implementing Comparable for a Person class.
class Person implements Comparable<Person> { final String name; final int age; Person(this.name, this.age); @override int compareTo(Person other) { return age - other.age; } @override String toString() => '$name ($age)'; } void main() { var people = [ Person('Alice', 30), Person('Bob', 25), Person('Charlie', 35) ]; people.sort(); print(people); }
The Person class implements Comparable<Person> and compares by age. The compareTo method returns the age difference. Sorting uses this natural order.
$ dart main.dart [Bob (25), Alice (30), Charlie (35)]
Comparing Multiple Properties
We can implement more complex comparison logic using multiple properties.
class Product implements Comparable<Product> { final String name; final double price; final int rating; Product(this.name, this.price, this.rating); @override int compareTo(Product other) { if (rating != other.rating) { return other.rating - rating; // Higher rating first } return price.compareTo(other.price); // Then lower price } @override String toString() => '$name (\$$price, $rating stars)'; } void main() { var products = [ Product('Laptop', 999.99, 4), Product('Phone', 699.99, 5), Product('Tablet', 499.99, 4) ]; products.sort(); print(products); }
Products are first sorted by rating (descending), then by price (ascending). The compareTo method implements this multi-level comparison logic.
$ dart main.dart [Phone ($699.99, 5 stars), Tablet ($499.99, 4 stars), Laptop ($999.99, 4 stars)]
String Comparison
String already implements Comparable, but we can customize the comparison.
class Book implements Comparable<Book> { final String title; final String author; Book(this.title, this.author); @override int compareTo(Book other) { // Case-insensitive comparison return title.toLowerCase().compareTo(other.title.toLowerCase()); } @override String toString() => '$title by $author'; } void main() { var books = [ Book('Dune', 'Frank Herbert'), Book('1984', 'George Orwell'), Book('animal farm', 'George Orwell') ]; books.sort(); print(books); }
This implements case-insensitive title comparison for books. The built-in String compareTo is used after converting to lowercase.
$ dart main.dart [1984 by George Orwell, animal farm by George Orwell, Dune by Frank Herbert]
Reverse Order Comparison
We can implement reverse ordering by inverting the comparison result.
class Task implements Comparable<Task> { final String description; final DateTime dueDate; Task(this.description, this.dueDate); @override int compareTo(Task other) { // Sort by due date in reverse (newest first) return other.dueDate.compareTo(dueDate); } @override String toString() => '$description (due ${dueDate.toLocalDate()})'; } void main() { var now = DateTime.now(); var tasks = [ Task('Write report', now.add(Duration(days: 3))), Task('Buy groceries', now), Task('Call client', now.add(Duration(days: 1))) ]; tasks.sort(); print(tasks); }
Tasks are sorted by due date in descending order (newest first). We reverse the comparison by comparing other.dueDate to this.dueDate.
$ dart main.dart [Write report (due 2025-04-07), Call client (due 2025-04-05), Buy groceries (due 2025-04-04)]
Using Comparable with Collections
Comparable enables useful operations on collections like min, max, and binarySearch.
class Student implements Comparable<Student> { final String name; final double gpa; Student(this.name, this.gpa); @override int compareTo(Student other) => gpa.compareTo(other.gpa); @override String toString() => '$name (GPA: $gpa)'; } void main() { var students = [ Student('Alice', 3.7), Student('Bob', 3.2), Student('Charlie', 3.9) ]; // Find min and max print('Lowest GPA: ${students.reduce((a, b) => a.compareTo(b) < 0 ? a : b)}'); print('Highest GPA: ${students.reduce((a, b) => a.compareTo(b) > 0 ? a : b)}'); // Binary search requires sorted list students.sort(); var index = students.binarySearch(Student('', 3.7)); print('Alice is at index $index'); }
The Student class enables collection operations through Comparable. reduce finds min/max, and binarySearch quickly locates items in sorted lists.
$ dart main.dart Lowest GPA: Bob (GPA: 3.2) Highest GPA: Charlie (GPA: 3.9) Alice is at index 1
Best Practices
- Consistency: Ensure compareTo is consistent with equals.
- Transitivity: Maintain a < b & b < c ⇒ a < c.
- Null Safety: Handle null values if needed.
- Performance: Keep comparisons efficient for sorting.
Source
This tutorial covered Dart's Comparable interface with practical examples demonstrating object comparison and sorting.
Author
List all Dart tutorials.