Table of Contents
Introduction to Dart
Dart is an object-oriented programming language known for its versatility, asynchronous support, and association with Flutter for cross-platform app development.
- Origin and Purpose:
- Dart is an object-oriented programming language developed by Google, first introduced in 2011.
- It’s designed to be versatile and applicable for various types of software development.
- General-purpose:
- Dart serves as a general-purpose language, used for web, mobile, and server applications.
- This versatility makes it suitable for creating a wide range of software solutions.
- Client-side and Server-side:
- One of Dart’s standout features is its support for both client-side and server-side programming.
- This allows developers to use the same language for both front-end and back-end development.
- Asynchronous Programming:
- Dart supports asynchronous programming through the use of “async” and “await” keywords.
- This is crucial for building responsive and real-time applications, like web and mobile apps.
- Rich Libraries:
- Dart comes with a rich set of libraries catering to different development areas, such as web, mobile, and server.
- These libraries provide tools and functionalities that accelerate application development.
- Flutter Framework:
- Dart is most notably associated with Flutter, Google’s UI framework for creating natively compiled applications.
- Flutter uses Dart as its primary programming language, allowing developers to build cross-platform apps.
- Cross-platform Development:
- Dart’s usage in Flutter makes it a popular choice for building apps that work on mobile, web, and desktop platforms.
- This approach simplifies maintaining a single codebase for multiple platforms.
- Strong Tooling:
- Dart offers strong tooling and development environments, enhancing productivity for programmers.
- Tools like the Dart SDK and Dart DevTools aid in debugging, profiling, and code analysis.
- Open-source:
- Dart is open-source, allowing the community to contribute, improve, and expand its features.
- Growing Ecosystem:
- Over time, the Dart ecosystem has grown, with a supportive community, third-party libraries, and resources for learning.
- Modern Language Features:
- Dart incorporates modern language features like strong typing, generics, and classes.
- It aims to make code cleaner, more readable, and less error-prone.
In essence, Dart is a versatile programming language that supports client-side and server-side development, asynchronous programming, and has gained prominence through its association with the Flutter framework for cross-platform application development.
Installation
- Install Dart SDK from here
- Install any Editor like IntelliJ IDEA or VsCode
Basics
First Dart Program
void main() { print('Hello, World!'); }
Data Types
In Dart language, the below data types are used:
Description | Keyword | Description |
Numbers | int, double, num | Used to to store numerical value |
Strings | String | Used to to store text value |
Booleans | bool | Used to store Boolean true and false value |
Lists | List | Used to store an ordered group of items |
Maps | Map | Used to store a set of values as key-value pair |
Sets | Set | Used to store unordered list of unique values of same types |
Runes | runes | Used to store Unicode values of String |
Null | null | It represents null value |
Operators
Operators in programming are symbols or keywords that represent a specific operation or computation to be performed on one or more operands (values, variables, or expressions). There are various types of operators in programming, such as:
- Arithmetic Operators
- Increment and Decrement Operators
- Assignment Operators
- Relational Operators
- Logical Operators
- Type Test Operators
Arithmetic Operators
Symbol | Operator Name | Description |
---|---|---|
+ | Addition | For adding two operands |
- | Subtraction | For subtracting two operands |
-expr | Unary Minus | For reversing the sign of the expression |
* | Multiplication | For multiplying two operands |
/ | Division | For dividing two operands and give output in double |
~/ | Integer Division | For dividing two operands and give output in integer |
% | Modulus | Remainder After Integer Division |
Increment and Decrement Operators
Operator Symbol | Operator Name | Description |
---|---|---|
++var | Pre Increment | Increase Value By 1. var = var + 1 Expression value is var+1 |
--var | Pre Decrement | Decrease Value By 1. var = var – 1 Expression value is var-1 |
var++ | Post Increment | Increase Value By 1. var = var + 1 Expression value is var |
var-- | Post Decrement | Decrease Value By 1. var = var – 1 Expression value is var |
Assignment Operators
Operator Type | Description |
---|---|
= | Assign a value to a variable |
+= | Adds a value to a variable |
-= | Reduces a value to a variable |
*= | Multiply value to a variable |
/= | Divided value by a variable |
Relational Operators
Operator Symbol | Operator Name | Description |
---|---|---|
> | Greater than | Used to check which operand is bigger and gives result as boolean |
< | Less than | Used to check which operand is smaller and gives result as boolean |
>= | Greater than or equal to | Used to check which operand is bigger or equal and gives result as boolean |
<= | Less than or equal to | Used to check which operand is smaller or equal and gives result as boolean |
== | Equal to | Used to check operands are equal to each other and gives result as boolean |
!= | Not equal to | Used to check operand are not equal to each other and gives result as boolean |
Logical Operators
Operator Type | Description |
---|---|
&& | This is ‘and’, return true if all conditions are true |
|| | This is ‘or’. Return true if one of the conditions is true |
! | This is ’not’. return false if the result is true and vice versa |
Type Test Operators
Operator Symbol | Operator Name | Description |
---|---|---|
is | is | Gives boolean value true if the object has a specific type |
is! | is not | Gives boolean value false if the object has a specific type |
Conditions and Loops
User Input
In Dart, to take input from stdin object has to use and will have to import dart:io library. A sample example is given for taking input from user.
import 'dart:io'; void main() { stdout.write("Enter your name: "); // Display a prompt String name = stdin.readLineSync(); // Read user input stdout.write("Enter your age: "); int age = int.parse( stdin.readLineSync()!); // Read and parse user input as an integer print("Hello, $name! You are $age years old."); }
By default user input is string type. If you want to read other data types (like integers or double numbers), you’ll need to parse the input accordingly.
Functions
Dart functions are blocks of code that perform specific tasks or operations, allowing you to organize and reuse code in a structured manner. They can take input values (parameters), process them, and produce output values (return).
int addNumbers(int a, int b) { return a + b; } void main() { int num1 = 5; int num2 = 7; int sum = addNumbers(num1, num2); // Calling the function print("Total: $sum"); }
If want to pass optional parameter just enclose the optional variables in square brackets []
.
int addNumbers(int a, int b, [int? unit]) { if (unit != null) return (a + b) * unit; else return (a + b); } void main() { int num1 = 5; int num2 = 7; int unit = 50; int sum1 = addNumbers(num1, num2); // Calling the function int sum2 = addNumbers( num1, num2, unit); // Calling the function with optional parameter print("Total cost for single unit: $sum1"); print("Total cost for multiple unit: $sum2"); }
Null Safety
Null safety is a feature in Dart that helps developers avoid null pointer exceptions by providing stronger type checks at compile time. It was introduced in Dart 2.12, and it allows developers to write safer and more reliable code.
Null safety introduces two new types of variables: nullable and non-nullable. A nullable variable can be assigned a value or null, while a non-nullable variable can only be assigned a value.
In Dart’s null safety feature, there are two new symbols that are introduced to represent nullable and non-nullable variables. These symbols are:
?
– The?
symbol indicates that a variable is nullable. This symbol is placed after the type of the variable. For example,String?
indicates that the variable can hold aString
value ornull
.!
– The!
symbol indicates that a variable is non-nullable. This symbol is placed after the type of the variable. For example,String!
indicates that the variable can only hold a non-nullString
value.
The below example will clear you about Null Safety.
// Nullable variable String? nullableString = "Hello World"; nullableString = null; // Valid assignment // Non-nullable variable String nonNullableString = "Hello World"; nonNullableString = null; // Invalid assignment, will generate a compile-time error
In this example, nullableString
is a nullable variable that can be assigned a value or null
. The ?
symbol after the String
type indicates that the variable is nullable. In the first assignment, nullableString
is assigned the value "Hello World"
, which is valid. In the second assignment, nullableString
is assigned null
, which is also valid.
On the other hand, nonNullableString
is a non-nullable variable that can only be assigned a value. It does not have the ?
symbol after the String
type, indicating that the variable is non-nullable. In the first assignment, nonNullableString
is assigned the value "Hello World"
, which is valid. In the second assignment, nonNullableString
is assigned null
, which is not valid and will generate a compile-time error.
Late Keyword In Dart
late keyword is used to declare a variable which is non-nullable and will be initialized at a later time.
late int age; void main() { // assigning value to late variable age = 30; print(age); }
OOP
OOP in Dart
Dart is a modern programming language that supports OOP concepts. Some of the key features of OOP in Dart are:
- Classes: Classes are the fundamental building blocks of OOP in Dart. A class can have fields (data members) and methods (functions), and it can also extend other classes to inherit their properties and behavior.
- Inheritance: In Dart, a class can inherit properties and behavior from another class using the ‘extends’ keyword. This allows for code reuse and promotes a more modular design.
- Encapsulation: Encapsulation is the practice of hiding implementation details of an object and only exposing the necessary information to other objects. In Dart, you can use the ‘getters’ and ‘setters’ to control access to class fields.
- Polymorphism: Polymorphism is the concept of treating objects of different types as if they are of the same type. In Dart, you can achieve polymorphism through inheritance and interface implementation.
- Interfaces: An interface is a contract that defines a set of methods that a class must implement. In Dart, you can define an interface using the ‘implements’ keyword.
Overall, OOP in Dart provides a powerful set of tools for creating modular, maintainable, and extensible software systems. By leveraging these concepts, developers can build software that is more robust, scalable, and easy to understand and modify over time.
Class & Object in Dart
In Dart, a class is a blueprint or template for creating objects that have properties and behavior. To define a class in Dart, you use the class
keyword followed by the class name, as shown below:
class MyClass { // class members go here }
Inside the curly braces of the class definition, you can define properties and methods that are associated with the class. For example, you can define a class with a single property and method like this:
class Person { String name; void sayHello() { print('Hello, my name is $name'); } }
In this example, the Person
class has a single property called name
, which is a string, and a method called sayHello()
that prints a message to the console using the name
property.
To create an instance of a class, you use the new
keyword followed by the class name and any constructor arguments, if necessary, like this:
var person = new Person(); person.name = 'John'; person.sayHello(); // prints "Hello, my name is John"
In this example, we create a new Person
object and set its name
property to “John”. We then call the sayHello()
method, which prints a message to the console using the name
property.
Classes in Dart can also inherit from other classes using the extends
keyword. This allows you to create more specialized classes that share properties and behavior with their parent class. You can also define interfaces using the implements
keyword, which allows you to specify a set of methods that a class must implement.
Constructor in Dart
In Dart, a constructor is a special method that is used to create and initialize objects of a class. The constructor has the same name as the class and can optionally take in parameters that are used to initialize the object’s properties.
There are two types of constructors in Dart: named constructors and default constructors.
A default constructor is a constructor with no parameters. If you do not define a constructor for a class, Dart provides a default constructor that takes no arguments.
A named constructor is a constructor that has a name other than the class name. Named constructors are useful when you want to provide multiple ways to create objects of a class, or when you want to create objects using different initialization logic.
A sample Code with Class, Object and Constructor is given below:
class Person { String name; int age; // Default constructor Person(this.name, this.age); // Named constructor Person.fromBirthYear(String name, int birthYear) { this.name = name; this.age = DateTime.now().year - birthYear; } void sayHello() { print("Hello, my name is $name and I'm $age years old."); } } void main() { var person1 = new Person("John", 30); var person2 = new Person.fromBirthYear("Jane", 1990); person1.sayHello(); person2.sayHello(); }
In this example, we define a Person
class with two constructors. The first constructor is a default constructor that takes in two parameters, name
and age
, and uses them to initialize the object’s properties.
The second constructor is a named constructor called fromBirthYear
that takes in a name
parameter and a birthYear
parameter. This constructor uses the DateTime.now().year
property to calculate the person’s age based on their birth year and sets the name
and age
properties accordingly.
In the main()
function, we create two Person
objects, one using the default constructor and the other using the named constructor. We then call the sayHello()
method on each object to print a message to the console.
By using constructors in Dart, you can create objects with the appropriate initial state and behavior, which makes your code more flexible and easier to maintain.
Encapsulation In Dart
Encapsulation is one of the fundamental principles of object-oriented programming (OOP). It refers to the practice of hiding the implementation details of an object from the outside world and providing a public interface for accessing and manipulating the object’s state.
In Dart, encapsulation can be achieved by using private and public members. Private members are those that can only be accessed within the class that defines them, while public members can be accessed from outside the class.
To define a private member in Dart, you can prefix its name with an underscore (_
) character. For example, consider the following Person
class:
class Person { String _name; Person(String name) { _name = name; } void sayHello() { print("Hello, my name is $_name."); } }
In this example, we define a private property called _name
that can only be accessed within the Person
class. We also define a constructor that takes in a name
parameter and sets the _name
property. Finally, we define a sayHello()
method that uses the _name
property to print a message to the console.
By making the _name
property private, we prevent external code from directly accessing or modifying it. Instead, we provide a public method (sayHello()
) that can be used to access the property indirectly. This way, we can control how the property is accessed and ensure that the object’s state remains consistent.
In summary, encapsulation is an important concept in Dart that helps to improve code organization, readability, and maintainability. By hiding implementation details and providing a public interface, you can create more robust and flexible classes that can be used in a variety of contexts.
Inheritance In Dart
Inheritance is a fundamental concept in object-oriented programming (OOP) that allows you to create new classes based on existing classes. In Dart, you can create a subclass that inherits properties and methods from a superclass by using the extends
keyword.
Here is an example of how to create a class hierarchy using inheritance:
class Animal { String name; Animal(String name) { this.name = name; } void makeSound() { print("Unknown sound"); } } class Dog extends Animal { Dog(String name) : super(name); void makeSound() { print("Woof!"); } } void main() { var animal = new Animal("Unknown animal"); var dog = new Dog("Fido"); animal.makeSound(); dog.makeSound(); }
In this example, we define a Animal
class with a name
property and a makeSound()
method that prints “Unknown sound” to the console. We then define a Dog
subclass that extends the Animal
class and overrides the makeSound()
method to print “Woof!” to the console.
In the main()
function, we create an Animal
object and a Dog
object, and call the makeSound()
method on each object. When we call animal.makeSound()
, the Animal
class’s implementation of makeSound()
is executed and “Unknown sound” is printed to the console. When we call dog.makeSound()
, the Dog
class’s implementation of makeSound()
is executed and “Woof!” is printed to the console.
By using inheritance in Dart, you can create more specialized classes that share common functionality with other classes. This can help to improve code organization, reduce redundancy, and make your code easier to maintain.
Enum In Dart
In Dart, an enum
(short for “enumeration”) is a special data type that represents a fixed set of constant values.
enum Color { red, green, blue } void main() { var set_color = Color.red; switch (set_color) { case Color.red: print("You have set red color."); break; case Color.green: print("You have set green color."); break; case Color.blue: print("You have set blue color."); break; } }
Factory Constructor
In Dart, a factory constructor is a special type of constructor that is used to create objects differently from the usual constructor mechanism. Other generative constructors only create an instance of the class. But, the factory constructor can return an instance of the class or even subclass.
class MyClass { final int value; // Regular constructor MyClass(this.value); // Factory constructor factory MyClass.custom(int customValue) { return MyClass(customValue); } } void main() { final myObj1 = MyClass(20); // Using the regular constructor final myObj2 = MyClass.custom(400); // Using the factory constructor print("From regular constructor: ${myObj1.value}"); print("From regular constructor: ${myObj2.value}"); }
show Output
From regular constructor: 20
From regular constructor: 400
Some key points about factory constructor:
- factory keyword is used to define a factory constructor.
- Factory constructor must return an instance of the class or sub-class.
- You can’t use this keyword inside factory constructor.
- It can’t access instance members of the class.
- It returns an instance of the same class or sub-class.
Asynchronous Programming
Asynchronous programming: Asynchronous programming is like being able to start a task that might take a while, but instead of waiting around for it to finish, your program can go on doing other things and come back to check on the task later.
most of the modern programming languages support asynchronous programming like Dart, Python, Go, JavaScript, Java, Swift, Kotlin, Rust, C#, Ruby etc.
We will discuss about some keys which are used in asynchronous programming in dart which are:
- Futures: A Future represents a value that may be available at some point in the future, but the program will be continue with the rest statement.
- Async and Await: The async keyword is used to declare an asynchronous function, and the await keyword is used to pause the execution of a function until the awaited Future completes.
- Streams: Streams are a way to handle sequences of asynchronous events.
The below code is showing that the task will be completed without waiting for Task 3 since it will need 4 second.
void main() async { print("Task 1"); print("Task 2"); // This readData() function will sleep for 4 seconds but the rest statement will be continued. Future readData() async { return Future.delayed(Duration(seconds: 4), () => print('Task 3')); } readData(); print("Task 4"); print("Task 5"); }
Show Output
Task 1
Task 2
Task 4
Task 5
Task 3
The below code is showing that the task will be completed orderly and waiting for 4 second to complete Task 3 then rest tasks will be completed.
void main() async { // This function will sleep for 4 seconds. print("Task 1"); print("Task 2"); Future<String> readData() async { return Future.delayed(Duration(seconds: 4), () => 'Task 3'); } // This code will wait for the `readData()` function to complete before // printing the result. String data = await readData(); print(data); print("Task 4"); print("Task 5"); }
Show Output
Task 1
Task 2
Task 3
Task 4
Task 5
Error Handling
Error handling in Dart involves managing exceptions and errors that may occur during program execution. Dart provides mechanisms to handle errors and exceptions through its try-catch-finally syntax. Here’s how error handling works in Dart:
void main() { try { divide(10,0); } catch (e) { print("Caught an exception: $e"); } } double divide(int a, int b) { if (b == 0) { throw ArgumentError("Cannot divide by zero"); } return a / b; }