Mastering Flutter/Dart Keywords – An Interesting Guide for Developers

Not just Flutter/Dart, learning the essentials of any Programming Language is the mandatory section for every Developer. However, there seems to be boredom in learning this stuff and some people try very hard to get past this. But this blog post will make this stuff easy and with better readability to catch up with the fundamental aspects of Dart Language. So let’s begin: Mastering Flutter/Dart Keywords – An Interesting Guide for Developers.


We shall be learning some of the popular keywords in Dart Language with examples, snippets, and so on…

Note: In the post-fix, assume there is a word keyword since it would be weird to write it down for each word.

Table of Contents

– static

The static keyword is all about declaring variables, methods, and getters/setters that are associated with the class itself rather than with instances of the class.

When we declare a variable as static in a class, it means that it is shared among all instances of the class. Moreover, static variables are initialized only once, and their values persist across multiple instances of the class. Furthermore, they can be accessed without creating an object of the class.

Here’s the code snippet

class Blogs {
  static String blogTitle = 'Flutter Driectory is a good choice for Flutter
  stuff.';
}

main() {
  print(Blogs.blogTitle);
}

In addition, static methods also follow the same procedure, but one thing here needs to be addressed. i.e. static methods cannot access instance variables or methods that are not associated with any specific instance. Such as:

class Blogs {
  
  static String blogFunction() {
    return "Flutter Directory is the best source of knowlege for Flutter           
    Engineers.";
  }
}

main() {
  print(Blogs.blogFunction());
}

So, by combining all, static members can be useful for sharing data or providing utility methods that don’t depend on instance-specific states.

– factory

A factory keyword is used to declare a factory constructor, which is a special type of constructor that is used to return an instance of the class using custom logic instead of creating a new object. Apart from this, a factory constructor can be used to implement object caching, return a different subtype of class, or perform any other instantiation logic.

Here is a code snippet

class MarksScored {
  final int value;
  
  MarksScored._(this.value);
  
  factory MarksScored(int marks) {
    if(marks >= 90) {
      return MarksScored._(marks);
    }
    else {
      return MarksScored._(0);
    }
  }
}

void main() {
  
  MarksScored scored = MarksScored(97);
  print("Total marks ${scored.value}");
  
  MarksScored ZeroScored = MarksScored(0);
  print("Total marks ${ZeroScored.value}");
}

Additionally, to keep it simple, you need to remember two points:

The return statement is used in the same instance.

Factory doesn’t support this keyword.

– var

When using var, Dart infers (deduces) the type of variable based on the assigned value.

Here’s an example snippet

main() {
  
  var title = 'Flutter Directory';
  var isOnlyFlutter = true;
  var blogCount = 11;
  
  var audienceRetention = 99.78;
  
  print(title);
  print(isOnlyFlutter);
  print(blogCount);
  print(audienceRetention);
}

w.r.t the above snippet, the variable:

title = inferred as type string

isOnlyFlutter = inferred as type bool

blogCount = inferred as type int

audienceRetention = inferred as type double

Furthermore, these values are determined at compile-time and remain the same throughout the variable’s scope. Since Dart is a statically typed Programming Language (where variable types are known at compile time), even though the type is implicit, it is still verified at compile time to ensure type safety.

However, declaring var cannot be considered the best approach. It is always good practice to use explicit keywords to ensure better readability and code clarity. Moreover, it also avoids potential issues regarding type inferencing.

– dynamic

Declaring variables with dynamic types is unknown until runtime and variables can hold onto any type.

Here’s the code snippet

void main() {
  dynamic value = 'Hello'; // Variable with dynamic type
  print(value); // Output: Hello

  value = 10; // Assigning an integer value
  print(value); // Output: 10

  value = true; // Assigning a boolean value
  print(value); // Output: true
}

Note: Dart does not support static type checking on dynamic variables, and the type of variable is determined at runtime based on the assigned value.

Using dynamic has its advantages, such as you don’t get compile-time checking vis-à-vis early error detection, etc. Instead, type errors might occur at runtime, if compatible operations or assignments are performed on the dynamic variable.

However, dynamic keywords can be useful in certain scenarios:

  • Dealing with dynamic Data Structures
  • Interacting with API calls
  • An explicit need to work with different types

So, dynamic types should be avoided and instead should be replaced with statically typed types.

– implements

Implements indicate that a class is implementing one or more interfaces in Dart.

Interface – defined as a set of method signatures that a class must implement.

Here is the code snippet illustrating the usage of implements.

// Interface definition
abstract class Animal {
  void makeSound();
}

// Class implementing an interface
class Dog implements Animal {
  @override
  void makeSound() {
    print('Woof!');
  }
}

void main() {
  var dog = Dog();
  dog.makeSound(); // Output: Woof!
}

However, it’s important to understand that Dart does not have explicit interface types like other languages such as Java and so on… Instead, any class can act as an interface and other classes can use them via the implements’ keyword. This allows for flexible and ad-hoc implementation.

– with and mixins

I am wrapping with and mixins in the same section because one is dependent on another.

with is used to allow the use of one or more mixins that a class will use. Whereas, mixins are a way to reduce code in multiple classes without the need for traditional inheritance.

Here’s a code snippet illustrating the use of both.

// Mixin definition
mixin Swimming {
  void swim() {
    print('Swimming...');
  }
}

