├── 09_while_loop.dart ├── 10_do_while_loop.dart ├── 06_conditional_expressions.dart ├── 12_continue_keyword.dart ├── 01_hello_world.dart ├── 11_break_keyword.dart ├── 04_constants.dart ├── 14_function_expression.dart ├── 08_for_loop.dart ├── 35_callable_classes.dart ├── 16_named_parameters.dart ├── 07_switch_and_case.dart ├── 02_data_types.dart ├── 13_functions.dart ├── 17_default_parameters.dart ├── 23_method_overriding.dart ├── 15_optional_positional_params.dart ├── 25_abstract_class_method.dart ├── 05_if_else_control_flow.dart ├── 03_string_and_string_interpolation.dart ├── 28_lambda_nameless_function.dart ├── 30_lexical_closures.dart ├── 19_class_and_objects.dart ├── 21_getters_setters.dart ├── 22_inheritance.dart ├── 26_interface.dart ├── 24_inheritance_with_constructors.dart ├── 29_higher_order_functions.dart ├── 27_static_method_variable.dart ├── LICENCE ├── 32_list_growable.dart ├── 31_list_fixed_length.dart ├── 34_set_and_hashset.dart ├── 33_maps_and_hashmap.dart ├── 20_constructors.dart ├── main.dart ├── 18_exception_handling.dart └── README.md /09_while_loop.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // WHILE Loop 5 | // WAP to find the even numbers between 1 to 10 6 | 7 | var i = 1; 8 | while (i <= 10) { 9 | 10 | if (i % 2 == 0) { 11 | print(i); 12 | } 13 | 14 | i++; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /10_do_while_loop.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // DO-WHILE Loop 5 | // WAP to find the even numbers between 1 to 10 6 | 7 | int i = 1; 8 | 9 | do { 10 | 11 | if ( i % 2 == 0) { 12 | print(i); 13 | } 14 | 15 | i++; 16 | } while ( i <= 10); 17 | } 18 | -------------------------------------------------------------------------------- /06_conditional_expressions.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | 5 | int a = 2; 6 | int b = 3; 7 | 8 | int smallNumber = a < b ? a : b; 9 | print("$smallNumber is smaller"); 10 | 11 | String name = null; 12 | 13 | String nameToPrint = name ?? "Guest User"; 14 | print(nameToPrint); 15 | } 16 | -------------------------------------------------------------------------------- /12_continue_keyword.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // CONTINUE keyword 5 | // Using Labels 6 | 7 | myLoop: for (int i = 1; i <= 3; i++) { 8 | 9 | myInnerLoop: for (int j = 1; j <= 3; j++) { 10 | 11 | if (i == 2 && j == 2) { 12 | continue myLoop; 13 | } 14 | print("$i $j"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /01_hello_world.dart: -------------------------------------------------------------------------------- 1 | void main() { 2 | 3 | // This is my first line of code 4 | print("Hello World"); // this is another comment .... 5 | 6 | print("This is my first application"); 7 | 8 | // Performing arithematic operation 9 | print(12 / 4); 10 | 11 | // Printing out boolean value 12 | print(false); 13 | // basic hello world 14 | } -------------------------------------------------------------------------------- /11_break_keyword.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // BREAK keyword 5 | // Using Labels 6 | // Nested FOR Loop 7 | 8 | myOuterLoop: for (int i = 1; i <= 3; i++) { 9 | 10 | innerLoop: for (int j = 1; j <= 3; j++) { 11 | print("$i $j"); 12 | 13 | if (i == 2 && j == 2) { 14 | break myOuterLoop; 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /04_constants.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // final 5 | final cityName = 'Mumbai'; 6 | // name = 'Peter'; // Throws an error 7 | 8 | final String countryName = 'India'; 9 | 10 | // const 11 | const PI = 3.14; 12 | const double gravity = 9.8; 13 | } 14 | 15 | class Circle { 16 | 17 | final color = 'Red'; 18 | static const PI = 3.14; 19 | } 20 | -------------------------------------------------------------------------------- /14_function_expression.dart: -------------------------------------------------------------------------------- 1 | // Expression in Function: 2 | 3 | void main() { 4 | 5 | findPerimeter(4, 2); 6 | 7 | int rectArea = getArea(10, 5); 8 | print("The area is $rectArea"); 9 | } 10 | 11 | void findPerimeter(int length, int breadth) => print("The perimeter is ${2 * (length + breadth)}"); 12 | 13 | int getArea(int length, int breadth) => length * breadth; 14 | 15 | 16 | -------------------------------------------------------------------------------- /08_for_loop.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // FOR Loop 5 | 6 | // WAP to find the even numbers between 1 to 10 7 | 8 | for (int i = 1; i <= 10; i++) { 9 | 10 | if ( i % 2 == 0) { 11 | print(i); 12 | } 13 | } 14 | 15 | 16 | // for ..in loop 17 | List planetList = ["Mercury", "Venus", "Earth", "Mars"]; 18 | 19 | for (String planet in planetList) { 20 | print(planet); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /35_callable_classes.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Callable class 4 | // --> Class treated as Function. 5 | // --> Implement call() method 6 | 7 | void main() { 8 | 9 | var personOne = Person(); 10 | var msg = personOne(25, "Peter"); 11 | print(msg); 12 | } 13 | 14 | class Person { 15 | 16 | String call(int age, String name) { 17 | return "The name of the person is $name and age is $age"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /16_named_parameters.dart: -------------------------------------------------------------------------------- 1 | 2 | // Optional Named Parameters 3 | 4 | void main() { 5 | findVolume(10, breadth: 5, height: 20); 6 | print(""); 7 | 8 | findVolume(10, height: 20, breadth: 5); // Sequence doesn't matter in Named Parameter 9 | } 10 | 11 | 12 | int findVolume(int length, {int breadth, int height}) { 13 | 14 | print("Length is $length"); 15 | print("Breadth is $breadth"); 16 | print("Height is $height"); 17 | 18 | print("Volume is ${length * breadth * height}"); 19 | } 20 | -------------------------------------------------------------------------------- /07_switch_and_case.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // Switch Case Statements: Applicable for only 'int' and 'String' 5 | 6 | String grade = 'A'; 7 | 8 | switch (grade) { 9 | 10 | case 'A': 11 | print("Excellent grade of A"); 12 | break; 13 | 14 | case 'B': 15 | print("Very Good !"); 16 | break; 17 | 18 | case 'C': 19 | print("Good enough. But work hard"); 20 | break; 21 | 22 | case 'F': 23 | print("You have failed"); 24 | break; 25 | default: 26 | print("Invalid Grade"); 27 | } 28 | } -------------------------------------------------------------------------------- /02_data_types.dart: -------------------------------------------------------------------------------- 1 | void main(List arguments) { 2 | 3 | // Numbers: int 4 | int score = 23; 5 | var count = 23; // It is inferred as integer automatically by compiler 6 | int hexValue = 0xEADEBAEE; 7 | 8 | // Numbers: double 9 | double percentage = 93.4; 10 | var percent = 82.533; 11 | double exponents = 1.42e5; 12 | 13 | // Strings 14 | String name = "Henry"; 15 | var company = "Google"; 16 | 17 | // Boolean 18 | bool isValid = true; 19 | var isAlive = false; 20 | 21 | print(score); 22 | print(exponents); 23 | 24 | // data types dart 25 | } 26 | -------------------------------------------------------------------------------- /13_functions.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | // OBJECTIVES 4 | // 1. Define a Function 5 | // 2. Pass parameters to a Function 6 | // 3. Return value from a Function 7 | // 4. Test that by default a Function returns null 8 | 9 | void main() { 10 | 11 | findPerimeter(4, 2); 12 | 13 | int rectArea = getArea(10, 5); 14 | print("The area is $rectArea"); 15 | } 16 | 17 | void findPerimeter(int length, int breadth) { 18 | 19 | int perimeter = 2 * (length + breadth); 20 | print("The perimeter is $perimeter"); 21 | } 22 | 23 | int getArea(int length, int breadth) { 24 | 25 | int area = length * breadth; 26 | return area; 27 | } 28 | -------------------------------------------------------------------------------- /17_default_parameters.dart: -------------------------------------------------------------------------------- 1 | // Default Parameters Program 2 | // 3 | 4 | void main() { 5 | 6 | findVolume(10); // Default value comes into action 7 | print(""); 8 | 9 | findVolume(10, breadth: 5, height: 30); // Overrides the old value with new one 10 | print(""); 11 | 12 | findVolume(10, height: 30, breadth: 5); // Making use of Named Parameters with Default values 13 | } 14 | 15 | 16 | int findVolume(int length, {int breadth = 2, int height = 20}) { 17 | 18 | print("Lenght is $length"); 19 | print("Breadth is $breadth"); 20 | print("Height is $height"); 21 | 22 | print("Volume is ${length * breadth * height}"); 23 | } 24 | -------------------------------------------------------------------------------- /23_method_overriding.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Exploring Method Overriding 4 | 5 | void main() { 6 | 7 | var dog = Dog(); 8 | dog.eat(); 9 | 10 | print(dog.color); 11 | } 12 | 13 | class Animal { 14 | 15 | String color = "brown"; 16 | 17 | void eat() { 18 | print("Animal is eating !"); 19 | } 20 | } 21 | 22 | class Dog extends Animal { 23 | 24 | String breed; 25 | 26 | String color = "Black"; // Property Overriding 27 | 28 | void bark() { 29 | print("Bark !"); 30 | } 31 | 32 | // Method Overriding 33 | void eat() { 34 | print("Dog is eating !"); 35 | super.eat(); 36 | print("More food to eat"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /15_optional_positional_params.dart: -------------------------------------------------------------------------------- 1 | 2 | // 1. Required Parameters 3 | // 2. Optional Positional Parameters 4 | 5 | void main() { 6 | 7 | printCities("New York", "New Delhi", "Sydney"); 8 | print(""); 9 | 10 | printCountries("USA"); // You can skip the Optional Positional Parameters 11 | 12 | } 13 | 14 | // Required Parameters 15 | void printCities(String name1, String name2, String name3) { 16 | 17 | print("Name 1 is $name1"); 18 | print("Name 2 is $name2"); 19 | print("Name 3 is $name3"); 20 | } 21 | 22 | // Optional Positional Parameters 23 | void printCountries(String name1, [String name2, String name3]) { 24 | 25 | print("Name 1 is $name1"); 26 | print("Name 2 is $name2"); 27 | print("Name 3 is $name3"); 28 | } 29 | -------------------------------------------------------------------------------- /25_abstract_class_method.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Abstract Method 4 | // 2. Abstract Class 5 | 6 | void main() { 7 | 8 | // var shape = Shape(); // Error. Cannot instantiate Abstract Class 9 | 10 | var rectangle = Rectangle(); 11 | rectangle.draw(); 12 | 13 | var circle = Circle(); 14 | circle.draw(); 15 | } 16 | 17 | abstract class Shape { 18 | 19 | // Define your Instance variable if needed 20 | int x; 21 | int y; 22 | 23 | void draw(); // Abstract Method 24 | 25 | void myNormalFunction() { 26 | // Some code 27 | } 28 | } 29 | 30 | 31 | class Rectangle extends Shape { 32 | 33 | void draw() { 34 | print("Drawing Rectangle....."); 35 | } 36 | } 37 | 38 | class Circle extends Shape { 39 | 40 | void draw() { 41 | print("Drawing Circle....."); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /05_if_else_control_flow.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // IF and ELSE Statements 5 | var salary = 15000; 6 | 7 | if (salary > 20000) { 8 | print("You got promotion. Congratulations !"); 9 | } else { 10 | print("You need to work hard !"); 11 | } 12 | 13 | // IF ELSE IF Ladder statements 14 | var marks = 70; 15 | 16 | if (marks >= 90 && marks < 100) { 17 | print("A+ grade"); 18 | } else if (marks >= 80 && marks < 90) { 19 | print("A grade"); 20 | } else if (marks >= 70 && marks < 80) { 21 | print("B grade"); 22 | } else if (marks >= 60 && marks < 70) { 23 | print("C grade"); 24 | } else if (marks > 30 && marks < 60) { 25 | print("D grade"); 26 | } else if (marks >= 0 && marks < 30) { 27 | print("You have failed"); 28 | } else { 29 | print("Invalid Marks. Please try again !"); 30 | } 31 | } 32 | // if else condition -------------------------------------------------------------------------------- /03_string_and_string_interpolation.dart: -------------------------------------------------------------------------------- 1 | 2 | void main() { 3 | 4 | // Literals 5 | var isCool = true; 6 | int x = 2; 7 | "John"; 8 | 4.5; 9 | 10 | // Various ways to define String Literals in Dart 11 | String s1 = 'Single'; 12 | String s2 = "Double"; 13 | String s3 = 'It\'s easy'; 14 | String s4 = "It's easy"; 15 | 16 | String s5 = 'This is going to be a very long String. ' 17 | 'This is just a sample String demo in Dart Programming Language'; 18 | 19 | 20 | // String Interpolation : Use ["My name is $name"] instead of ["My name is " + name] 21 | String name = "Kevin"; 22 | 23 | print("My name is $name"); 24 | print("The number of characters in String Kevin is ${name.length}"); 25 | 26 | 27 | int l = 20; 28 | int b = 10; 29 | 30 | print("The sum of $l and $b is ${l + b}"); 31 | print("The area of rectangle with length $l and breadth $b is ${l * b}"); 32 | } 33 | -------------------------------------------------------------------------------- /28_lambda_nameless_function.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Lambda Functions 4 | // NOTE: A function in Dart is object 5 | 6 | void main() { 7 | 8 | // Defining Lambda: 1st way 9 | Function addTwoNumbers = (int a, int b) { 10 | var sum = a + b; 11 | print(sum); 12 | }; 13 | 14 | var multiplyByFour = (int number) { 15 | return number * 4; 16 | }; 17 | 18 | // Defining Lambda: 2nd way: Function Expression: Using Short Hand Syntax or FAT Arrow ( '=>' ) 19 | Function addNumbers = (int a, int b) => print(a + b); 20 | 21 | var multiplyFour = (int number) => number * 4; 22 | 23 | 24 | // Calling lambda function 25 | addTwoNumbers(2, 5); 26 | print(multiplyByFour(5)); 27 | 28 | addNumbers(3, 7); 29 | print(multiplyFour(10)); 30 | } 31 | 32 | 33 | // A example of Normal function 34 | void addMyNumbers(int a, int b) { 35 | 36 | var sum = a + b; 37 | print(sum); 38 | } 39 | -------------------------------------------------------------------------------- /30_lexical_closures.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Objective 4 | // 1. Closures 5 | 6 | 7 | void main() { 8 | 9 | // Definition 1: 10 | // A closure is a function that has access to the parent scope, even after the scope has closed. 11 | 12 | String message = "Dar is good"; 13 | 14 | Function showMessage = () { 15 | message = "Dart is awesome"; 16 | print(message); 17 | }; 18 | 19 | showMessage(); 20 | 21 | 22 | // Definition 2: 23 | // A closure is a function object that has access to variables in its lexical scope, 24 | // even when the function is used outside of its original scope. 25 | 26 | Function talk = () { 27 | 28 | String msg = "Hi"; 29 | 30 | Function say = () { 31 | msg = "Hello"; 32 | print(msg); 33 | }; 34 | 35 | return say; 36 | }; 37 | 38 | Function speak = talk(); 39 | 40 | speak(); // talk() // say() // print(msg) // "Hello" 41 | } 42 | -------------------------------------------------------------------------------- /19_class_and_objects.dart: -------------------------------------------------------------------------------- 1 | void main() { 2 | 3 | var student1 = Student(); // One Object, student1 is reference variable 4 | student1.id = 23; 5 | student1.name = "Peter"; 6 | print("${student1.id} and ${student1.name}"); 7 | 8 | student1.study(); 9 | student1.sleep(); 10 | 11 | var student2 = Student(); // One Object, student2 is reference variable 12 | student2.id = 45; 13 | student2.name = "Sam"; 14 | print("${student2.id} and ${student2.name}"); 15 | student2.study(); 16 | student2.sleep(); 17 | } 18 | 19 | // Define states (properties) and behavior of a Student 20 | class Student { 21 | int id = -1; // Instance or Field Variable, default value is -1 22 | String name; // Instance or Field Variable, default value is null 23 | 24 | void study() { 25 | print("${this.name} is now studying"); 26 | } 27 | 28 | void sleep() { 29 | print("${this.name} is now sleeping"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /21_getters_setters.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Default Getter and Setter 4 | // 2. Custom Getter and Setter 5 | // 3. Private Instance Variable 6 | 7 | void main() { 8 | 9 | var student = Student(); 10 | student.name = "Peter"; // Calling default Setter to set value 11 | print(student.name); // Calling default Getter to get value 12 | 13 | student.percentage = 438.0; // Calling Custom Setter to set value 14 | print(student.percentage); // Calling Custom Getter to get value 15 | } 16 | 17 | class Student { 18 | 19 | String name; // Instance Variable with default Getter and Setter 20 | 21 | double _percent; // Private Instance Variable for its own library 22 | 23 | // Instance variable with Custom Setter 24 | void set percentage(double marksSecured) => _percent = (marksSecured / 500) * 100; 25 | // Instance variable with Custom Getter 26 | double get percentage => _percent; 27 | } 28 | -------------------------------------------------------------------------------- /22_inheritance.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Exploring Inheritance 4 | 5 | void main() { 6 | 7 | var dog = Dog(); 8 | dog.breed = "Labrador"; 9 | dog.color = "Black"; 10 | dog.bark(); 11 | dog.eat(); 12 | 13 | var cat = Cat(); 14 | cat.color = "White"; 15 | cat.age = 6; 16 | cat.eat(); 17 | cat.meow(); 18 | 19 | var animal = Animal(); 20 | animal.color = "brown"; 21 | animal.eat(); 22 | } 23 | 24 | class Animal { 25 | 26 | String color; 27 | 28 | void eat() { 29 | print("Eat !"); 30 | } 31 | } 32 | 33 | class Dog extends Animal { // Dog is Child class or sub class, Animal is super or parent class 34 | 35 | String breed; 36 | 37 | void bark() { 38 | print("Bark !"); 39 | } 40 | } 41 | 42 | class Cat extends Animal { // Cat is Child class or sub class, Animal is super or parent class 43 | 44 | int age; 45 | 46 | void meow() { 47 | print("Meow !"); 48 | } 49 | } 50 | 51 | 52 | // Inheritance -------------------------------------------------------------------------------- /26_interface.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Interface 4 | 5 | void main() { 6 | 7 | var tv = Television(); 8 | tv.volumeUp(); 9 | tv.volumeDown(); 10 | } 11 | 12 | class Remote { 13 | 14 | void volumeUp() { 15 | print("______Volume Up from Remote_______"); 16 | } 17 | 18 | void volumeDown() { 19 | print("______Volume Down from Remote_______"); 20 | } 21 | } 22 | 23 | class AnotherClass { 24 | 25 | void justAnotherMethod(){ 26 | // Code 27 | } 28 | 29 | } 30 | 31 | // Here Remote and AnotherClass acts as Interface 32 | class Television implements Remote, AnotherClass { 33 | 34 | void volumeUp() { 35 | // super.volumeUp(); // Not allowed to call super while implementing a class as Interface 36 | print("______Volume Up in Television_______"); 37 | } 38 | 39 | void volumeDown() { 40 | print("______Volume Down in Television_______"); 41 | } 42 | 43 | void justAnotherMethod() { 44 | print("Some code"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /24_inheritance_with_constructors.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Inheritance with Default Constructor and Parameterised Constructor 4 | // 2. Inheritance with Named Constructor 5 | 6 | void main() { 7 | 8 | var dog1 = Dog("Labrador", "Black"); 9 | 10 | print(""); 11 | 12 | var dog2 = Dog("Pug", "Brown"); 13 | 14 | print(""); 15 | 16 | var dog3 = Dog.myNamedConstructor("German Shepherd", "Black-Brown"); 17 | } 18 | 19 | class Animal { 20 | 21 | String color; 22 | 23 | Animal(String color) { 24 | this.color = color; 25 | print("Animal class constructor"); 26 | } 27 | 28 | Animal.myAnimalNamedConstrctor(String color) { 29 | print("Animal class named constructor"); 30 | } 31 | } 32 | 33 | class Dog extends Animal { 34 | 35 | String breed; 36 | 37 | Dog(String breed, String color) : super(color) { 38 | this.breed = breed; 39 | print("Dog class constructor"); 40 | } 41 | 42 | Dog.myNamedConstructor(String breed, String color) : super.myAnimalNamedConstrctor(color) { 43 | this.breed = breed; 44 | print("Dog class Named Constructor"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /29_higher_order_functions.dart: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Objectives 4 | // 1. Higher-Order Function: 5 | // How to pass function as parameter? 6 | // How to return a function from another function? 7 | 8 | 9 | void main() { 10 | 11 | // Example One: Passing Function to Higher-Order Function 12 | Function addNumbers = (a, b) => print(a + b); 13 | someOtherFunction("Hello", addNumbers); 14 | 15 | 16 | // Example Two: Receiving Function from Higher-Order Function 17 | var myFunc = taskToPerform(); 18 | print(myFunc(10)); // multiplyFour(10) // number * 4 // 10 * 4 // OUTPUT: 40 19 | } 20 | 21 | 22 | 23 | // Example one: Accepts function as parameter 24 | void someOtherFunction(String message, Function myFunction) { // Higher-Order Function 25 | 26 | print(message); 27 | myFunction(2, 4); // addNumbers(2, 4) // print(a + b); // print(2 + 4) // OUTPUT: 6 28 | } 29 | 30 | 31 | // Example two: Returns a function 32 | Function taskToPerform() { // Higher-Order Function 33 | 34 | Function multiplyFour = (int number) => number * 4; 35 | return multiplyFour; 36 | } 37 | -------------------------------------------------------------------------------- /27_static_method_variable.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Static Methods and Variables 4 | 5 | void main() { 6 | 7 | var circle1 = Circle(); 8 | // circle1.pi; // 4 bytes 9 | 10 | var circle2 = Circle(); 11 | // circle2.pi; // 4 bytes 12 | 13 | // 8 bytes // waste of extra 4 bytes 14 | 15 | Circle.pi; // 4 bytes 16 | Circle.pi; // No more memory will be allocated . 17 | 18 | 19 | // circle.calculateArea(); 20 | 21 | // print(Circle.pi); // Syntax to call Static Variable 22 | 23 | // Circle.calculateArea(); // Syntax to call Static Method 24 | } 25 | 26 | class Circle { 27 | 28 | static const double pi = 3.14; 29 | static int maxRadius = 5; 30 | 31 | String color; 32 | 33 | static void calculateArea() { 34 | print("Some code to calculate area of Circle"); 35 | // myNormalFunction(); // Not allowed to call instance functions 36 | // this.color; // You cannot use 'this' keyword and even cannot access Instance variables 37 | } 38 | 39 | void myNormalFunction() { 40 | calculateArea(); 41 | this.color = "Red"; 42 | print(pi); 43 | print(maxRadius); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Hazrat Ali 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /32_list_growable.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Growable list 4 | 5 | void main() { 6 | // Elements: N 21 12 7 | // Index: 0 1 2 8 | 9 | List countries = ["USA", "INDIA", "CHINA"]; // Growable List : METHOD 1 10 | countries.add("Nepal"); 11 | countries.add("Japan"); 12 | 13 | 14 | List numbersList = List(); // Growable List: METHOD 2 15 | numbersList.add(73); // Insert Operation 16 | numbersList.add(64); 17 | numbersList.add(21); 18 | numbersList.add(12); 19 | 20 | numbersList[0] = 99; // Update operation 21 | numbersList[1] = null; // Delete operation 22 | 23 | print(numbersList[0]); 24 | 25 | numbersList.remove(99); 26 | numbersList.add(24); 27 | numbersList.removeAt(3); 28 | // numbersList.clear(); 29 | 30 | print("\n"); 31 | 32 | for (int element in numbersList) { // Using Individual Element ( Objects ) 33 | print(element); 34 | } 35 | 36 | print("\n"); 37 | 38 | numbersList.forEach((element) => print(element)); // Using Lambda 39 | 40 | print("\n"); 41 | 42 | for (int i = 0; i < numbersList.length; i++) { // Using Index 43 | print(numbersList[i]); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /31_list_fixed_length.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Fixed-length list 4 | 5 | void main() { 6 | 7 | // Elements: N N N N N 8 | // Index: 0 1 2 3 4 9 | 10 | List numbersList = List(5); // Fixed-length list 11 | numbersList[0] = 73; // Insert operation 12 | numbersList[1] = 64; 13 | numbersList[3] = 21; 14 | numbersList[4] = 12; 15 | 16 | numbersList[0] = 99; // Update operation 17 | numbersList[1] = null;// Delete operation 18 | 19 | print(numbersList[0]); 20 | print("\n"); 21 | 22 | // numbersList.remove(73); // Not supported in fixed-length list 23 | // numbersList.add(24); // Not supported in fixed-length list 24 | // numbersList.removeAt(3); // Not supported in fixed-length list 25 | // numbersList.clear(); // Not supported in fixed-length list 26 | 27 | for (int element in numbersList) { // Using Individual Element (Objects) 28 | print(element); 29 | } 30 | 31 | print("\n"); 32 | 33 | numbersList.forEach((element) => print(element)); // Using Lambda 34 | 35 | print("\n"); 36 | 37 | for (int i = 0; i < numbersList.length; i++) { // Using Index 38 | print(numbersList[i]); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /34_set_and_hashset.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Sets: 4 | // --> Unordered Collection 5 | // --> All elements are unique 6 | 7 | void main() { 8 | 9 | Set countries = Set.from(["USA", "INDIA", "CHINA"]); // Method 1: From a list 10 | countries.add("Nepal"); 11 | countries.add("Japan"); 12 | 13 | 14 | Set numbersSet = Set(); // Method 2: Using Constructor 15 | numbersSet.add(73); // Insert Operation 16 | numbersSet.add(64); 17 | numbersSet.add(21); 18 | numbersSet.add(12); 19 | 20 | numbersSet.add(73); // Duplicate entries are ignored 21 | numbersSet.add(73); // Ignored 22 | 23 | numbersSet.contains(73); // returns true if the element is found in set 24 | numbersSet.remove(64); // returns true if the element was found and deleted 25 | numbersSet.isEmpty; // returns true if the Set is empty 26 | numbersSet.length; // returns number of elements in Set 27 | // numbersSet.clear(); // Deletes all elements 28 | 29 | print("\n"); 30 | 31 | for (int element in numbersSet) { // Using Individual Element ( Objects ) 32 | print(element); 33 | } 34 | 35 | print("\n"); 36 | 37 | numbersSet.forEach((element) => print(element)); // Using Lambda 38 | } 39 | -------------------------------------------------------------------------------- /33_maps_and_hashmap.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Maps 4 | // --> KEY has to be unique 5 | // --> VALUE can be duplicate 6 | 7 | void main() { 8 | 9 | Map countryDialingCode = { // Method 1: Using Literal 10 | "USA": 1, 11 | "INDIA": 91, 12 | "PAKISTAN": 92 13 | }; 14 | 15 | 16 | Map fruits = Map(); // Method 2: Using Constructor 17 | fruits["apple"] = "red"; 18 | fruits["banana"] = "yellow"; 19 | fruits["guava"] = "green"; 20 | 21 | fruits.containsKey("apple"); // returns true if the KEY is present in Map 22 | fruits.update("apple", (value) => "green"); // Update the VALUE for the given KEY 23 | fruits.remove("apple"); // removes KEY and it's VALUE and returns the VALUE 24 | fruits.isEmpty; // returns true if the Map is empty 25 | fruits.length; // returns number of elements in Map 26 | // fruits.clear(); // Deletes all elements 27 | 28 | print(fruits["apple"]); 29 | 30 | print("\n"); 31 | 32 | for (String key in fruits.keys) { // Print all keys 33 | print(key); 34 | } 35 | 36 | print("\n"); 37 | 38 | for (String value in fruits.values) { // Print all values 39 | print(value); 40 | } 41 | 42 | print("\n"); 43 | 44 | fruits.forEach((key, value) => print("key: $key and value: $value")); // Using Lambda 45 | 46 | } 47 | -------------------------------------------------------------------------------- /20_constructors.dart: -------------------------------------------------------------------------------- 1 | 2 | // Objectives 3 | // 1. Default Constructor 4 | // 2. Parameterized Constructor 5 | // 3. Named Constructor 6 | // 4. Constant Constructor 7 | 8 | void main() { 9 | 10 | var student1 = Student(23, "Peter"); // One Object, student1 is reference variable 11 | print("${student1.id} and ${student1.name}"); 12 | 13 | student1.study(); 14 | student1.sleep(); 15 | 16 | var student2 = Student(45, "Sam"); // One Object, student2 is reference variable 17 | print("${student2.id} and ${student2.name}"); 18 | 19 | student2.study(); 20 | student2.sleep(); 21 | 22 | 23 | var student3 = Student.myCustomConstructor(); // One object, student3 is a reference variable 24 | student3.id = 54; 25 | student3.name = "Rahul"; 26 | print("${student3.id} and ${student3.name}"); 27 | 28 | 29 | var student4 = Student.myAnotherNamedConstructor(87, "Paul"); 30 | print("${student4.id} and ${student4.name}"); 31 | } 32 | 33 | // Define states (properties) and behavior of a Student 34 | class Student { 35 | int id = -1; 36 | String name; 37 | 38 | Student(this.id, this.name); // Parameterised Constructor 39 | 40 | Student.myCustomConstructor() { // Named Constructor 41 | print("This is my custom constructor"); 42 | } 43 | 44 | Student.myAnotherNamedConstructor(this.id, this.name); // Named Constructor 45 | 46 | void study() { 47 | print("${this.name} is now studying"); 48 | } 49 | 50 | void sleep() { 51 | print("${this.name} is now sleeping"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /main.dart: -------------------------------------------------------------------------------- 1 | class Vehicle { 2 | String code = "8809"; 3 | String brand = "Tesla"; 4 | double averageVelocity = 25; 5 | 6 | void transport() { 7 | print("I am moving"); 8 | } 9 | } 10 | 11 | class Animal { 12 | 13 | } 14 | 15 | class Car extends Vehicle { 16 | double _areaOfBox; 17 | 18 | // Car({required this._areaOfBox}); 19 | 20 | Car.basic() : _areaOfBox = 0; 21 | 22 | void startCruise() { 23 | print("Cruise control is on"); 24 | } 25 | 26 | void reportAreaOfBox() { 27 | print("The area of the box of this car is ${this._areaOfBox}L"); 28 | } 29 | 30 | double get areaOfBox => _areaOfBox; 31 | 32 | set areaOfBox(double areaOfBox) { 33 | if(areaOfBox < 0) { 34 | _areaOfBox = 0; 35 | } else { 36 | _areaOfBox = areaOfBox; 37 | } 38 | } 39 | 40 | @override 41 | void transport() { 42 | print("I am a car"); 43 | } 44 | } 45 | 46 | void main() { 47 | Vehicle vehicle = Vehicle(); 48 | // vehicle.transport(); 49 | // print(vehicle.code); 50 | Car bmw = Car.basic(); 51 | bmw.areaOfBox = -100; 52 | print(bmw.areaOfBox); 53 | 54 | 55 | TwitterUser user1 = TwitterUser 56 | .byEmail("ali@gmail.com"); 57 | TwitterUser user2 = TwitterUser 58 | .byNumber("091123325"); 59 | 60 | bmw.transport(); 61 | } 62 | 63 | 64 | class TwitterUser { 65 | String email; 66 | String phoneNumber; 67 | 68 | TwitterUser.byEmail(this.email) 69 | : phoneNumber = "0"; 70 | 71 | TwitterUser.byNumber(this.phoneNumber) 72 | : email = "test@gmail.com"; 73 | } -------------------------------------------------------------------------------- /18_exception_handling.dart: -------------------------------------------------------------------------------- 1 | 2 | // OBJECTIVE: Exception Handling 3 | // 1. ON Clause 4 | // 2. Catch Clause with Exception Object 5 | // 3. Catch Clause with Exception Object and StackTrace Object 6 | // 4. Finally Clause 7 | // 5. Create our own Custom Exception 8 | 9 | void main() { 10 | 11 | print("CASE 1"); 12 | // CASE 1: When you know the exception to be thrown, use ON Clause 13 | try { 14 | int result = 12 ~/ 0; 15 | print("The result is $result"); 16 | } on IntegerDivisionByZeroException { 17 | print("Cannot divide by Zero"); 18 | } 19 | 20 | print(""); print("CASE 2"); 21 | // CASE 2: When you do not know the exception use CATCH Clause 22 | try { 23 | int result = 12 ~/ 0; 24 | print("The result is $result"); 25 | } catch (e) { 26 | print("The exception thrown is $e"); 27 | } 28 | 29 | print(""); print("CASE 3"); 30 | // CASE 3: Using STACK TRACE to know the events occurred before Exception was thrown 31 | try { 32 | int result = 12 ~/ 0; 33 | print("The result is $result"); 34 | } catch (e, s) { 35 | print("The exception thrown is $e"); 36 | print("STACK TRACE \n $s"); 37 | } 38 | 39 | print(""); print("CASE 4"); 40 | // CASE 4: Whether there is an Exception or not, FINALLY Clause is always Executed 41 | try { 42 | int result = 12 ~/ 3; 43 | print("The result is $result"); 44 | } catch (e) { 45 | print("The exception thrown is $e"); 46 | } finally { 47 | print("This is FINALLY Clause and is always executed."); 48 | } 49 | 50 | print(""); print("CASE 5"); 51 | // CASE 5: Custom Exception 52 | try { 53 | depositMoney(-200); 54 | } catch (e) { 55 | print(e.errorMessage()); 56 | } finally { 57 | // Code 58 | } 59 | } 60 | 61 | class DepositException implements Exception { 62 | String errorMessage() { 63 | return "You cannot enter amount less than 0"; 64 | } 65 | } 66 | 67 | void depositMoney(int amount) { 68 | if (amount < 0) { 69 | throw new DepositException(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ✈ Hazrat Ali 2 | 3 | # 🚁 Dart Programming For Learning ( Basic Level ) 4 | 5 | # 🚀 Object-Oriented Programming (OOP) in Dart 6 | 7 | Object-oriented programming (OOP) is a programming paradigm that structures code using objects, which are instances of classes. Dart fully supports OOP principles, and this section provides a comprehensive exploration of key OOP concepts in Dart. 8 | 9 | ## Classes and Objects 10 | 11 | In Dart, a class is a blueprint for creating objects. Objects are instances of classes and encapsulate data and behavior. Let's expand on the basic example: 12 | 13 | ```dart 14 | class Animal { 15 | String name; 16 | int age; 17 | 18 | Animal(this.name, this.age); 19 | 20 | void makeSound() { 21 | print('Animal makes a sound'); 22 | } 23 | } 24 | 25 | class Dog extends Animal { 26 | String breed; 27 | 28 | Dog(String name, int age, this.breed) : super(name, age); 29 | 30 | @override 31 | void makeSound() { 32 | print('Dog barks'); 33 | } 34 | 35 | void showDetails() { 36 | print('Name: $name, Age: $age, Breed: $breed'); 37 | } 38 | } 39 | 40 | void main() { 41 | // Creating an instance of the Dog class 42 | var myDog = Dog('Buddy', 3, 'Golden Retriever'); 43 | 44 | // Accessing properties 45 | print('Name: ${myDog.name}, Age: ${myDog.age}, Breed: ${myDog.breed}'); 46 | 47 | // Invoking methods 48 | myDog.makeSound(); 49 | myDog.showDetails(); 50 | } 51 | ``` 52 | 53 | In this example, we have an `Animal` class with properties `name` and `age` and a method `makeSound`. The `Dog` class extends `Animal` and introduces an additional property `breed` and a method `showDetails`. 54 | 55 | ## Constructors 56 | 57 | Constructors are special methods used for initializing objects. Dart supports both default and named constructors. Let's extend the previous example to include named constructors: 58 | 59 | ```dart 60 | class Animal { 61 | String name; 62 | int age; 63 | 64 | Animal(this.name, this.age); 65 | 66 | Animal.namedConstructor(this.name) : age = 0; 67 | 68 | void makeSound() { 69 | print('Animal makes a sound'); 70 | } 71 | } 72 | 73 | class Dog extends Animal { 74 | String breed; 75 | 76 | Dog(String name, int age, this.breed) : super(name, age); 77 | 78 | Dog.namedConstructor(String name, String breed) 79 | : breed = breed, 80 | super.namedConstructor(name); 81 | 82 | @override 83 | void makeSound() { 84 | print('Dog barks'); 85 | } 86 | 87 | void showDetails() { 88 | print('Name: $name, Age: $age, Breed: $breed'); 89 | } 90 | } 91 | 92 | void main() { 93 | var myDog = Dog('Buddy', 3, 'Golden Retriever'); 94 | 95 | var anotherDog = Dog.namedConstructor('Max', 'Labrador'); 96 | 97 | myDog.showDetails(); 98 | anotherDog.showDetails(); 99 | } 100 | ``` 101 | 102 | Here, we've added named constructors `namedConstructor` to both the `Animal` and `Dog` classes. This allows for alternative ways to construct objects. 103 | 104 | ## Inheritance 105 | 106 | Inheritance is a fundamental OOP concept that allows a class to inherit properties and methods from another class. The `extends` keyword in Dart is used to implement inheritance. Let's extend our example further: 107 | 108 | ```dart 109 | class Animal { 110 | String name; 111 | int age; 112 | 113 | Animal(this.name, this.age); 114 | 115 | Animal.namedConstructor(this.name) : age = 0; 116 | 117 | void makeSound() { 118 | print('Animal makes a sound'); 119 | } 120 | } 121 | 122 | class Dog extends Animal { 123 | String breed; 124 | 125 | Dog(String name, int age, this.breed) : super(name, age); 126 | 127 | Dog.namedConstructor(String name, String breed) 128 | : breed = breed, 129 | super.namedConstructor(name); 130 | 131 | @override 132 | void makeSound() { 133 | print('Dog barks'); 134 | } 135 | 136 | void showDetails() { 137 | print('Name: $name, Age: $age, Breed: $breed'); 138 | } 139 | } 140 | 141 | class Cat extends Animal { 142 | bool hasStripes; 143 | 144 | Cat(String name, int age, this.hasStripes) : super(name, age); 145 | 146 | void makeSound() { 147 | print('Cat meows'); 148 | } 149 | 150 | void showDetails() { 151 | print('Name: $name, Age: $age, Has Stripes: $hasStripes'); 152 | } 153 | } 154 | 155 | void main() { 156 | var myDog = Dog('Buddy', 3, 'Golden Retriever'); 157 | var myCat = Cat('Whiskers', 2, true); 158 | 159 | myDog.showDetails(); 160 | myCat.showDetails(); 161 | } 162 | ``` 163 | 164 | In this extension, we've introduced a new class `Cat` that also extends `Animal`. The `Cat` class has its own properties and methods, and it overrides the `makeSound` method inherited from `Animal`. 165 | 166 | ## Encapsulation 167 | 168 | Encapsulation is the concept of bundling data and methods that operate on that data within a single unit, i.e., a class. Dart supports encapsulation through the use of access modifiers (`public`, `private`, and `protected`). Dart uses an underscore `_` as a convention for marking private members. Let's modify our example to incorporate encapsulation: 169 | 170 | ```dart 171 | class Animal { 172 | String _name; // Private property 173 | 174 | 175 | int _age; // Private property 176 | 177 | Animal(this._name, this._age); 178 | 179 | Animal.namedConstructor(this._name) : _age = 0; 180 | 181 | void makeSound() { 182 | print('Animal makes a sound'); 183 | } 184 | 185 | // Getter for private property _name 186 | String get name => _name; 187 | 188 | // Setter for private property _name 189 | set name(String value) => _name = value; 190 | 191 | // Getter for private property _age 192 | int get age => _age; 193 | 194 | // Setter for private property _age 195 | set age(int value) => _age = value; 196 | } 197 | 198 | class Dog extends Animal { 199 | String _breed; // Private property 200 | 201 | Dog(String name, int age, this._breed) : super(name, age); 202 | 203 | Dog.namedConstructor(String name, String breed) 204 | : _breed = breed, 205 | super.namedConstructor(name); 206 | 207 | @override 208 | void makeSound() { 209 | print('Dog barks'); 210 | } 211 | 212 | void showDetails() { 213 | print('Name: $name, Age: $age, Breed: $_breed'); 214 | } 215 | } 216 | 217 | void main() { 218 | var myDog = Dog('Buddy', 3, 'Golden Retriever'); 219 | 220 | // Accessing private properties through getters 221 | print('Name: ${myDog.name}, Age: ${myDog.age}, Breed: ${myDog.showDetails()}'); 222 | } 223 | ``` 224 | 225 | In this example, properties `_name`, `_age`, and `_breed` are marked as private using the underscore `_`. Getters and setters are then used to provide controlled access to these private properties. 226 | 227 | ## Abstraction 228 | 229 | Abstraction involves hiding complex implementation details and showing only the necessary features of an object. Dart achieves abstraction through abstract classes and methods. Let's create an abstract class and extend it: 230 | 231 | ```dart 232 | abstract class Shape { 233 | // Abstract method 234 | void draw(); 235 | 236 | // Regular method 237 | void getInfo() { 238 | print('This is a shape.'); 239 | } 240 | } 241 | 242 | class Circle extends Shape { 243 | double radius; 244 | 245 | Circle(this.radius); 246 | 247 | @override 248 | void draw() { 249 | print('Drawing a circle with radius $radius'); 250 | } 251 | } 252 | 253 | class Square extends Shape { 254 | double side; 255 | 256 | Square(this.side); 257 | 258 | @override 259 | void draw() { 260 | print('Drawing a square with side $side'); 261 | } 262 | } 263 | 264 | void main() { 265 | var myCircle = Circle(5.0); 266 | var mySquare = Square(4.0); 267 | 268 | myCircle.draw(); 269 | myCircle.getInfo(); 270 | 271 | mySquare.draw(); 272 | mySquare.getInfo(); 273 | } 274 | ``` 275 | 276 | Here, `Shape` is an abstract class with an abstract method `draw()`. The `Circle` and `Square` classes extend `Shape` and provide their own implementations of the `draw()` method. 277 | 278 | ## Polymorphism 279 | 280 | Polymorphism allows objects of different types to be treated as objects of a common type. Dart supports polymorphism through method overriding. Let's demonstrate polymorphism using our existing classes: 281 | 282 | ```dart 283 | void main() { 284 | Shape myCircle = Circle(5.0); 285 | Shape mySquare = Square(4.0); 286 | 287 | drawShape(myCircle); 288 | drawShape(mySquare); 289 | } 290 | 291 | void drawShape(Shape shape) { 292 | shape.draw(); 293 | } 294 | ``` 295 | 296 | In this example, `myCircle` and `mySquare` are both treated as `Shape` objects when passed to the `drawShape` function. The `draw()` method of the appropriate class (either `Circle` or `Square`) is called based on the actual type of the object. 297 | 298 | 299 | ## Conclusion 300 | 301 | This comprehensive exploration covers the fundamental concepts of Object-Oriented Programming (OOP) in Dart. Understanding these concepts, including classes, inheritance, constructors, encapsulation, abstraction, and polymorphism, is crucial for writing efficient and maintainable Dart code. For more in-depth information and advanced use cases, refer to the official Dart documentation: [Dart Documentation](https://dart.dev/guides). 302 | 303 | # Extensions in Dart 304 | 305 | Dart introduced extensions as a feature that allows adding new functionality to existing classes without modifying their source code. This provides a way to extend the behavior of types you don't own or cannot modify. Let's explore the concept of extensions in Dart and how to implement them. 306 | 307 | ## Extension Declaration 308 | 309 | To declare an extension, you use the `extension` keyword followed by a name and the `on` keyword specifying the type you want to extend. Inside the extension, you can define new methods, getters, setters, and fields: 310 | 311 | ```dart 312 | extension StringExtension on String { 313 | int parseInt() { 314 | return int.parse(this); 315 | } 316 | 317 | String capitalize() { 318 | return this.isNotEmpty ? this[0].toUpperCase() + this.substring(1) : this; 319 | } 320 | } 321 | ``` 322 | 323 | In this example, we declare an extension named `StringExtension` that extends the `String` class. It provides two new methods: `parseInt` to parse a string into an integer and `capitalize` to capitalize the first letter of the string. 324 | 325 | ## Using Extensions 326 | 327 | Once an extension is declared, you can use its methods as if they were defined directly on the extended type. Here's how you use the `StringExtension` extension: 328 | 329 | ```dart 330 | void main() { 331 | String numberString = '42'; 332 | int number = numberString.parseInt(); 333 | 334 | print('Parsed number: $number'); 335 | 336 | String greeting = 'hello'; 337 | String capitalizedGreeting = greeting.capitalize(); 338 | 339 | print('Capitalized greeting: $capitalizedGreeting'); 340 | } 341 | ``` 342 | 343 | In this example, the `parseInt` method from the `StringExtension` extension is used to parse a string into an integer, and the `capitalize` method is used to capitalize the first letter of a string. 344 | 345 | 346 | ## Limitations 347 | 348 | - Extensions can only be declared on non-nullable types. 349 | - They cannot access private members of the extended type. 350 | - Extensions are not inherited, meaning if a subclass extends a class, it won't automatically inherit the extensions of the superclass. 351 | 352 | ## Advanced Usage 353 | 354 | Extensions can be used to add functionality to third-party or system libraries without modifying their source code. For example, you could create an extension to add extra methods to the `List` class: 355 | 356 | ```dart 357 | extension ListExtension on List { 358 | E safeGet(int index) { 359 | return (index >= 0 && index < this.length) ? this[index] : null; 360 | } 361 | 362 | void printAll() { 363 | this.forEach(print); 364 | } 365 | } 366 | ``` 367 | 368 | Now, you can use these methods on any list: 369 | 370 | ```dart 371 | void main() { 372 | List numbers = [1, 2, 3, 4, 5]; 373 | 374 | int element = numbers.safeGet(2); 375 | print('Element at index 2: $element'); 376 | 377 | numbers.printAll(); 378 | } 379 | ``` 380 | 381 | This is a powerful feature for enhancing existing types and promoting code reuse. 382 | 383 | ## Conclusion 384 | 385 | Extensions in Dart provide a clean and efficient way to add new functionality to existing types. They improve code readability and maintainability by allowing you to extend classes without modifying their source code. When used carefully, extensions can be a valuable tool for writing concise and expressive Dart code. For more in-depth information and advanced use cases, refer to the official Dart documentation on [extensions](https://dart.dev/guides/language/extension-methods). 386 | 387 | # Mixins 388 | 389 | Mixins in Dart are a way to reuse a class's code in multiple class hierarchies. They allow you to extend the functionality of a class without using traditional inheritance. Mixins are a powerful feature in Dart that promotes code reuse and separation of concerns. Here's a step-by-step guide to understanding and using mixins in Dart: 390 | 391 | 392 | ### 1. **Define a Mixin:** 393 | 394 | Create a mixin by using the `mixin` keyword followed by a name. A mixin can include methods, properties, and even other mixins. 395 | 396 | ```dart 397 | mixin LoggingMixin { 398 | void log(String message) { 399 | print('Log: $message'); 400 | } 401 | } 402 | ``` 403 | 404 | In this example, `LoggingMixin` defines a simple `log` method. 405 | 406 | ### 2. **Use Mixin in a Class:** 407 | 408 | To use a mixin in a class, use the `with` keyword followed by the mixin's name. 409 | 410 | ```dart 411 | class Calculator with LoggingMixin { 412 | int add(int a, int b) { 413 | log('Adding $a and $b'); 414 | return a + b; 415 | } 416 | } 417 | ``` 418 | 419 | Now, the `Calculator` class can use the `log` method from the `LoggingMixin`. 420 | 421 | 422 | ### 3. **Instantiate and Use the Class:** 423 | 424 | Create an instance of the class and use its methods as usual. 425 | 426 | ```dart 427 | void main() { 428 | var calculator = Calculator(); 429 | var result = calculator.add(3, 7); 430 | print('Result: $result'); 431 | } 432 | ``` 433 | 434 | The `Calculator` class now benefits from the `log` method provided by the `LoggingMixin`. 435 | 436 | ### 4. **Multiple Mixins:** 437 | 438 | You can use multiple mixins in a single class by separating them with commas. 439 | 440 | ```dart 441 | mixin MathOperations { 442 | int multiply(int a, int b) => a * b; 443 | } 444 | 445 | class AdvancedCalculator with LoggingMixin, MathOperations { 446 | //... 447 | } 448 | ``` 449 | 450 | Now, `AdvancedCalculator` has access to both the `log` method from `LoggingMixin` and the `multiply` method from `MathOperations`. 451 | 452 | 453 | ### 5. **Order of Mixins:** 454 | 455 | The order in which mixins are applied matters. The behavior of the class may vary based on the order of mixins. If two mixins provide the same method or property, the one declared first takes precedence. 456 | 457 | ### 6. **Understanding `on` Clause (Optional):** 458 | 459 | You can use the `on` clause to restrict the types that can use the mixin. This ensures that the mixin is applied only to specific types. 460 | 461 | ```dart 462 | mixin LoggingMixin on Calculator { 463 | 464 | } 465 | ``` 466 | 467 | In this example, `LoggingMixin` can only be used with classes that extend or implement `Calculator`. 468 | 469 | ### 7. **Considerations:** 470 | 471 | - Mixins promote code reuse and maintainability. 472 | - They allow you to avoid the diamond problem (ambiguity that arises when a class inherits from two classes that have a common ancestor). 473 | - Be mindful of the order of mixins and potential conflicts. 474 | 475 | ### Example Code: 476 | 477 | Here's a complete example incorporating all the concepts: 478 | 479 | ```dart 480 | mixin LoggingMixin { 481 | void log(String message) { 482 | print('Log: $message'); 483 | } 484 | } 485 | 486 | mixin MathOperations { 487 | int multiply(int a, int b) => a * b; 488 | } 489 | 490 | class Calculator with LoggingMixin, MathOperations { 491 | int add(int a, int b) { 492 | log('Adding $a and $b'); 493 | return a + b; 494 | } 495 | } 496 | 497 | void main() { 498 | var advancedCalculator = Calculator(); 499 | var result = advancedCalculator.add(3, 7); 500 | print('Result: $result'); 501 | 502 | var multiplicationResult = advancedCalculator.multiply(4, 5); 503 | print('Multiplication Result: $multiplicationResult'); 504 | } 505 | ``` 506 | 507 | This example demonstrates a `Calculator` class using both `LoggingMixin` and `MathOperations` mixins. 508 | 509 | By understanding and using mixins effectively, you can enhance the modularity and flexibility of your Dart code. 510 | 511 | # Enums 512 | 513 | Enums in Dart allow you to define a set of named constant values. They are often used to represent a fixed set of values or options. Here's an example of how you can use enums in Dart: 514 | 515 | ```dart 516 | // Define an enum named 'Status' 517 | enum Status { 518 | idle, 519 | running, 520 | paused, 521 | stopped, 522 | } 523 | 524 | void main() { 525 | // Using enum values 526 | Status currentStatus = Status.running; 527 | 528 | // Switch statement with enum 529 | switch (currentStatus) { 530 | case Status.idle: 531 | print("The system is idle."); 532 | break; 533 | case Status.running: 534 | print("The system is running."); 535 | break; 536 | case Status.paused: 537 | print("The system is paused."); 538 | break; 539 | case Status.stopped: 540 | print("The system is stopped."); 541 | break; 542 | default: 543 | print("Unknown status"); 544 | } 545 | } 546 | ``` 547 | 548 | In this example, we define an enum called `Status` with four possible values: `idle`, `running`, `paused`, and `stopped`. We then declare a variable `currentStatus` and assign it the value `Status.running`. Finally, we use a switch statement to check the current status and print a corresponding message. 549 | 550 | Enums in Dart are powerful because they provide a way to represent a fixed set of values in a clear and concise manner, making the code more readable and maintainable. 551 | 552 | 553 | 554 | --------------------------------------------------------------------------------