Dart 1 - Dart Programming Tutorial

By Sheldon L Published at 2020-03-09 Updated at 2020-03-09


Basics

/// # Hello World
/*
void main() {
  print('hello');
}
*/


/// # [dart: core]
/*
import 'dart:core';           /// is imported automatically

void main() {
  var firstName = 11;         /// can asign any type
  String lastName = 'Ahsan';  /// only string

  print(firstName.toString() + ' ' + lastName);
}
*/


/// # [dart: io]
/*
import 'dart:io';

void main() {
  stdout.writeln('What is your name: ?');
  String name = stdin.readLineSync();

  print('Hello, $name');
}
*/

/// Data Type: [int], [double], [String], [dynamic]

/// Everything is object
///
/*
void main() {
  int number;               /// if not asigned, defult is [null] type
  var number2 = 22;
  print('$number, $number2 \n');
  number = 1;
  print('$number, $number2 \n');

  double dNumber = 11.11;
  var dNumber2 = 22.22;
  print('$dNumber, $dNumber2 \n');

  String name = 'Jame';
  var name2 = 'Tom';
  print('$name, $name2 \n');

  bool isTrue = true;
  var isTrue2 = false;
  print('$isTrue, $isTrue2 \n');

  dynamic weakVar;
  print('$weakVar \n');
  weakVar = 102;
  print('$weakVar \n');
  weakVar = 'Muhmad';
  print('$weakVar \n');
}
*/

/// Difference between [var] & [dynamic]
/*
void main() {
  /// [dynamic]
  dynamic x = 'hal';
  x = 123;
  print(x);
  /// [var]
  var a = 'hal';
  /* a = 123;          /// throw `exception`, because var type can not be changed when has asigned. */
  print(a);
}
*/


/// [String]
/*
void main() {
  String s1 = "Sentences. pair of single quotes or double quotes.\n";
  String s2 = "Sentences. \n'\\n' makes a newline.\n'\\' to not skip `\\`,`\'` and so on...\n";
  String s3 =
'''
Paragraphs, trible quotes;
P1;
P2;
''';
  print(s1);
  print(s2);
  print(s3);

  /// [String] -> [double]/[int]
  var one = int.parse('1');
  assert(one == 1);        /// verify

  var onePointOone = double.parse('1.1');
  assert(onePointOone == 1.1);

  /// [double]/[int] -> [String]
  var oneStr = 1.toString();
  assert(oneStr == '1');

  var piStr = 3.1415926.toStringAsFixed(2);
  assert(piStr == '3.14', 'true');
}
*/


/// [const], can not be reasigned
/*
void main() {
  const constNum = 0;
  const constBool = true;
  const constStr = 'a const string';

  print(constBool);
  print(constNum);
  print(constStr);

  print(constBool.runtimeType);
  print(constNum.runtimeType);
  print(constStr.runtimeType);
}
*/


/// Operators
/*
void main() {
  int num = 2 + 3;
  print(num);
  num = num - 2;
  print(num);
  num = num * 3;
  print(num);
  num = num % 2;
  print(num);

  /// relation: ==, !=, >=, <=
  if (num == 0){
    print('Even number');
  }

  /// unary operators
  num *= 2;
  print(num);
  num += 1;
  print(num);
  num -= 1;
  print(num);
  ++num;          // same as num++
  print(num);
  --num;          // same as num--
  print(num);

  /// logical: &&, ||
  if (num < 1 || num > 6) {
    print('not a dice');
  } else {
    if (num >= 1 && num <= 3){
      print('small');
    } else {
      print('big');
    }
  }
}
*/


/// Null aware operator: [?.], [??], [??=]
/*
class  Num {
  int num = 0;
}

void main() {
  var n;
  int number;
  /*
  if (n != null){       /// if not aware, the following will throw `exception`
    number = n.num;
  }
  */
  /// shortcut of the above:
  number = n?.num;       /// if n != null, return n.num, else, return `null`.
  print(number);
  number = n?.num ?? 0;  /// if n != null, return n.num, else, renturn `0`.
  print(number);

  int number2;
  print(number2 ??= -1);  /// if number22 is null, assigne it to -1
}
*/


/// Ternary operator
/*
void main() {
  int x = 100;
  var result = x % 2 == 0 ? 'Even' : 'Odd';
  print(result);
}
*/

