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.🧑🏻‍💻

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs