Google has announced the launch of Dart 3, the most significant update to the Dart programming language yet. This latest version heralds three major advancements: complete null security, major new language features for records, patterns, and class modifiers, and expanded platform support with web-native code via Wasm compilation. Let’s delve into these features in detail.
let’s take a quick look at the core features of Flutter:
Beautiful: Flutter allows you to create visually stunning user interfaces with its rich set of customizable widgets and powerful design capabilities.
Fast: Flutter’s reactive framework and optimized rendering engine enable high-performance applications that run smoothly and respond quickly to user interactions.
Productive: Flutter offers a hot reload feature, allowing developers to instantly see the changes they make to the code, resulting in a highly efficient and iterative development process.
Portable: With Flutter, you can build apps for multiple platforms, including iOS, Android, web, and even desktop, using a single codebase. This cross-platform compatibility saves time and effort in development.
Open source: Flutter is an open-source framework, backed by Google, which means it has a vibrant and supportive community. It provides access to a wide range of libraries, tools, and resources, empowering developers to create innovative and feature-rich applications.
Let’s explore the feature release of Dart 3.0, which includes three major improvements:
1. Full-fledged null safety:
With Dart 3.0, all code now has sound null safety. This leads to several benefits, such as reducing runtime errors from nulls, smaller compiled output, and improved performance.
2. Patterns:
Dart 3.0 introduces a new feature called “Patterns.” Let’s delve into the details.
- Records: Records help in building structured data and destructure it back into individual elements without any extra boilerplate, similar to Pair<V1, V2>.
// Here we are building structured data, a pair of doubles
(double, double) getLocation(String place) {
return (27.54, 98.65);
}
void main() {
// Here we are destructuring back into the individual elements
var (lat, lng) = getLocation('New Delhi');
print('lat $lat, lng $lng');
}
- Switch expression: This feature eliminates a lot of boilerplate from switch case and multiple if..elseif statements
import 'dart:math' as math;
sealed class Shape {}
class Square implements Shape {
final double length;
Square(this.length);
}
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
/// this method used older approach for switch case
double calculateAreaWithOlderApproach(Shape shape) {
switch (shape.runtimeType) {
case Square:
double length = (shape as Square).length;
return length * length;
case Circle:
double radius = (shape as Circle).radius;
return radius * radius * math.pi;
default:
return 0.0;
}
}
/// this method used newer approach for switch case and lines of code has been reduced
double calculateAreaWithNewApproach(Shape shape) => switch (shape) {
Square(length: double l) => l * l,
Circle(radius: double r) => r * r * math.pi
};
void main() {
double area = calculateAreaWithOlderApproach(Circle(5));
print('Area from old approach: $area');
area = calculateAreaWithNewApproach(Circle(5));
print('Area from new approach: $area');
}
extension DescribeDate on DateTime {
void describe() {
final now = DateTime.now();
final difference = this.difference(DateTime(now.year, now.month, now.day));
String description = switch (difference) {
Duration(inDays: -1) => 'Yesterday',
Duration(inDays: 0) => 'Today',
Duration(inDays: 1) => 'Tomorrow',
Duration(inDays: int d, isNegative: true) => '${d.abs()} days ago',
Duration(inDays: int d, isNegative: false) => '$d days from now',
};
print('$year/$month/$day is $description');
}
}
main() {
DateTime(2023, 5, 16).describe();
DateTime(2023, 5, 17).describe();
DateTime(2023, 5, 18).describe();
DateTime(2023, 5, 10).describe();
DateTime(2023, 5, 25).describe();
}
3. Class modifiers:
Dart 3.0 introduces several class modifiers to enhance code structure and inheritance patterns.
- interface: If a class is declared as an interface, other classes can implement it but can’t inherit from it. Objects can be created for interfaces. This will solve the problem where changes in the base class can break classes that inherit from it.
// Can be constructed and implemented, but not extended nor mixed in.
interface class Shape {
double area() => 10*10;
}
class Rect implements Shape {
@override
double area() => 10.0 * 5.0;
}
void main() {
Shape shape = Shape();
print('Area from shape: ${shape.area()}');
Shape rect = Rect();
print('Area from rect: ${rect.area()}');
}
2. abstract: Abstract classes are those that can’t be instantiated directly. They usually contain one or more abstract methods which must be implemented by any concrete (i.e., non-abstract) subclass.
abstract class Shape {
double area();
}
class Rect implements Shape {
@override
double area() => 10.0 * 5.0;
}
void main() {
// instance can't be created
//Shape shape = Shape();
Shape rect = Rect();
print('Area from rect: ${rect.area()}');
}
3. base: This modifier ensures that the implementation of a class or mixin is inherited. A base class restricts implementation outside of its own library, providing guarantees such as always calling the base class constructor when creating a subtype.
4. final: A final class cannot be subclassed. This is beneficial when you want to prevent other developers from extending your class and potentially misusing it.
5. sealed: A sealed class shares similarities with a final class, as it cannot be extended outside the library where it is defined. However, within the confines of the same library, it allows for subclassing.
6. mixin: A mixin allows for the reuse of a class’s code in multiple class hierarchies.
No modifier: If no modifier is used, the class or mixin can be freely used. It can be instantiated, subclassed, or mixed in without any restrictions..
4. WASM (WebAssembly):
To start, let's dive into what WebAssembly (WASM) is in simple terms. Have you ever used Photoshop or Figma and had to download a large application to your desktop? What if you could access these tools directly in your web browser without any installation or configuration? That's where WASM comes into play.
Traditional web applications are built using HTML, CSS, and JavaScript frameworks like React or VueJS. While these tools can create beautiful web pages and games, they have their limitations. Complex applications like Photoshop and high-end video games are typically develped in programming langages like C, C++, or Rust and run as an executable deskt0p application.
But with WASM, these complex applications can be ported to work online within browsers. It's essentially a new type of code that can be used alongside traditional web languages. WASM allows developers to write code in other programming languages and compile it to run in the browser. This means, we can now access applicatons like Figma or play high-end games directly in our web browsers without the need for any installation or configuration.
Traditionally, programming languages are written in a format that computers cannot understand. Therefore, we need to convert the source code written in a programming language into a machine-understandable code through a process called compilation. The transformed code format is referred to as a compilation target.
WebAssembly is a new type of compilation target for langages such as C, C++, and Rust, used to run native apps inside web browsers. To create a WebAssembly binary file (.wasm), the native code is compiled using an online asembler such as WASMExplorer or WASMFiddle or a tool like Emscripten.
The resulting binary file can be loaded and run within the browser alongside Javascript code and can interact with the Javascript code using Javascript WebAssembly APIs. This enables high-performance applications like native desktop programs, video games, and image editors to be run directly within web browsers without requiring any additional installations or plugins.
Integrate with Flutter Web
We will add the .wasm
generated above in our assets.
As we know that, we can call Javascript functions inside the Flutter Web, we will utilize this feature. But during my research, I found a package (wasm_interop) that does all the JS interactions for us.