mixin Flying {
  void fly() {
    print('Flying...');
  }
}

// Class using mixins
class Duck with Swimming, Flying {
  void display() {
    print('I am a duck.');
  }
}

void main() {
  var duck = Duck();
  duck.display(); // Output: I am a duck.
  duck.swim(); // Output: Swimming...
  duck.fly(); // Output: Flying...
}

Note: It’s important to remember that the order of mixins specified under with keyword matters a lot.

If multiple mixins define the same method, then the method of rightmost mixins takes precedence. Additionally, mixins cannot have constructors, and a class can use multiple mixins by separating them with commas after the with keyword.

– const

The const keyword is used to declare compile-time constant values. In addition, this remains constant throughout the program execution.

The code snippet further illustrates:

const int audienceCount = 450;
const String comment = "This is marvelous though!";

and so on...

Apart from this, the const keyword can be used for any sort of collection of literals too, such as lists, maps, and sets.

const myList = [1, 2, 3];
const mySet = {1, 2, 3};
const myMap = {'a': 1, 'b': 2};

Furthermore, const keywords can also be used with final and static values to declare variables for that particular behavior.

static const int x = 5;
final const double pi = 3.14;

So, declaring a variable const means more code and memory optimizations and performance enhancements.

– final

The final keyword is used to assign values once at runtime. Once assigned, its value cannot be changed till program execution. Such that:

final int x = 5;
final String name = 'John';

Moreover, as per the above heading regarding the const keyword, the same approach can be used for the final too, but with this minor difference, we talked about in the first line.

A similar example snippet

final List<int> numbers = [1, 2, 3];
final Set<String> names = {'John', 'Jane'};
final Map<String, int> scores = {'John': 90, 'Jane': 85};

Just like const, the final keyword also help in code clarity and improve readability.

– mounted

Mounted is not potentially a Dart keyword, but instead, it is used in the context of Flutter.

It is used by Flutter’s state to determine the availability of the widget and acts as a flag.

Here is an illustration

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  void _loadData() async {
    setState(() {
      _isLoading = true;
    });

    // Simulate an asynchronous operation
    await Future.delayed(Duration(seconds: 2));

    if (mounted) {
      setState(() {
        _isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: _isLoading ? CircularProgressIndicator() : Text('Data Loaded'),
      ),
    );
  }
}

In the above snippet, the mounted entity is used to check if the widget is still mounted (available) so that the bool _isLoading is loaded or not.

Additionally, mounted helps to avoid potential errors, especially when working with asynchronous operations such as async and await, or when the state of the widget might change while the operation is in progress.

– typedef

A typedef keyword is used to create function type aliases. It allows defining custom names for a function type, making code easy and more expressive to read.

Here is an illustration snippet

typedef String MyFunction(int a, String b);

void main() {
  MyFunction myFunction = (int a, String b) {
    return '$a $b';
  };

  String result = myFunction(42, 'Hello');
  print(result); // Output: 42 Hello
}

Using typedef promotes code clarity, especially when dealing with complex function signatures or just giving them meaningful names. Secondly, it promotes type safety, code reuse ability, and so on.

– extension

The extension method is used to add functionality to existing classes or types without changing their original identity.

— Defining an extension

extension nameOfExtension on type {
  type get nameOfMethod => // what function you wanna perfom
}

Here is an illustration snippet

extension DateFormat on DateTime {
  String get formatter => this.year.toString();
}

void main() {
  print(DateTime.now().formatter); // output => 2023
}

Moreover, getting the complete height of a device via MediaQuery wrapped under extension.

extension MediaQueryEx on BuildContext {
  double allHeight get => toDouble();
}

-------------
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: context.allHeight,
      child: Column(
        children: [
          
        ],
      ),
    );
  }
}

Using extension methods, no doubt is the best invention by the Flutter team to optimize our existing code bases and maintain code readability.

– enum

In Dart, enums are special datatypes that represent a set of constant values. It provides a way to define a discrete set of named values, which can be used to make code more readable and maintainable.

Code snippet

enum Shapes {
  circle,
  rectangle,
  square,
  diagonal
}

void main() {
  Shapes shape = Shapes.diagonal;
  
  print(shape);
}

Apart from this, enums are also comparable.

enum Shapes {
  circle,
  rectangle,
  square,
  diagonal
}

void main() {
  Shapes shape = Shapes.diagonal;
  
  print(shape == Shapes.diagonal);
  print(shape == Shapes.square);
}

In conclusion, enums are a great way to make code readable and reduce code complexity.

– async, await

async and await comes under Asynchronous Programming. A detailed description can be found in the link below:

Furthermore, this link may be useful too.

– async*, yield

async* and yield comes under streams. In addition, I would recommend the same link which is provided above as it contains a detailed scenario of streams and their types.

Attaching this link will surely be helpful for you.


Thanks for your precious time!

Wrapping up

In this blog post: Mastering Flutter/Dart Keywords – An Interesting Guide for Developers, I tried my best, up to my limited knowledge, to make this fit for a beginner to a pro-level developer.

I would love to have your feedback on this topic, and if you think something has been missed out, you can jot it down in the comment box of this blog post.

Furthermore, connect with me on the:

GitHub Repositories, and YouTube Channel.

Read out previous blogs – Click here

Also, read An Interesting Guide to Exploring Flutter Drawer

Leave a Comment