DEV Community

Cover image for Top features of Dart3: Introduction
Harsh Bangari Rawat
Harsh Bangari Rawat

Posted on

Top features of Dart3: Introduction

1. Pattern Matching and Enhanced Control Flow

  • Switch Expressions with Patterns: Go beyond simple value comparisons in switch statements. Use patterns to match complex data structures and their properties:
enum Season { spring, summer, autumn, winter }

String describeSeason(Season season) {
  switch (season) {
    case Season.spring:
      return 'Time for flowers!';
    case Season.summer:
      return 'Get ready for the beach!';
    case Season.autumn:
      return 'Leaves are changing!';
    case Season.winter:
      return 'Bundle up!';
  }
}

void main() {
  print(describeSeason(Season.summer)); // Output: Get ready for the beach!
}
Enter fullscreen mode Exit fullscreen mode
  • If-Case Statements: Similar to pattern matching in switch, you can now use if statements with case clauses for more concise conditional logic:
String getGreeting(int timeOfDay) {
  if (timeOfDay < 12) {
    return 'Good morning!';
  } else if (timeOfDay < 17) {
    return 'Good afternoon!';
  } else {
    return 'Good evening!';
  }
}

void main() {
  print(getGreeting(10)); // Output: Good morning!
}
Enter fullscreen mode Exit fullscreen mode

2. Records: Lightweight Data Structures

  • Immutable and Concise: Create anonymous, immutable data structures without defining a full class. Ideal for returning multiple values from functions:
Point getLocation() {
  return const Point(x: 10, y: 20); // Concise record creation
}

void main() {
  final point = getLocation();
  print(point.x); // Output: 10 (Records provide property access)
}
Enter fullscreen mode Exit fullscreen mode

3. Destructuring with Pattern Matching

  • Extract Values from Data Structures: Elevate code readability by extracting values directly from patterns in assignments:
void processPerson(Person person) {
  final name = person.name;
  final age = person.age;
  // ... use name and age
}

void main() {
  final person = Person(name: 'Alice', age: 30);
  processPerson(person);

  // With destructuring:
  final Person(name, age) = person; // Extract name and age directly
  // ... use name and age
}
Enter fullscreen mode Exit fullscreen mode

4. Class Modifiers for Enhanced Control

  • sealed: Restrict subclasses and ensure all possible cases are handled when using a class hierarchy.
sealed class Shape {
  const Shape();
}

class Circle extends Shape {
  final double radius;
  const Circle(this.radius);
}

class Square extends Shape {
  final double sideLength;
  const Square(this.sideLength);
}

void main() {
  // Compile-time error: Triangle is not a subclass of sealed class Shape
  // class Triangle extends Shape {}
}
Enter fullscreen mode Exit fullscreen mode
  • abstract: Enforce subclasses to implement abstract methods and prevent direct instantiation of the abstract class.
abstract class HospitalStaff {
  // Abstract method - subclasses must define work behavior
  void performDuties();

  String get name; // Concrete property (optional)
}

class Doctor extends HospitalStaff {
  final String specialization;

  Doctor(this.name, this.specialization);

  @override // Ensures correct implementation
  void performDuties() {
    print('$name the doctor is diagnosing patients.');
  }
}

class Nurse extends HospitalStaff {
  final String department;

  Nurse(this.name, this.department);

  @override
  void performDuties() {
    print('$name the nurse is assisting patients in the $department department.');
  }
}

void main() {
  // Cannot directly create a HospitalStaff object
  // HospitalStaff staff = HospitalStaff(); // Compile-time error

  // Create concrete subclass objects (Doctor and Nurse)
  Doctor drAmitJ = Doctor('Dr. Amit J', 'Cardiology');
  Nurse varshaK = Nurse('Varsha K', 'Emergency');

  drAmitJ.performDuties(); // Dr. Amit J the doctor is diagnosing patients.
  varshaK.performDuties();  // Varsha K the nurse is assisting patients in the Emergency department.
}
Enter fullscreen mode Exit fullscreen mode
  • mixin: Promote code reusability by allowing multiple classes to inherit behavior from a mixin.
mixin Treatable {
  // Abstract method - subclasses must define treatment behavior
  void provideTreatment();

  String get diagnosis; // Optional property
}

class Doctor {
  final String name;
  final String specialization;

  Doctor(this.name, this.specialization);

  void performDuties() {
    print('$name the doctor is diagnosing patients.');
  }
}

class Nurse extends HospitalStaff {
  final String department;

  Nurse(this.name, this.department);

  void performDuties() {
    print('$name the nurse is assisting patients in the $department department.');
  }
}

class Patient with Treatable {
  final String name;
  final String condition;

  Patient(this.name, this.condition);

  @override
  void provideTreatment() {
    print('Providing treatment for $condition to $name.');
  }

  // Can inherit diagnosis from Treatable if needed
}

void main() {
  // Doctor and Nurse classes remain unchanged

  Patient raviKumar = Patient('Ravi Kumar', 'Flu');
  raviKumar.provideTreatment(); // Providing treatment for Flu to Ravi Kumar.
}
Enter fullscreen mode Exit fullscreen mode
  • non-nullable: Enforce non-null semantics on specific class members for stricter type safety.
class Patient {
  final String name; // Non-nullable - must be initialized with a value

  // Can be nullable if a patient might not have a diagnosis yet
  final String? diagnosis;

  Patient(this.name, {this.diagnosis});
}

class Doctor {
  final String name;
  final String specialization; // Non-nullable - specialization is required

  Doctor(this.name, this.specialization);

  void treatPatient(Patient patient) {
    if (patient.diagnosis != null) { // Check for null before accessing diagnosis
      print('Dr. $name is treating $patient.name for ${patient.diagnosis}.');
    } else {
      print('Dr. $name is examining $patient.name.');
    }
  }
}

void main() {
  Patient raviKumar = Patient('Ravi Kumar'); // Valid - name is non-nullable
  // Patient raviKumar; // Error: 'name' must be initialized

  Doctor drAmit = Doctor('Dr. Amit J', 'Cardiology'); // Valid - both fields are non-nullable

  drAmit.treatPatient(raviKumar); // Outputs: Dr. Amit J is examining Ravi Kumar. (diagnosis is null)
}
Enter fullscreen mode Exit fullscreen mode

Want to learn more about Dart3? Check out the resources link!

Until next time, keep calm and code on.🧑🏻‍💻

Top comments (0)