Today’s article is a short revelation of the cool features that the dart language offers. More often these options are not necessary for simple apps but are a lifesaver when you want to improve your code by making it simple, clear, and concise.
With that in mind let’s go.
Cascade notation
Cascades (..
, ?..
) allow you to make a sequence of operations on the same object. This often saves you the step of creating a temporary variable and allows you to write more fluid code.
var paint = Paint(); paint.color = Colors.black; paint.strokeCap = StrokeCap.round; paint.strokeWidth = 5.0; //above block of code when optimized var paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5.0;
Abstract classes
Use the abstract
modifier to define an abstract class (a class that can’t be instantiated). Abstract classes are useful for defining interfaces, often with some implementation.
// This class is declared abstract and thus // can't be instantiated. abstract class AbstractContainer { // Define constructors, fields, methods... void updateChildren(); // Abstract method. }
Factory constructors
Use the factory
keyword when implementing a constructor that doesn’t always create a new instance of its class.
class Logger { String name; Logger(this.name); factory Logger.fromJson(Map<String, Object> json) { return Logger(json['name'].toString()); } }
Named constructors
Use named constructors to implement multiple constructors for a class or to provide extra clarity:
class Points { final double x; final double y; //unnamed constructor Points(this.x, this.y); // Named constructor Points.origin(double x,double y) : x = x, y = y; // Named constructor Points.destination(double x,double y) : x = x, y = y; }
Mixins
Mixins are a way of reusing a class’s code in multiple class hierarchies.
To implement a mixin, create a class that declares no constructors. Unless you want your mixin to be usable as a regular class, use the mixin
keyword instead of class
.
To use a mixin, use the with
keyword followed by one or more mixin names.
To restrict the types that can use a mixin use the on
keyword to specify the required superclass.
class Musician {} //creating a mixin mixin Feedback { void boo() { print('boooing'); } void clap() { print('clapping'); } } //only classes that extend or implement the Musician class //can use the mixin Song mixin Song on Musician { void play() { print('-------playing------'); } void stop() { print('....stopping.....'); } } //To use a mixin, use the with keyword followed by one or more mixin names class PerformSong extends Musician with Feedback, Song { //Because PerformSong extends Musician, //PerformSong can mix in Song void awesomeSong() { play(); clap(); } void badSong() { play(); boo(); } } void main() { PerformSong().awesomeSong(); PerformSong().stop(); PerformSong().badSong(); }
Typedefs
A type alias — is a concise way to refer to a type. Commonly used to create a custom type that is used a lot in the project.
typedef IntList = List<int>; List<int> i1=[1,2,3]; // normal way. IntList i2 = [1, 2, 3]; // Same thing but shorter and clearer. //type alias can have type parameters typedef ListMapper<X> = Map<X, List<X>>; Map<String, List<String>> m1 = {}; // normal way. ListMapper<String> m2 = {}; // Same thing but shorter and clearer.
Extension methods
Extension methods, introduced in Dart 2.7, are a way to add functionality to existing libraries and code.
//extension to convert a string to a number extension NumberParsing on String { int customParseInt() { return int.parse(this); } double customParseDouble() { return double.parse(this); } } void main() { //various ways to use the extension var d = '21'.customParseDouble(); print(d); var i = NumberParsing('20').customParseInt(); print(i); }
Optional positional parameters
You can make positional parameters optional by wrapping them in brackets. Optional positional parameters are always last in a function’s parameter list. Their default value is null unless you provide another default value.
String joinWithCommas(int a, [int? b, int? c, int? d, int e = 100]) { var total = '$a'; if (b != null) total = '$total,$b'; if (c != null) total = '$total,$c'; if (d != null) total = '$total,$d'; total = '$total,$e'; return total; } void main() { var result = joinWithCommas(1, 2); print(result); }
unawaited_futures
When you want to start a fire-and-forget Future
, the recommended way is to use unawaited
import 'dart:async'; Future doSomething() { return Future.delayed(Duration(seconds: 5)); } void main() async { //the function is fired and awaited till completion await doSomething(); // Explicitly-ignored //The function is fired and forgotten unawaited(doSomething()); }
If you come across another cool feature, please let me know so that I can top it up on this list.
That’s all for today.
Full Article: Dedan Ndungu @ Better Programming