/// Conditional Statement
/*
void main() {
  int number = 91;

  if (number % 2 == 0){
    print('Even');
  } else if (number % 3 == 0) {
    print('Trible');
  } else {
    print('Confused');
  }
}
*/
/*
void main() {
  int number = 91;
  var result = number % 3;

  switch(result) {
    case 0: print('Trible'); break;
    case 1: print('1 left'); break;
    case 2: print('2 left'); break;
  }
}
*/


/// Loop
/*
void main() {
  for (var i = 1; i <= 10; i++) {
    print(i);
  }

  var ls = [0,1,2,3];
  for (var i in ls) {
    print(i);
  }

  for (var i = 0; i < ls.length; i++) {
    print(i);
  }

  ls.forEach(
    (i) => print(i)
  );

  int i = 3;
  while (i >= 0) {
    print(i);
    i--;
  }

  i = 3;
  do{
    print(i);
    i--;
  } while (i > 0);
}
*/


/// [break] and [continue]
/*
void main() {
  for (var i = 0; i < 10; i++) {
    if (i > 4) break;
    print(i);
  }

  for (var i = 0; i <10; i++) {
    if (i % 2 == 0) continue;
    print("Odd: $i");
  }
}
*/


/// Collection - [List]
/*
void main() {

  List whateverList;
  print(whateverList.runtimeType);    /// [Null]

  // Opt 0.
  var names = List();
  print(names.runtimeType);           /// [List<dynamic>]
  names = <String> ['Jame', 'Jack'];  /// [List<String>]
  print(names.runtimeType);
  // Opt 1.
  /* var names = <String>['Jame', 'Jack'];            */
  // Opt 2.
  /* List <String> names = ['Jame', 'Jack'];  */
  // Opt 3.
  /* List names = <String> ['Jame', 'Jack'];  */
  /// The above same as [Set]

  print(names[0]);
  print(names.length);
  for (var name in names) { print(name); }

  // mutable
  List mixList = ['Max', 120, true];
  print(mixList);
  mixList[1] = 100;
  print(mixList);
  mixList[1] = 'Mary';
  print(mixList);

  // immutable
  List <String> members = const ['Jame', 'Jack'];
  /* members[1] = 'Mike';       /// will throw `exception` */

  // copy to a new List
  /* var members2 = members     /// will refer to the same List */
  var members2 = [...members];  /// no const, so immutable
  print('Members: $members');
  members2[1] = 'Mike';
  print('Members3: $members2');
}
*/


/// Collection - [Set]
/*
void main() {
  Set halogens = <String>{'fluorine', 'chlorine', 'fluorine', 'chlorine'};
  for (var halogen in halogens) {
    print(halogen);    /// won't repeat
  }

  var halogens2 = {};
  print(halogens2.runtimeType);   /// [_InternalLinkedHashMap<dynamic, dynamic>], can not tell between [Set] and [Map]

  var halogens3 = <String>{};
  print(halogens3.runtimeType);   /// [_CompactLinkedHashSet<String>]
}
*/


/// Collection - [Map]   // similar to dictionary in python
/*
void main() {
  Map gifts = {
    'Mary': 'dolls',
    'Bill': 'computers',
    'Jill': 'books',
  };
  print(gifts['Mary']);

  gifts['Mary'] = 'flowers';
  print(gifts);

  Map gifts2;
  print(gifts2.runtimeType);   /// [Null]

  var gifts3 = {};
  print(gifts3.runtimeType);   /// [_InternalLinkedHashMap<dynamic, dynamic>]

  var gifts4 = Map();
  print(gifts4.runtimeType);   /// [_InternalLinkedHashMap<dynamic, dynamic>]

}
*/


/// [function]
/*
void main() {
  showResult(square(4));
  showResult(add(5, 6));            /// positional prameters
  showResult(add2(5, number2: 6));  /// number2 is [named] parameter
  showResult(add2(5));              /// [named] parameter number2 has got a defult value
  showResult(add4(5, 6));           /// [optional]
  showResult(add4(5));

  print(square.runtimeType);         /// [(dynamic) => dynamic], the type of input and output

  var ls = ['apples', 'bananas', 'oranges'];
  ls.forEach((i) { print(i); });     /// Anonymous function, call back immediately
  ls.forEach( (i) => print(i) );     /// Anonymous arrow function
}

dynamic square(var number) {         /// Basic format of function
  return number * number;
}

/// parameters defultly is [positional parameter]
dynamic add( var number1, var number2 ) => number1 + number2;   /// One line arrow function

/// [{}] means [named parameter], can be assigned with default value.
/// Opt 0.
dynamic add2( var number1, {var number2} ) => number1 + (number2 ?? 0);
/// Opt 1.
dynamic add3( var number1, {var number2 = 0} ) => number1 + number2;

/// Can not give an unnamed parameter a defult value.
/* dynamic add3( var number1 = 0, {var number2 = 0} ) => number1 + number2; */

/// [[]] means [optional prameter]
/// Opt 0.
dynamic add4( var number1, [var number2]) => number1 + (number2 ?? 0);
/// Opt 1.
dynamic add5( var number1, [var number2 = 0]) => number1 + number2;

/// Can not use [named] and [optional] together.
/// Can not use [named] and [optional] before [positional]


void showResult(var msg) {
  print('Result is $msg');
}
*/


/// [class]
/// Class 1 - constructor
/*
class Person {
  // Init
  String name;
  int age;

  // Default constructor
  // Opt 0.
  /*
  Person(String name, [int age = 18]) {     /// better to declare type, or won't check out the type error when compile, but runtime error will occur.
    this.name = name;
    this.age = age;
  }
  */
  // Opt 1.
  Person(this.name, [this.age = (18)]);   /// already init, no need to declare type

  // Named constructor
  Person.gest() {
    name = 'Gest';
  }

  void showNameAndAge(){
    print('$name, $age');
  }
}

void main() {
  Person person1 = Person('Mike');
  person1.age = 39;
  person1.showNameAndAge();

  Person person2 = Person('Jack', 25);
  person2.showNameAndAge();

  Person person3 = Person('Anna');
  person3.showNameAndAge();

  Person person4 = Person.gest();
  person4.showNameAndAge();
}
*/

/// Class 2 - final & static const
/*
class Person2 {
  final String name;            /// [final] type will be defined here or in the constructor
  static const int age = 10;    /// [const] type must be defined here and can not be changed
  /// [const] type in class need kw [static]

  Person2(this.name);           /// if [final] type is defined in constructor, can be assigned when be constructed.
}

void main() {
  var personA = Person2('Jack');  /// [const] can not be reassigned, so no [age] need; if final type [name] is defined when init, no [name] need either.
  print(personA.name);

  var personB = Person2('Mike');
  print(personB.name);

  /* print(person.age);          /// static field can not be accessed */
  /// Should call like this:
  print(Person2.age);
}
*/

// Class 3 - extends
/*
class Vehicle {
  String model;

  Vehicle(this.model) {
    print(this.model);
  }

  void showOutput() {
    print(model);
  }
}

class Car extends Vehicle {
  int year;
  double price;
  

  Car(String model, this.year, this.price) : super(model);

  void showOutput(){
    super.showOutput();        /// model will be print twice
    print(this.year);
    print(this.price);
  }
}

void main() {
  var carA = Car('Accord', 2014, 15000);
  carA.showOutput();
}
*/

// class 4 - override
/*
class X {
  String name;

  X(this.name);

  void showOutput() {
    print(this.name);
  }

  dynamic square(dynamic val) {
    return val * val;
  }
}

class Y extends X {
  Y(String name) : super(name);

  @override              /// use override notation is a good practic, it will reminde you when super method is not exist.
  /// though there is no issue if not use the notation.
  void showOutput() {
    print(this.name);    /// override, same as parent
    print('Hello');
  }
}
*/

// Class 5 - getters & setters
/*
class Rectangle {
  num left, top, width, height;   /// [num]: [int] or [double]

  Rectangle(this.left, this.top, this.width, this.height);

  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;

  void showOutput() {
    print('($left, $top), ($right, $top)');
    print('($left, $bottom), ($right, $bottom)');
  }
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  rect.showOutput();

  print(rect.left);
  rect.right = 12;
  print(rect.left);
  rect.showOutput();

  print(rect.top);
  rect.bottom = 10;
  print(rect.top);
  rect.showOutput();
}
*/


/// Exception handling

int mustGreaterThanZero(int val) {
  if (val <= 0) {
    throw Exception('Value must be greater than zero');
  }
  return val;
}

void verifyValue(var val) {
  var valueVerification;

  try {
    valueVerification = mustGreaterThanZero(val);   /// more exception pattern: try...on..., not mentioned here
  }
  catch(e) {
    print(e);
  }
  finally {
    if (valueVerification == null) {
      print('Value is not accepted');
    } else {
      print('Value verified: $valueVerification');
    }
  }
}

void main() {
  verifyValue(10);
  verifyValue(-1);
}