From 754cdb5510cbb11b01989c9f0f93a35e1ccd0c4c Mon Sep 17 00:00:00 2001 From: JMARyA Date: Sat, 8 Jun 2024 21:44:45 +0200 Subject: [PATCH] add dart --- technology/dev/Development.md | 3 + technology/dev/programming/languages/Dart.md | 2973 ++++++++++++++++++ 2 files changed, 2976 insertions(+) create mode 100644 technology/dev/programming/languages/Dart.md diff --git a/technology/dev/Development.md b/technology/dev/Development.md index ce30c81..c65b130 100644 --- a/technology/dev/Development.md +++ b/technology/dev/Development.md @@ -8,6 +8,9 @@ rev: 2024-05-02 ## Languages - [Python](programming/languages/Python.md) - [Rust](programming/languages/Rust.md) +- [DuckyScript](programming/languages/DuckyScript.md) +- [Dart](programming/languages/Dart.md) +- [SQL](programming/languages/SQL.md) ## Frameworks - [TailwindCSS](TailwindCSS.md) diff --git a/technology/dev/programming/languages/Dart.md b/technology/dev/programming/languages/Dart.md new file mode 100644 index 0000000..45d9586 --- /dev/null +++ b/technology/dev/programming/languages/Dart.md @@ -0,0 +1,2973 @@ +--- +obj: concept +website: https://dart.dev +rev: 2024-05-28 +--- + +# Dart +Dart is a programming language for the web, mobile and server. It's main use is within [Flutter](../frameworks/Flutter.md). + +## Syntax +Simple Hello World: +```dart +void main() { + print('Hello, World!'); +} +``` + +### Variables +Here's an example of creating a variable and initializing it: +```dart +var name = 'Bob'; +``` + +Variables store references. The variable called `name` contains a reference to a `String` object with a value of "Bob". + +The type of the name variable is inferred to be `String`, but you can change that type by specifying it. If an object isn't restricted to a single type, specify the `Object` type (or `dynamic` if necessary). +```dart +Object name = 'Bob'; +``` + +Another option is to explicitly declare the type that would be inferred: +```dart +String name = 'Bob'; +``` + +#### Null +Dart variables are non nullable by default. If a variable should be null you have to explicitly specify it: +```dart +String? name // Nullable type. Can be `null` or string. + +String name // Non-nullable type. Cannot be `null` but can be string. +``` + +Every variable needs to be initialized before use when not nullable. If you want to lazy load a variable or get around null checks, you can use the `late` keyword: +```dart +late String description; + +void main() { + description = 'Feijoada!'; + print(description); +} +``` + +#### Final and const +If you never intend to change a variable, use `final` or `const`, either instead of `var` or in addition to a type. A `final` variable can be set only once; a `const` variable is a compile-time constant. (Const variables are implicitly final.) + +```dart +final name = 'Bob'; // Without a type annotation +final String nickname = 'Bobby'; +``` + +### Operators +When you use operators, you create expressions. Here are some examples of operator expressions: + +```dart +a++ +a + b +a = b +a == b +c ? a : b +a is T +``` + +#### Arithmetic operators +Dart supports the usual arithmetic operators, as shown in the following table. + +| Operator | Meaning | +| ----------- | ------------------------------------------------------------------------ | +| `+` | Add | +| `-` | Subtract | +| `-`_`expr`_ | Unary minus, also known as negation (reverse the sign of the expression) | +| `*` | Multiply | +| `/` | Divide | +| `~/` | Divide, returning an integer result | +| `%` | Get the remainder of an integer division (modulo) | + +Example: + +```dart +assert(2 + 3 == 5); +assert(2 - 3 == -1); +assert(2 * 3 == 6); +assert(5 / 2 == 2.5); // Result is a double +assert(5 ~/ 2 == 2); // Result is an int +assert(5 % 2 == 1); // Remainder + +assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1'); +``` + +Dart also supports both prefix and postfix increment and decrement operators. + +| Operator | Meaning | +| ----------- | --------------------------------------------------------------- | +| `++`_`var`_ | _`var`_  `=`  _`var`_ `+ 1` (expression value is _`var`_ `+ 1`) | +| _`var`_`++` | _`var`_  `=`  _`var`_ `+ 1` (expression value is _`var`_) | +| `--`_`var`_ | _`var`_  `=`  _`var`_ `- 1` (expression value is _`var`_ `- 1`) | +| _`var`_`--` | _`var`_  `=`  _`var`_ `- 1` (expression value is _`var`_) | + +Example: + +```dart +int a; +int b; + +a = 0; +b = ++a; // Increment a before b gets its value. +assert(a == b); // 1 == 1 + +a = 0; +b = a++; // Increment a after b gets its value. +assert(a != b); // 1 != 0 + +a = 0; +b = --a; // Decrement a before b gets its value. +assert(a == b); // -1 == -1 + +a = 0; +b = a--; // Decrement a after b gets its value. +assert(a != b); // -1 != 0 +``` + +#### Equality and relational operators +The following table lists the meanings of equality and relational operators. + +| Operator | Meaning | +| -------- | --------------------------- | +| `==` | Equal; see discussion below | +| `!=` | Not equal | +| `>` | Greater than | +| `<` | Less than | +| `>=` | Greater than or equal to | +| `<=` | Less than or equal to | + +To test whether two objects x and y represent the same thing, use the `==` operator. (In the rare case where you need to know whether two objects are the exact same object, use the identical() function instead.) Here's how the `==` operator works: + +1. If _x_ or _y_ is null, return true if both are null, and false if only one is null. + +2. Return the result of invoking the `==` method on _x_ with the argument _y_. (That's right, operators such as `==` are methods that are invoked on their first operand. For details, see [Operators](https://dart.dev/language/methods#operators).) + + +Here's an example of using each of the equality and relational operators: + +```dart +assert(2 == 2); +assert(2 != 3); +assert(3 > 2); +assert(2 < 3); +assert(3 >= 3); +assert(2 <= 3); +``` + +#### Type test operators +The `as`, `is`, and `is!` operators are handy for checking types at runtime. + +| Operator | Meaning | +| -------- | -------------------------------------------------- | +| `as` | Typecast (also used to specify library prefixes) | +| `is` | True if the object has the specified type | +| `is!` | True if the object doesn't have the specified type | + +The result of `obj is T` is true if `obj` implements the interface specified by `T`. For example, `obj is Object?` is always true. + +Use the `as` operator to cast an object to a particular type if and only if you are sure that the object is of that type. Example: + +```dart +(employee as Person).firstName = 'Bob'; +``` + +If you aren't sure that the object is of type `T`, then use `is T` to check the type before using the object. + +```dart +if (employee is Person) { + // Type check + employee.firstName = 'Bob'; +} +``` + +#### Assignment operators +As you've already seen, you can assign values using the `=` operator. To assign only if the assigned-to variable is null, use the `??=` operator. + +```dart +// Assign value to a +a = value; +// Assign value to b if b is null; otherwise, b stays the same +b ??= value; +``` + +Compound assignment operators such as `+=` combine an operation with an assignment. + +| | | | | | +| ---- | ----- | ----- | ------ | ----- | +| `=` | `*=` | `%=` | `>>>=` | `^=` | +| `+=` | `/=` | `<<=` | `&=` | `\|=` | +| `-=` | `~/=` | `>>=` | | | + +Here's how compound assignment operators work: + +| | | | +| ------------------------- | --------------- | ------------------ | +| **For an operator _op_:** | `a` _`op`_`= b` | `a = a` _`op`_ `b` | +| **Example:** | `a += b` | `a = a + b` | + +The following example uses assignment and compound assignment operators: + +```dart +var a = 2; // Assign using = +a *= 3; // Assign and multiply: a = a * 3 +assert(a == 6); +``` + +#### Logical operators +You can invert or combine boolean expressions using the logical operators. + +| Operator | Meaning | +| ----------- | ------------------------------------------------------------------------ | +| `!`_`expr`_ | inverts the following expression (changes false to true, and vice versa) | +| `\|` | logical OR | +| `&&` | logical AND | + +Here's an example of using the logical operators: + +```dart +if (!done && (col == 0 || col == 3)) { + // ...Do something... +} +``` + +#### Bitwise and shift operators +You can manipulate the individual bits of numbers in Dart. Usually, you'd use these bitwise and shift operators with integers. + +| Operator | Meaning | +| ----------- | ----------------------------------------------------- | +| `&` | AND | +| `\|` | OR | +| `^` | XOR | +| `~`_`expr`_ | Unary bitwise complement (0s become 1s; 1s become 0s) | +| `<<` | Shift left | +| `>>` | Shift right | +| `>>>` | Unsigned shift right | + +Here's an example of using bitwise and shift operators: + +```dart +final value = 0x22; +final bitmask = 0x0f; + +assert((value & bitmask) == 0x02); // AND +assert((value & ~bitmask) == 0x20); // AND NOT +assert((value | bitmask) == 0x2f); // OR +assert((value ^ bitmask) == 0x2d); // XOR + +assert((value << 4) == 0x220); // Shift left +assert((value >> 4) == 0x02); // Shift right + +// Shift right example that results in different behavior on web +// because the operand value changes when masked to 32 bits: +assert((-value >> 4) == -0x03); + +assert((value >>> 4) == 0x02); // Unsigned shift right +assert((-value >>> 4) > 0); // Unsigned shift right +``` + +#### Conditional expressions +Dart has two operators that let you concisely evaluate expressions that might otherwise require if-else statements: + +_`condition`_ `?` _`expr1`_ `:` _`expr2`_ + +If _condition_ is true, evaluates _expr1_ (and returns its value); otherwise, evaluates and returns the value of _expr2_. + +_`expr1`_ `??` _`expr2`_ + +If _expr1_ is non-null, returns its value; otherwise, evaluates and returns the value of _expr2_. + +When you need to assign a value based on a boolean expression, consider using the conditional operator `?` and `:`. + +```dart +var visibility = isPublic ? 'public' : 'private'; +``` + +If the boolean expression tests for null, consider using the if-null operator `??` (also known as the null-coalescing operator). + +```dart +String playerName(String? name) => name ?? 'Guest'; +``` + +The previous example could have been written at least two other ways, but not as succinctly: + +```dart +// Slightly longer version uses ?: operator. +String playerName(String? name) => name != null ? name : 'Guest'; + +// Very long version uses if-else statement. +String playerName(String? name) { + if (name != null) { + return name; + } else { + return 'Guest'; + } +} +``` + +#### Cascade notation +Cascades (`..`, `?..`) allow you to make a sequence of operations on the same object. In addition to accessing instance members, you can also call instance methods on that same object. This often saves you the step of creating a temporary variable and allows you to write more fluid code. + +Consider the following code: + +```dart +var paint = Paint() + ..color = Colors.black + ..strokeCap = StrokeCap.round + ..strokeWidth = 5.0; +``` + +The constructor, `Paint()`, returns a `Paint` object. The code that follows the cascade notation operates on this object, ignoring any values that might be returned. + +The previous example is equivalent to this code: + +```dart +var paint = Paint(); +paint.color = Colors.black; +paint.strokeCap = StrokeCap.round; +paint.strokeWidth = 5.0; +``` + +If the object that the cascade operates on can be null, then use a _null-shorting_ cascade (`?..`) for the first operation. Starting with `?..` guarantees that none of the cascade operations are attempted on that null object. + +```dart +querySelector('#confirm') // Get an object. + ?..text = 'Confirm' // Use its members. + ..classes.add('important') + ..onClick.listen((e) => window.alert('Confirmed!')) + ..scrollIntoView(); +``` + +The previous code is equivalent to the following: + +```dart +var button = querySelector('#confirm'); +button?.text = 'Confirm'; +button?.classes.add('important'); +button?.onClick.listen((e) => window.alert('Confirmed!')); +button?.scrollIntoView(); +``` + +You can also nest cascades. For example: + +```dart +final addressBook = (AddressBookBuilder() + ..name = 'jenny' + ..email = 'jenny@example.com' + ..phone = (PhoneNumberBuilder() + ..number = '415-555-0100' + ..label = 'home') + .build()) + .build(); +``` + +Be careful to construct your cascade on a function that returns an actual object. For example, the following code fails: + +```dart +var sb = StringBuffer(); +sb.write('foo') + ..write('bar'); // Error: method 'write' isn't defined for 'void'. +``` + +The `sb.write()` call returns void, and you can't construct a cascade on `void`. + +#### Spread operators +Spread operators evaluate an expression that yields a collection, unpacks the resulting values, and inserts them into another collection. + +**The spread operator isn't actually an operator expression**. The `...`/`...?` syntax is part of the collection literal itself. + +Because it isn't an operator, the syntax doesn't have any "operator precedence". Effectively, it has the lowest "precedence" — any kind of expression is valid as the spread target, such as: + +```dart +[...a + b] +``` + +#### Other operators +You've seen most of the remaining operators in other examples: + +| Operator | Name | Meaning | +| -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `()` | Function application | Represents a function call | +| `[]` | Subscript access | Represents a call to the overridable `[]` operator; example: `fooList[1]` passes the int `1` to `fooList` to access the element at index `1` | +| `?[]` | Conditional subscript access | Like `[]`, but the leftmost operand can be null; example: `fooList?[1]` passes the int `1` to `fooList` to access the element at index `1` unless `fooList` is null (in which case the expression evaluates to null) | +| `.` | Member access | Refers to a property of an expression; example: `foo.bar` selects property `bar` from expression `foo` | +| `?.` | Conditional member access | Like `.`, but the leftmost operand can be null; example: `foo?.bar` selects property `bar` from expression `foo` unless `foo` is null (in which case the value of `foo?.bar` is null) | +| `!` | Non-null assertion operator | Casts an expression to its underlying non-nullable type, throwing a runtime exception if the cast fails; example: `foo!.bar` asserts `foo` is non-null and selects the property `bar`, unless `foo` is null in which case a runtime exception is thrown | + +### Comments +Dart supports single-line comments, multi-line comments, and documentation comments. + +####Single-line comments +A single-line comment begins with `//`. Everything between `//` and the end of line is ignored by the Dart compiler. +```dart +void main() { + // TODO: refactor into an AbstractLlamaGreetingFactory? + print('Welcome to my Llama farm!'); +} +``` + +#### Multi-line comments +A mul ti-line comment begins with `/*` and ends with `*/`. Everything between `/*` and `*/` is ignored by the Dart compiler (unless the comment is a documentation comment; see the next section). Multi-line comments can nest. +```dart +void main() { + /* + * This is a lot of work. Consider raising chickens. + + Llama larry = Llama(); + larry.feed(); + larry.exercise(); + larry.clean(); + */ +} +``` + +#### Documentation comments +Documentation comments are multi-line or single-line comments that begin with `///` or `/**`. Using `///` on consecutive lines has the same effect as a multi-line doc comment. + +Inside a documentation comment, the analyzer ignores all text unless it is enclosed in brackets. Using brackets, you can refer to classes, methods, fields, top-level variables, functions, and parameters. The names in brackets are resolved in the lexical scope of the documented program element. + +Here is an example of documentation comments with references to other classes and arguments: +```dart +/// A domesticated South American camelid (Lama glama). +/// +/// Andean cultures have used llamas as meat and pack +/// animals since pre-Hispanic times. +/// +/// Just like any other animal, llamas need to eat, +/// so don't forget to [feed] them some [Food]. +class Llama { + String? name; + + /// Feeds your llama [food]. + /// + /// The typical llama eats one bale of hay per week. + void feed(Food food) { + // ... + } + + /// Exercises your llama with an [activity] for + /// [timeLimit] minutes. + void exercise(Activity activity, int timeLimit) { + // ... + } +} +``` + +In the class's generated documentation, `[feed]` becomes a link to the docs for the feed method, and `[Food]` becomes a link to the docs for the Food class. + +### Metadata +Use metadata to give additional information about your code. A metadata annotation begins with the character `@`, followed by either a reference to a compile-time constant (such as `deprecated`) or a call to a constant constructor. + +Four annotations are available to all Dart code: `@Deprecated`, `@deprecated`, `@override`, and `@pragma`. For examples of using `@override`, see Extending a class. Here's an example of using the `@Deprecated` annotation: +```dart +class Television { + /// Use [turnOn] to turn the power on instead. + @Deprecated('Use turnOn instead') + void activate() { + turnOn(); + } + + /// Turns the TV's power on. + void turnOn() {...} + // ··· +} +``` + +You can use `@deprecated` if you don't want to specify a message. However, we recommend always specifying a message with `@Deprecated`. + +You can define your own metadata annotations. Here's an example of defining a `@Todo` annotation that takes two arguments: +```dart +class Todo { + final String who; + final String what; + + const Todo(this.who, this.what); +} +``` + +And here's an example of using that `@Todo` annotation: +```dart +@Todo('Dash', 'Implement this function') +void doSomething() { + print('Do something'); +} +``` + +Metadata can appear before a library, class, typedef, type parameter, constructor, factory, function, field, parameter, or variable declaration and before an import or export directive. + +### Libraries +The `import` and `library` directives can help you create a modular and shareable code base. Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore (`_`) are visible only inside the library. Every Dart file (plus its parts) is a library, even if it doesn't use a library directive. + +Libraries can be distributed using packages. + +#### Using libraries +Use `import` to specify how a namespace from one library is used in the scope of another library. + +For example, Dart web apps generally use the `dart:html` library, which they can import like this: +```dart +import 'dart:html'; +``` + +The only required argument to import is a URI specifying the library. For built-in libraries, the URI has the special `dart:` scheme. For other libraries, you can use a file system path or the `package:` scheme. The `package:` scheme specifies libraries provided by a package manager such as the pub tool. For example: +```dart +import 'package:test/test.dart'; +``` + +#### Specifying a library prefix +If you import two libraries that have conflicting identifiers, then you can specify a prefix for one or both libraries. For example, if library1 and library2 both have an Element class, then you might have code like this: +```dart +import 'package:lib1/lib1.dart'; +import 'package:lib2/lib2.dart' as lib2; + +// Uses Element from lib1. +Element element1 = Element(); + +// Uses Element from lib2. +lib2.Element element2 = lib2.Element(); +``` + +#### Importing only part of a library +If you want to use only part of a library, you can selectively import the library. For example: +```dart +// Import only foo. +import 'package:lib1/lib1.dart' show foo; + +// Import all names EXCEPT foo. +import 'package:lib2/lib2.dart' hide foo; +``` + +#### Lazily loading a library +Deferred loading (also called lazy loading) allows a web app to load a library on demand, if and when the library is needed. Use deferred loading when you want to meet one or more of the following needs. +- Reduce a web app's initial startup time. +- Perform A/B testing—trying out alternative implementations of an algorithm, for example. +- Load rarely used functionality, such as optional screens and dialogs. + +That doesn't mean Dart loads all the deferred components at start time. The web app can download deferred components via the web when needed. + +The dart tool doesn't support deferred loading for targets other than web. If you're building a [Flutter](../frameworks/Flutter.md) app, consult its implementation of deferred loading in the [Flutter](../frameworks/Flutter.md) guide on deferred components. + +To lazily load a library, first import it using deferred as. +```dart +import 'package:greetings/hello.dart' deferred as hello; +``` + +When you need the library, invoke `loadLibrary()` using the library's identifier. +```dart +Future greet() async { + await hello.loadLibrary(); + hello.printGreeting(); +} +``` + +In the preceding code, the `await` keyword pauses execution until the library is loaded. + +You can invoke `loadLibrary()` multiple times on a library without problems. The library is loaded only once. + +Keep in mind the following when you use deferred loading: + +- A deferred library's constants aren't constants in the importing file. Remember, these constants don't exist until the deferred library is loaded. +- You can't use types from a deferred library in the importing file. Instead, consider moving interface types to a library imported by both the deferred library and the importing file. +- Dart implicitly inserts loadLibrary() into the namespace that you define using deferred as namespace. The loadLibrary() function returns a Future. + +#### The library directive +To specify library-level doc comments or metadata annotations, attach them to a library declaration at the start of the file. +```dart +/// A really great test library. +@TestOn('browser') +library; +``` + +### Types +The Dart language has special support for the following: +- Numbers (`int`, `double`) +- Strings (`String`) +- Booleans (`bool`) +- Records (`(value1, value2)`) +- Lists (`List`, also known as arrays) +- Sets (`Set`) +- Maps (`Map`) +- Runes (`Runes`; often replaced by the characters API) +- Symbols (`Symbol`) +- The value null (`Null`) + +This support includes the ability to create objects using literals. For example, 'this is a string' is a string literal, and `true` is a boolean literal. + +Because every variable in Dart refers to an object you can usually use constructors to initialize variables. Some of the built-in types have their own constructors. For example, you can use the `Map()` constructor to create a map. + +Some other types also have special roles in the Dart language: +- `Object`: The superclass of all Dart classes except Null. +- `Enum`: The superclass of all enums. +- `Future` and Stream: Used in asynchrony support. +- `Iterable`: Used in for-in loops and in synchronous generator functions. +- `Never`: Indicates that an expression can never successfully finish evaluating. Most often used for functions that always throw an exception. +- `dynamic`: Indicates that you want to disable static checking. Usually you should use Object or Object? instead. +- `void`: Indicates that a value is never used. Often used as a return type. + +#### Numbers +Dart numbers come in two flavors: + +`int` + +Integer values no larger than 64 bits, depending on the platform. On native platforms, values can be from -263 to 263 - 1. On the web, integer values are represented as JavaScript numbers (64-bit floating-point values with no fractional part) and can be from -253 to 253 - 1. + +`double` + +64-bit (double-precision) floating-point numbers, as specified by the IEEE 754 standard. + +Both `int` and `double` are subtypes of `num`. The num type includes basic operators such as +, -, /, and *, and is also where you'll find `abs()`,`ceil()`, and `floor()`, among other methods. (Bitwise operators, such as >>, are defined in the `int` class.) If num and its subtypes don't have what you're looking for, the `dart:math` library might. + +Integers are numbers without a decimal point. Here are some examples of defining integer literals: +```dart +var x = 1; +var hex = 0xDEADBEEF; +``` + +If a number includes a decimal, it is a `double`. Here are some examples of defining double literals: +```dart +var y = 1.1; +var exponents = 1.42e5; +``` + +You can also declare a variable as a `num`. If you do this, the variable can have both integer and double values. +```dart +num x = 1; // x can have both int and double values +x += 2.5; +``` + +Integer literals are automatically converted to doubles when necessary: +```dart +double z = 1; // Equivalent to double z = 1.0. +``` + +Here's how you turn a string into a number, or vice versa: +```dart +// String -> int +var one = int.parse('1'); +assert(one == 1); + +// String -> double +var onePointOne = double.parse('1.1'); +assert(onePointOne == 1.1); + +// int -> String +String oneAsString = 1.toString(); +assert(oneAsString == '1'); + +// double -> String +String piAsString = 3.14159.toStringAsFixed(2); +assert(piAsString == '3.14'); +``` + +#### Strings +A Dart string (`String` object) holds a sequence of UTF-16 code units. You can use either single or double quotes to create a string: +```dart +var s1 = 'Single quotes work well for string literals.'; +var s2 = "Double quotes work just as well."; +var s3 = 'It\'s easy to escape the string delimiter.'; +var s4 = "It's even easier to use the other delimiter."; +``` + +You can put the value of an expression inside a string by using `${expression}`. If the expression is an identifier, you can skip the `{}`. To get the string corresponding to an object, Dart calls the object's `toString()` method. +```dart +var s = 'string interpolation'; + +assert('Dart has $s, which is very handy.' == + 'Dart has string interpolation, ' + 'which is very handy.'); +assert('That deserves all caps. ' + '${s.toUpperCase()} is very handy!' == + 'That deserves all caps. ' + 'STRING INTERPOLATION is very handy!'); +``` + +> **Note**: The `==` operator tests whether two objects are equivalent. Two strings are equivalent if they contain the same sequence of code units. + +You can concatenate strings using adjacent string literals or the `+` operator: +```dart +var s1 = 'String ' + 'concatenation' + " works even over line breaks."; +assert(s1 == + 'String concatenation works even over ' + 'line breaks.'); + +var s2 = 'The + operator ' + 'works, as well.'; +assert(s2 == 'The + operator works, as well.'); +``` + +To create a multi-line string, use a triple quote with either single or double quotation marks: +```dart +var s1 = ''' +You can create +multi-line strings like this one. +'''; + +var s2 = """This is also a +multi-line string."""; +``` + +You can create a "raw" string by prefixing it with `r`: +```dart +var s = r'In a raw string, not even \n gets special treatment.'; +``` + +See Runes and grapheme clusters for details on how to express [Unicode](../../../files/Unicode.md) characters in a string. + +Literal strings are compile-time constants, as long as any interpolated expression is a compile-time constant that evaluates to `null` or a `numeric`, `string`, or `boolean` value. +```dart +// These work in a const string. +const aConstNum = 0; +const aConstBool = true; +const aConstString = 'a constant string'; + +// These do NOT work in a const string. +var aNum = 0; +var aBool = true; +var aString = 'a string'; +const aConstList = [1, 2, 3]; + +const validConstString = '$aConstNum $aConstBool $aConstString'; +// const invalidConstString = '$aNum $aBool $aString $aConstList'; +``` + +#### Booleans +To represent boolean values, Dart has a type named `bool`. Only two objects have type `bool`: the boolean literals `true` and `false`, which are both compile-time constants. + +Dart's type safety means that you can't use code like `if (nonbooleanValue)` or `assert (nonbooleanValue)`. Instead, explicitly check for values, like this: +```dart +// Check for an empty string. +var fullName = ''; +assert(fullName.isEmpty); + +// Check for zero. +var hitPoints = 0; +assert(hitPoints == 0); + +// Check for null. +var unicorn = null; +assert(unicorn == null); + +// Check for NaN. +var iMeantToDoThis = 0 / 0; +assert(iMeantToDoThis.isNaN); +``` + +#### Runes and grapheme clusters +In Dart, runes expose the [Unicode](../../../files/Unicode.md) code points of a string. You can use the characters package to view or manipulate user-perceived characters, also known as [Unicode](../../../files/Unicode.md) (extended) grapheme clusters. + +[Unicode](../../../files/Unicode.md) defines a unique numeric value for each letter, digit, and symbol used in all of the world's writing systems. Because a Dart string is a sequence of UTF-16 code units, expressing [Unicode](../../../files/Unicode.md) code points within a string requires special syntax. The usual way to express a [Unicode](../../../files/Unicode.md) code point is `\uXXXX`, where `XXXX` is a 4-digit hexadecimal value. For example, the heart character (♥) is `\u2665`. To specify more or less than 4 hex digits, place the value in curly brackets. For example, the laughing emoji (😆) is `\u{1f606}`. + +If you need to read or write individual [Unicode](../../../files/Unicode.md) characters, use the characters getter defined on String by the characters package. The returned Characters object is the string as a sequence of grapheme clusters. Here's an example of using the characters API: +```dart +import 'package:characters/characters.dart'; + +void main() { + var hi = 'Hi 🇩🇰'; + print(hi); + print('The end of the string: ${hi.substring(hi.length - 1)}'); + print('The last character: ${hi.characters.last}'); +} +``` + +The output, depending on your environment, looks something like this: +``` +$ dart run bin/main.dart +Hi 🇩🇰 +The end of the string: ??? +The last character: 🇩🇰 +``` + +For details on using the characters package to manipulate strings, see the example and API reference for the characters package. + +#### Symbols +A Symbol object represents an operator or identifier declared in a Dart program. You might never need to use symbols, but they're invaluable for APIs that refer to identifiers by name, because minification changes identifier names but not identifier symbols. + +To get the symbol for an identifier, use a symbol literal, which is just `#` followed by the identifier: +```dart +#radix +#bar +``` + +Symbol literals are compile-time constants. + +#### Records +Records are an anonymous, immutable, aggregate type. Like other collection types, they let you bundle multiple objects into a single object. Unlike other collection types, records are fixed-sized, heterogeneous, and typed. + +Records are real values; you can store them in variables, nest them, pass them to and from functions, and store them in data structures such as lists, maps, and sets. + +##### Record syntax +Records expressions are comma-delimited lists of named or positional fields, enclosed in parentheses: +```dart +var record = ('first', a: 2, b: true, 'last'); +``` + +Record type annotations are comma-delimited lists of types enclosed in parentheses. You can use record type annotations to define return types and parameter types. For example, the following `(int, int)` statements are record type annotations: +```dart +(int, int) swap((int, int) record) { + var (a, b) = record; + return (b, a); +} +``` + +Fields in record expressions and type annotations mirror how parameters and arguments work in functions. Positional fields go directly inside the parentheses: +```dart +// Record type annotation in a variable declaration: +(String, int) record; + +// Initialize it with a record expression: +record = ('A string', 123); +``` + +In a record type annotation, named fields go inside a curly brace-delimited section of type-and-name pairs, after all positional fields. In a record expression, the names go before each field value with a colon after: +```dart +// Record type annotation in a variable declaration: +({int a, bool b}) record; + +// Initialize it with a record expression: +record = (a: 123, b: true); +``` + +The names of named fields in a record type are part of the record's type definition, or its shape. Two records with named fields with different names have different types: +```dart +({int a, int b}) recordAB = (a: 1, b: 2); +({int x, int y}) recordXY = (x: 3, y: 4); + +// Compile error! These records don't have the same type. +// recordAB = recordXY; +``` + +In a record type annotation, you can also name the positional fields, but these names are purely for documentation and don't affect the record's type: +```dart +(int a, int b) recordAB = (1, 2); +(int x, int y) recordXY = (3, 4); + +recordAB = recordXY; // OK. +``` + +This is similar to how positional parameters in a function declaration or function typedef can have names but those names don't affect the signature of the function. + +##### Record fields +Record fields are accessible through built-in getters. Records are immutable, so fields do not have setters. + +Named fields expose getters of the same name. Positional fields expose getters of the name `$`, skipping named fields: +```dart +var record = ('first', a: 2, b: true, 'last'); + +print(record.$1); // Prints 'first' +print(record.a); // Prints 2 +print(record.b); // Prints true +print(record.$2); // Prints 'last' +``` + +##### Record types +There is no type declaration for individual record types. Records are structurally typed based on the types of their fields. A record's shape (the set of its fields, the fields' types, and their names, if any) uniquely determines the type of a record. + +Each field in a record has its own type. Field types can differ within the same record. The type system is aware of each field's type wherever it is accessed from the record: +```dart +(num, Object) pair = (42, 'a'); + +var first = pair.$1; // Static type `num`, runtime type `int`. +var second = pair.$2; // Static type `Object`, runtime type `String`. +``` + +##### Record equality +Two records are equal if they have the same shape (set of fields), and their corresponding fields have the same values. Since named field order is not part of a record's shape, the order of named fields does not affect equality. + +For example: +```dart +(int x, int y, int z) point = (1, 2, 3); +(int r, int g, int b) color = (1, 2, 3); + +print(point == color); // Prints 'true'. + +({int x, int y, int z}) point = (x: 1, y: 2, z: 3); +({int r, int g, int b}) color = (r: 1, g: 2, b: 3); + +print(point == color); // Prints 'false'. Lint: Equals on unrelated types. +``` + +Records automatically define `hashCode` and `==` methods based on the structure of their fields. + +##### Multiple returns +Records allow functions to return multiple values bundled together. To retrieve record values from a return, destructure the values into local variables using pattern matching. +```dart +// Returns multiple values in a record: +(String name, int age) userInfo(Map json) { + return (json['name'] as String, json['age'] as int); +} + +final json = { + 'name': 'Dash', + 'age': 10, + 'color': 'blue', +}; + +// Destructures using a record pattern with positional fields: +var (name, age) = userInfo(json); + +/* Equivalent to: + var info = userInfo(json); + var name = info.$1; + var age = info.$2; +*/ +``` + +You can also destructure a record using its named fields, using the colon `:` syntax. +```dart +({String name, int age}) userInfo(Map json) +// ··· +// Destructures using a record pattern with named fields: +final (:name, :age) = userInfo(json); +``` + +You can return multiple values from a function without records, but other methods come with downsides. For example, creating a class is much more verbose, and using other collection types like List or Map loses type safety. + +#### Collections +Dart has built-in support for list, set, and map collections. To learn more about configuring the types collections contain, check out Generics. + +##### Lists +Perhaps the most common collection in nearly every programming language is the array, or ordered group of objects. In Dart, arrays are List objects, so most people just call them lists. + +Dart list literals are denoted by a comma separated list of expressions or values, enclosed in square brackets (`[]`). Here's a simple Dart list: +```dart +var list = [1, 2, 3]; +``` + +> **Note**: Dart infers that list has type `List`. If you try to add non-integer objects to this list, the analyzer or runtime raises an error. + +You can add a comma after the last item in a Dart collection literal. This trailing comma doesn't affect the collection, but it can help prevent copy-paste errors. +```dart +var list = [ + 'Car', + 'Boat', + 'Plane', +]; +``` + +Lists use zero-based indexing, where 0 is the index of the first value and `list.length - 1` is the index of the last value. You can get a list's length using the .length property and access a list's values using the subscript operator (`[]`): +```dart +var list = [1, 2, 3]; +assert(list.length == 3); +assert(list[1] == 2); + +list[1] = 1; +assert(list[1] == 1); +``` + +To create a list that's a compile-time constant, add `const` before the list literal: +```dart +var constantList = const [1, 2, 3]; +// constantList[1] = 1; // This line will cause an error. +``` + +##### Sets +A set in Dart is an unordered collection of unique items. Dart support for sets is provided by set literals and the Set type. + +Here is a simple Dart set, created using a set literal: +```dart +var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'}; +``` + +> **Note**: Dart infers that halogens has the type `Set`. If you try to add the wrong type of value to the set, the analyzer or runtime raises an error. + +To create an empty set, use `{}` preceded by a type argument, or assign `{}` to a variable of type `Set`: +```dart +var names = {}; +// Set names = {}; // This works, too. +// var names = {}; // Creates a map, not a set. +``` + +Set or map? + +The syntax for map literals is similar to that for set literals. Because map literals came first, `{}` defaults to the Map type. If you forget the type annotation on `{}` or the variable it's assigned to, then Dart creates an object of type `Map`. + +Add items to an existing set using the `add()` or `addAll()` methods: +```dart +var elements = {}; +elements.add('fluorine'); +elements.addAll(halogens); +``` + +Use .length to get the number of items in the set: +```dart +var elements = {}; +elements.add('fluorine'); +elements.addAll(halogens); +assert(elements.length == 5); +``` + +To create a set that's a compile-time constant, add `const` before the set literal: +```dart +final constantSet = const { + 'fluorine', + 'chlorine', + 'bromine', + 'iodine', + 'astatine', +}; +// constantSet.add('helium'); // This line will cause an error. +``` + +##### Maps +In general, a map is an object that associates keys and values. Both keys and values can be any type of object. Each key occurs only once, but you can use the same value multiple times. Dart support for maps is provided by map literals and the Map type. + +Here are a couple of simple Dart maps, created using map literals: +```dart +var gifts = { + // Key: Value + 'first': 'partridge', + 'second': 'turtledoves', + 'fifth': 'golden rings' +}; + +var nobleGases = { + 2: 'helium', + 10: 'neon', + 18: 'argon', +}; +``` + +> **Note**: Dart infers that gifts has the type `Map` and nobleGases has the type `Map`. If you try to add the wrong type of value to either map, the analyzer or runtime raises an error. For more information, read about type inference. + +You can create the same objects using a Map constructor: +```dart +var gifts = Map(); +gifts['first'] = 'partridge'; +gifts['second'] = 'turtledoves'; +gifts['fifth'] = 'golden rings'; + +var nobleGases = Map(); +nobleGases[2] = 'helium'; +nobleGases[10] = 'neon'; +nobleGases[18] = 'argon'; +``` + +> **Note**: If you come from a language like C# or Java, you might expect to see `new Map()` instead of just `Map()`. In Dart, the `new` keyword is optional. + +Add a new key-value pair to an existing map using the subscript assignment operator (`[]=`): +```dart +var gifts = {'first': 'partridge'}; +gifts['fourth'] = 'calling birds'; // Add a key-value pair +``` + +Retrieve a value from a map using the subscript operator (`[]`): +```dart +var gifts = {'first': 'partridge'}; +assert(gifts['first'] == 'partridge'); +``` + +If you look for a key that isn't in a map, you get `null` in return: +```dart +var gifts = {'first': 'partridge'}; +assert(gifts['fifth'] == null); +``` + +Use .length to get the number of key-value pairs in the map: +```dart +var gifts = {'first': 'partridge'}; +gifts['fourth'] = 'calling birds'; +assert(gifts.length == 2); +``` + +To create a map that's a compile-time constant, add `const` before the map literal: +```dart +final constantMap = const { + 2: 'helium', + 10: 'neon', + 18: 'argon', +}; + +// constantMap[2] = 'Helium'; // This line will cause an error. +``` + +###### Spread operators +Dart supports the spread operator (`...`) and the null-aware spread operator (`...?`) in list, map, and set literals. Spread operators provide a concise way to insert multiple values into a collection. + +For example, you can use the spread operator (`...`) to insert all the values of a list into another list: +```dart +var list = [1, 2, 3]; +var list2 = [0, ...list]; +assert(list2.length == 4); +``` + +If the expression to the right of the spread operator might be `null`, you can avoid exceptions by using a null-aware spread operator (`...?`): +```dart +var list2 = [0, ...?list]; +assert(list2.length == 1); +``` + +###### Control-flow operators +Dart offers collection if and collection for for use in list, map, and set literals. You can use these operators to build collections using conditionals (`if`) and repetition (`for`). + +Here's an example of using collection if to create a list with three or four items in it: +```dart +var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet']; +``` + +Dart also supports if-case inside collection literals: +```dart +var nav = ['Home', 'Furniture', 'Plants', if (login case 'Manager') 'Inventory']; +``` + +Here's an example of using collection for to manipulate the items of a list before adding them to another list: +```dart +var listOfInts = [1, 2, 3]; +var listOfStrings = ['#0', for (var i in listOfInts) '#$i']; +assert(listOfStrings[1] == '#1'); +``` + +#### Generics +If you look at the API documentation for the basic array type, List, you'll see that the type is actually `List`. The `<...>` notation marks List as a generic (or parameterized) type—a type that has formal type parameters. By convention, most type variables have single-letter names, such as E, T, S, K, and V. + +Generics are often required for type safety, but they have more benefits than just allowing your code to run: +- Properly specifying generic types results in better generated code. +- You can use generics to reduce code duplication. + +If you intend for a list to contain only strings, you can declare it as `List` (read that as "list of string"). That way you, your fellow programmers, and your tools can detect that assigning a non-string to the list is probably a mistake. + +Another reason for using generics is to reduce code duplication. Generics let you share a single interface and implementation between many types, while still taking advantage of static analysis. For example, say you create an interface for caching an object: +```dart +abstract class ObjectCache { + Object getByKey(String key); + void setByKey(String key, Object value); +} +``` + +You discover that you want a string-specific version of this interface, so you create another interface: +```dart +abstract class StringCache { + String getByKey(String key); + void setByKey(String key, String value); +} +``` + +Later, you decide you want a number-specific version of this interface... You get the idea. + +Generic types can save you the trouble of creating all these interfaces. Instead, you can create a single interface that takes a type parameter: +```dart +abstract class Cache { + T getByKey(String key); + void setByKey(String key, T value); +} +``` + +In this code, `T` is the stand-in type. It's a placeholder that you can think of as a type that a developer will define later. + +List, set, and map literals can be parameterized. Parameterized literals are just like the literals you've already seen, except that you add (for lists and sets) or (for maps) before the opening bracket. Here is an example of using typed literals: +```dart +var names = ['Seth', 'Kathy', 'Lars']; +var uniqueNames = {'Seth', 'Kathy', 'Lars'}; +var pages = { + 'index.html': 'Homepage', + 'robots.txt': 'Hints for web robots', + 'humans.txt': 'We are people, not machines' +}; +``` + +To specify one or more types when using a constructor, put the types in angle brackets (`<...>`) just after the class name. For example: +```dart +var nameSet = Set.from(names); +``` + +The following code creates a map that has integer keys and values of type View: +```dart +var views = Map(); +``` + +Dart generic types are reified, which means that they carry their type information around at runtime. For example, you can test the type of a collection: +```dart +var names = []; +names.addAll(['Seth', 'Kathy', 'Lars']); +print(names is List); // true +``` + +##### Restricting the parameterized type +When implementing a generic type, you might want to limit the types that can be provided as arguments, so that the argument must be a subtype of a particular type. You can do this using extends. + +A common use case is ensuring that a type is non-nullable by making it a subtype of `Object` (instead of the default, `Object?`). +```dart +class Foo { + // Any type provided to Foo for T must be non-nullable. +} +``` + +You can use extends with other types besides `Object`. Here's an example of extending `SomeBaseClass`, so that members of `SomeBaseClass` can be called on objects of type `T`: +```dart +class Foo { + // Implementation goes here... + String toString() => "Instance of 'Foo<$T>'"; +} + +class Extender extends SomeBaseClass {...} +``` + +It's OK to use `SomeBaseClass` or any of its subtypes as the generic argument: +```dart +var someBaseClassFoo = Foo(); +var extenderFoo = Foo(); +``` + +It's also OK to specify no generic argument: +```dart +var foo = Foo(); +print(foo); // Instance of 'Foo' +``` + +Specifying any non-SomeBaseClass type results in an error. + +##### Using generic methods +Methods and functions also allow type arguments: +```dart +T first(List ts) { + // Do some initial work or error checking, then... + T tmp = ts[0]; + // Do some additional checking or processing... + return tmp; +} +``` + +Here the generic type parameter on first (``) allows you to use the type argument `T` in several places: + +- In the function's return type (`T`). +- In the type of an argument (`List`). +- In the type of a local variable (`T tmp`). + +### Patterns +Patterns are a syntactic category in the Dart language, like statements and expressions. A pattern represents the shape of a set of values that it may match against actual values. + +#### Logical-or +`subpattern1 || subpattern2` + +A logical-or pattern separates subpatterns by `||` and matches if any of the branches match. Branches are evaluated left-to-right. Once a branch matches, the rest are not evaluated. +```dart +var isPrimary = switch (color) { + Color.red || Color.yellow || Color.blue => true, + _ => false +}; +``` + +Subpatterns in a logical-or pattern can bind variables, but the branches must define the same set of variables, because only one branch will be evaluated when the pattern matches. +#### Logical-and +`subpattern1 && subpattern2` + +A pair of patterns separated by `&&` matches only if both subpatterns match. If the left branch does not match, the right branch is not evaluated. + +Subpatterns in a logical-and pattern can bind variables, but the variables in each subpattern must not overlap, because they will both be bound if the pattern matches: +```dart +switch ((1, 2)) { + // Error, both subpatterns attempt to bind 'b'. + case (var a, var b) && (var b, var c): // ... +} +``` + +#### Relational +`== expression` + +`< expression` + +Relational patterns compare the matched value to a given constant using any of the equality or relational operators: `==`, `!=`, `<`, `>`, `<=`, and `>=`. + +The pattern matches when calling the appropriate operator on the matched value with the constant as an argument returns true. + +Relational patterns are useful for matching on numeric ranges, especially when combined with the logical-and pattern: +```dart +String asciiCharType(int char) { + const space = 32; + const zero = 48; + const nine = 57; + + return switch (char) { + < space => 'control', + == space => 'space', + > space && < zero => 'punctuation', + >= zero && <= nine => 'digit', + _ => '' + }; +} +``` + +#### Cast +`foo as String` + +A cast pattern lets you insert a type cast in the middle of destructuring, before passing the value to another subpattern: +```dart +(num, Object) record = (1, 's'); +var (i as int, s as String) = record; +``` + +Cast patterns will throw if the value doesn't have the stated type. Like the null-assert pattern, this lets you forcibly assert the expected type of some destructured value. + +#### Null-check +`subpattern?` + +Null-check patterns match first if the value is not null, and then match the inner pattern against that same value. They let you bind a variable whose type is the non-nullable base type of the nullable value being matched. + +To treat null values as match failures without throwing, use the null-check pattern. +```dart +String? maybeString = 'nullable with base type String'; +switch (maybeString) { + case var s?: + // 's' has type non-nullable String here. +} +``` + +To match when the value is `null`, use the constant pattern null. + +#### Null-assert +`subpattern!` + +Null-assert patterns match first if the object is not null, then on the value. They permit non-null values to flow through, but throw if the matched value is `null`. + +To ensure `null` values are not silently treated as match failures, use a null-assert pattern while matching: +```dart +List row = ['user', null]; +switch (row) { + case ['user', var name!]: // ... + // 'name' is a non-nullable string here. +} +``` + +To eliminate `null` values from variable declaration patterns, use the null-assert pattern: +```dart +(int?, int?) position = (2, 3); + +var (x!, y!) = position; +``` + +To match when the value is `null`, use the constant pattern null. + +#### Constant +`123, null, 'string', math.pi, SomeClass.constant, const Thing(1, 2), const (1 + 2)` + +Constant patterns match when the value is equal to the constant: +```dart +switch (number) { + // Matches if 1 == number. + case 1: // ... +} +``` + +More complex constant expressions must be parenthesized and prefixed with `const` (`const (1 + 2)`): +```dart +// List or map pattern: +case [a, b]: // ... + +// List or map literal: +case const [a, b]: // ... +``` + +#### Variable +`var bar, String str, final int _` + +Variable patterns bind new variables to values that have been matched or destructured. They usually occur as part of a destructuring pattern to capture a destructured value. + +The variables are in scope in a region of code that is only reachable when the pattern has matched. +```dart +switch ((1, 2)) { + // 'var a' and 'var b' are variable patterns that bind to 1 and 2, respectively. + case (var a, var b): // ... + // 'a' and 'b' are in scope in the case body. +} +``` + +A typed variable pattern only matches if the matched value has the declared type, and fails otherwise: +```dart +switch ((1, 2)) { + // Does not match. + case (int a, String b): // ... +} +``` + +You can use a wildcard pattern as a variable pattern. + +#### Identifier +`foo, _` + +Identifier patterns may behave like a constant pattern or like a variable pattern, depending on the context where they appear: + +- Declaration context: declares a new variable with identifier name: `var (a, b) = (1, 2);` +- Assignment context: assigns to existing variable with identifier name: `(a, b) = (3, 4);` +- Matching context: treated as a named constant pattern (unless its name is `_`): +```dart +const c = 1; +switch (2) { + case c: + print('match $c'); + default: + print('no match'); // Prints "no match". +} +``` + +Wildcard identifier in any context: matches any value and discards it: `case [_, var y, _]: print('The middle element is $y');` + +#### Parenthesized +`(subpattern)` + +Like parenthesized expressions, parentheses in a pattern let you control pattern precedence and insert a lower-precedence pattern where a higher precedence one is expected. + +For example, imagine the boolean constants x, y, and z equal true, true, and false, respectively. Though the following example resembles boolean expression evaulation, the example matches patterns: +```dart +// ... +x || y => 'matches true', +x || y && z => 'matches true', +x || (y && z) => 'matches true', +// `x || y && z` is the same thing as `x || (y && z)`. +(x || y) && z => 'matches nothing', +// ... +``` + +#### List +`[subpattern1, subpattern2]` + +A list pattern matches values that implement List, and then recursively matches its subpatterns against the list's elements to destructure them by position: +```dart +const a = 'a'; +const b = 'b'; +switch (obj) { + // List pattern [a, b] matches obj first if obj is a list with two fields, + // then if its fields match the constant subpatterns 'a' and 'b'. + case [a, b]: + print('$a, $b'); +} +``` + +List patterns require that the number of elements in the pattern match the entire list. You can, however, use a rest element as a place holder to account for any number of elements in a list. + +#### Rest element +List patterns can contain one rest element (...) which allows matching lists of arbitrary lengths. +```dart +var [a, b, ..., c, d] = [1, 2, 3, 4, 5, 6, 7]; +// Prints "1 2 6 7". +print('$a $b $c $d'); +``` + +A rest element can also have a subpattern that collects elements that don't match the other subpatterns in the list, into a new list: +```dart +var [a, b, ...rest, c, d] = [1, 2, 3, 4, 5, 6, 7]; +// Prints "1 2 [3, 4, 5] 6 7". +print('$a $b $rest $c $d'); +``` + +#### Map +`{"key": subpattern1, someConst: subpattern2}` + +Map patterns match values that implement Map, and then recursively match its subpatterns against the map's keys to destructure them. + +Map patterns don't require the pattern to match the entire map. A map pattern ignores any keys that the map contains that aren't matched by the pattern. + +#### Record +`(subpattern1, subpattern2)` + +`(x: subpattern1, y: subpattern2)` + +Record patterns match a record object and destructure its fields. If the value isn't a record with the same shape as the pattern, the match fails. Otherwise, the field subpatterns are matched against the corresponding fields in the record. + +Record patterns require that the pattern match the entire record. To destructure a record with named fields using a pattern, include the field names in the pattern: +```dart +var (myString: foo, myNumber: bar) = (myString: 'string', myNumber: 1); +``` + +The getter name can be omitted and inferred from the variable pattern or identifier pattern in the field subpattern. These pairs of patterns are each equivalent: +```dart +// Record pattern with variable subpatterns: +var (untyped: untyped, typed: int typed) = record; +var (:untyped, :int typed) = record; + +switch (record) { + case (untyped: var untyped, typed: int typed): // ... + case (:var untyped, :int typed): // ... +} + +// Record pattern with null-check and null-assert subpatterns: +switch (record) { + case (checked: var checked?, asserted: var asserted!): // ... + case (:var checked?, :var asserted!): // ... +} + +// Record pattern with cast subpattern: +var (untyped: untyped as int, typed: typed as String) = record; +var (:untyped as int, :typed as String) = record; +``` + +#### Object +`SomeClass(x: subpattern1, y: subpattern2)` + +Object patterns check the matched value against a given named type to destructure data using getters on the object's properties. They are refuted if the value doesn't have the same type. +```dart +switch (shape) { + // Matches if shape is of type Rect, and then against the properties of Rect. + case Rect(width: var w, height: var h): // ... +} +``` + +The getter name can be omitted and inferred from the variable pattern or identifier pattern in the field subpattern: +```dart +// Binds new variables x and y to the values of Point's x and y properties. +var Point(:x, :y) = Point(1, 2); +``` + +Object patterns don't require the pattern to match the entire object. If an object has extra fields that the pattern doesn't destructure, it can still match. + +#### Wildcard +`_` + +A pattern named `_` is a wildcard, either a variable pattern or identifier pattern, that doesn't bind or assign to any variable. + +It's useful as a placeholder in places where you need a subpattern in order to destructure later positional values: +```dart +var [_, two, _] = list; +``` + +A wildcard name with a type annotation is useful when you want to test a value's type but not bind the value to a name: +```dart +var list = [1, 2, 3]; + +switch (record) { + case (int _, String _): + print('First field is int and second is String.'); +} +``` + +### Functions +Dart is a true object-oriented language, so even functions are objects and have a type, `Function`. This means that functions can be assigned to variables or passed as arguments to other functions. You can also call an instance of a Dart class as if it were a function. + +Here's an example of implementing a function: +```dart +bool isNoble(int atomicNumber) { + return _nobleGases[atomicNumber] != null; +} +``` + +Although Effective Dart recommends type annotations for public APIs, the function still works if you omit the types: +```dart +isNoble(atomicNumber) { + return _nobleGases[atomicNumber] != null; +} +``` + +For functions that contain just one expression, you can use a shorthand syntax: +```dart +bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null; +``` + +The `=>` expr syntax is a shorthand for `{ return expr; }`. The `=>` notation is sometimes referred to as arrow syntax. + +#### Parameters +A function can have any number of required positional parameters. These can be followed either by named parameters or by optional positional parameters (but not both). + +You can use trailing commas when you pass arguments to a function or when you define function parameters. + +##### Named parameters +Named parameters are optional unless they're explicitly marked as required. + +When defining a function, use `{param1, param2, …}` to specify named parameters. If you don't provide a default value or mark a named parameter as required, their types must be nullable as their default value will be `null`: +```dart +/// Sets the [bold] and [hidden] flags ... +void enableFlags({bool? bold, bool? hidden}) {...} +``` + +When calling a function, you can specify named arguments using `paramName: value`. For example: +```dart +enableFlags(bold: true, hidden: false); +``` + +To define a default value for a named parameter besides null, use `=` to specify a default value. The specified value must be a compile-time constant. For example: +```dart +/// Sets the [bold] and [hidden] flags ... +void enableFlags({bool bold = false, bool hidden = false}) {...} + +// bold will be true; hidden will be false. +enableFlags(bold: true); +``` + +If you instead want a named parameter to be mandatory, requiring callers to provide a value for the parameter, annotate them with `required`: +```dart +const Scrollbar({super.key, required Widget child}); +``` + +A parameter marked as required can still be nullable: +```dart +const Scrollbar({super.key, required Widget? child}); +``` + +You might want to place positional arguments first, but Dart doesn't require it. Dart allows named arguments to be placed anywhere in the argument list when it suits your API: +```dart +repeat(times: 2, () { + ... +}); +``` + +##### Optional positional parameters +Wrapping a set of function parameters in `[]` marks them as optional positional parameters. If you don't provide a default value, their types must be nullable as their default value will `null`: +```dart +String say(String from, String msg, [String? device]) { + var result = '$from says $msg'; + if (device != null) { + result = '$result with a $device'; + } + return result; +} +``` + +Here's an example of calling this function without the optional parameter: +```dart +assert(say('Bob', 'Howdy') == 'Bob says Howdy'); +``` + +And here's an example of calling this function with the third parameter: +```dart +assert(say('Bob', 'Howdy', 'smoke signal') == + 'Bob says Howdy with a smoke signal'); +``` + +To define a default value for an optional positional parameter besides `null`, use `=` to specify a default value. The specified value must be a compile-time constant. For example: +```dart +String say(String from, String msg, [String device = 'carrier pigeon']) { + var result = '$from says $msg with a $device'; + return result; +} + +assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon'); +``` + +#### The `main()` function +Every app must have a top-level `main()` function, which serves as the entrypoint to the app. The `main()` function returns void and has an optional `List` parameter for arguments. + +Here's a simple `main()` function: +```dart +void main() { + print('Hello, World!'); +} +``` + +Here's an example of the `main()` function for a command-line app that takes arguments: +```dart +// Run the app like this: dart run args.dart 1 test +void main(List arguments) { + print(arguments); + + assert(arguments.length == 2); + assert(int.parse(arguments[0]) == 1); + assert(arguments[1] == 'test'); +} +``` + +You can use the `args` library to define and parse command-line arguments. + +#### Functions as first-class objects +You can pass a function as a parameter to another function. For example: +```dart +void printElement(int element) { + print(element); +} + +var list = [1, 2, 3]; + +// Pass printElement as a parameter. +list.forEach(printElement); +``` + +You can also assign a function to a variable, such as: +```dart +var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!'; +assert(loudify('hello') == '!!! HELLO !!!'); +``` + +This example uses an anonymous function. More about those in the next section. + +#### Anonymous functions +Though you name most functions, such as `main()` or `printElement()`. you can also create functions without names. These functions are called anonymous functions, lambdas, or closures. + +An anonymous function resembles a named function as it has: + +- Zero or more parameters, comma-separated +- Optional type annotations between parentheses. + +The following code block contains the function's body: +```dart +([[Type]] param1[, ...]]) { + codeBlock; +} +``` + +The following example defines an anonymous function with an untyped parameter, item. The anonymous function passes it to the map function. The map function, invoked for each item in the list, converts each string to uppercase. Then, the anonymous function passed to forEach, prints each converted string with its length. +```dart +const list = ['apples', 'bananas', 'oranges']; + +var uppercaseList = list.map((item) { + return item.toUpperCase(); +}).toList(); +// Convert to list after mapping + +for (var item in uppercaseList) { + print('$item: ${item.length}'); +} +``` + +```dart +var uppercaseList = list.map((item) => item.toUpperCase()).toList(); +uppercaseList.forEach((item) => print('$item: ${item.length}')); +``` + +#### Return values +All functions return a value. If no return value is specified, the statement return `null`; is implicitly appended to the function body. +```dart +foo() {} + +assert(foo() == null); +``` + +To return multiple values in a function, aggregate the values in a record. +```dart +(String, int) foo() { + return ('something', 42); +} +``` + +#### Generators +When you need to lazily produce a sequence of values, consider using a generator function. Dart has built-in support for two kinds of generator functions: + +- Synchronous generator: Returns an `Iterable` object. +- Asynchronous generator: Returns a `Stream` object. + +To implement a synchronous generator function, mark the function body as `sync*`, and use `yield` statements to deliver values: +```dart +Iterable naturalsTo(int n) sync* { + int k = 0; + while (k < n) yield k++; +} +``` + +To implement an asynchronous generator function, mark the function body as `async*`, and use `yield` statements to deliver values: +```dart +Stream asynchronousNaturalsTo(int n) async* { + int k = 0; + while (k < n) yield k++; +} +``` + +If your generator is recursive, you can improve its performance by using `yield*`: +```dart +Iterable naturalsDownFrom(int n) sync* { + if (n > 0) { + yield n; + yield* naturalsDownFrom(n - 1); + } +} +``` + +### Loops +#### For loops +You can iterate with the standard for loop. For example: +```dart +var message = StringBuffer('Dart is fun'); +for (var i = 0; i < 5; i++) { + message.write('!'); +} +``` + +Closures inside of Dart's for loops capture the value of the index. This avoids a common pitfall found in JavaScript. For example, consider: +```dart +var callbacks = []; +for (var i = 0; i < 2; i++) { + callbacks.add(() => print(i)); +} + +for (final c in callbacks) { + c(); +} +``` + +The output is 0 and then 1, as expected. In contrast, the example would print 2 and then 2 in JavaScript. + +Sometimes you might not need to know the current iteration counter when iterating over an Iterable type, like List or Set. In that case, use the for-in loop for cleaner code: +```dart +for (final candidate in candidates) { + candidate.interview(); +} +``` + +To process the values obtained from the iterable, you can also use a pattern in a for-in loop: +```dart +for (final Candidate(:name, :yearsExperience) in candidates) { + print('$name has $yearsExperience of experience.'); +} +``` + +Iterable classes also have a forEach() method as another option: +```dart +var collection = [1, 2, 3]; +collection.forEach(print); // 1 2 3 +``` + +#### While and do-while +A while loop evaluates the condition before the loop: +```dart +while (!isDone()) { + doSomething(); +} +``` + +A do-while loop evaluates the condition after the loop: +```dart +do { + printLine(); +} while (!atEndOfPage()); +``` + +#### Break and continue +Use `break` to stop looping: +```dart +while (true) { + if (shutDownRequested()) break; + processIncomingRequests(); +} +``` + +Use `continue` to skip to the next loop iteration: +```dart +for (int i = 0; i < candidates.length; i++) { + var candidate = candidates[i]; + if (candidate.yearsExperience < 5) { + continue; + } + candidate.interview(); +} +``` + +If you're using an Iterable such as a list or set, how you write the previous example might differ: +```dart +candidates + .where((c) => c.yearsExperience >= 5) + .forEach((c) => c.interview()); +``` + +### Branches +#### If +Dart supports if statements with optional else clauses. The condition in parentheses after if must be an expression that evaluates to a boolean: +```dart +if (isRaining()) { + you.bringRainCoat(); +} else if (isSnowing()) { + you.wearJacket(); +} else { + car.putTopDown(); +} +``` + +#### If-case +Dart if statements support case clauses followed by a pattern: +```dart +if (pair case [int x, int y]) return Point(x, y); +``` + +If the pattern matches the value, then the branch executes with any variables the pattern defines in scope. + +In the previous example, the list pattern `[int x, int y]` matches the value pair, so the branch `return Point(x, y)` executes with the variables that the pattern defined, x and y. + +Otherwise, control flow progresses to the else branch to execute, if there is one: +```dart +if (pair case [int x, int y]) { + print('Was coordinate array $x,$y'); +} else { + throw FormatException('Invalid coordinates.'); +} +``` + +The if-case statement provides a way to match and destructure against a single pattern. To test a value against multiple patterns, use `switch`. + +#### Switch statements +A switch statement evaluates a value expression against a series of cases. Each case clause is a pattern for the value to match against. You can use any kind of pattern for a case. + +When the value matches a case's pattern, the case body executes. Non-empty case clauses jump to the end of the switch after completion. They do not require a `break` statement. Other valid ways to end a non-empty case clause are a `continue`, `throw`, or `return` statement. + +Use a `default` or wildcard `_` clause to execute code when no case clause matches: +```dart +var command = 'OPEN'; +switch (command) { + case 'CLOSED': + executeClosed(); + case 'PENDING': + executePending(); + case 'APPROVED': + executeApproved(); + case 'DENIED': + executeDenied(); + case 'OPEN': + executeOpen(); + default: + executeUnknown(); +} +``` + +Empty cases fall through to the next case, allowing cases to share a body. For an empty case that does not fall through, use `break` for its body. For non-sequential fall-through, you can use a `continue` statement and a label: +```dart +switch (command) { + case 'OPEN': + executeOpen(); + continue newCase; // Continues executing at the newCase label. + + case 'DENIED': // Empty case falls through. + case 'CLOSED': + executeClosed(); // Runs for both DENIED and CLOSED, + + newCase: + case 'PENDING': + executeNowClosed(); // Runs for both OPEN and PENDING. +} +``` + +You can use logical-or patterns to allow cases to share a body or a guard. To learn more about patterns and case clauses, check out the patterns documentation on Switch statements and expressions. + +#### Switch expressions +A switch expression produces a value based on the expression body of whichever case matches. You can use a switch expression wherever Dart allows expressions, except at the start of an expression statement. For example: +```dart +var x = switch (y) { ... }; + +print(switch (x) { ... }); + +return switch (x) { ... }; +``` + +If you want to use a switch at the start of an expression statement, use a switch statement. + +Switch expressions allow you to rewrite a switch statement like this: +```dart +// Where slash, star, comma, semicolon, etc., are constant variables... +switch (charCode) { + case slash || star || plus || minus: // Logical-or pattern + token = operator(charCode); + case comma || semicolon: // Logical-or pattern + token = punctuation(charCode); + case >= digit0 && <= digit9: // Relational and logical-and patterns + token = number(); + default: + throw FormatException('Invalid'); +} +``` + +Into an expression, like this: +```dart +token = switch (charCode) { + slash || star || plus || minus => operator(charCode), + comma || semicolon => punctuation(charCode), + >= digit0 && <= digit9 => number(), + _ => throw FormatException('Invalid') +}; +``` + +The syntax of a switch expression differs from switch statement syntax: +- Cases do not start with the `case` keyword. +- A case body is a single expression instead of a series of statements. +- Each case must have a body; there is no implicit fallthrough for empty cases. +- Case patterns are separated from their bodies using `=>` instead of `:`. +- Cases are separated by `,` (and an optional trailing `,` is allowed). +- Default cases can only use `_`, instead of allowing both `default` and `_`. + +#### Exhaustiveness checking +Exhaustiveness checking is a feature that reports a compile-time error if it's possible for a value to enter a switch but not match any of the cases. +```dart +// Non-exhaustive switch on bool?, missing case to match null possibility: +switch (nullableBool) { + case true: + print('yes'); + case false: + print('no'); +} +``` + +A default case (`default` or `_`) covers all possible values that can flow through a switch. This makes a switch on any type exhaustive. + +Enums and sealed types are particularly useful for switches because, even without a default case, their possible values are known and fully enumerable. Use the sealed modifier on a class to enable exhaustiveness checking when switching over subtypes of that class: +```dart +sealed class Shape {} + +class Square implements Shape { + final double length; + Square(this.length); +} + +class Circle implements Shape { + final double radius; + Circle(this.radius); +} + +double calculateArea(Shape shape) => switch (shape) { + Square(length: var l) => l * l, + Circle(radius: var r) => math.pi * r * r + }; +``` + +If anyone were to add a new subclass of `Shape`, this switch expression would be incomplete. Exhaustiveness checking would inform you of the missing subtype. This allows you to use Dart in a somewhat functional algebraic datatype style. + +#### Guard clause +To set an optional guard clause after a case clause, use the keyword when. A guard clause can follow if case, and both switch statements and expressions. +```dart +// Switch statement: +switch (something) { + case somePattern when some || boolean || expression: + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause. + body; +} + +// Switch expression: +var value = switch (something) { + somePattern when some || boolean || expression => body, + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause. +} + +// If-case statement: +if (something case somePattern when some || boolean || expression) { + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Guard clause. + body; +} +``` + +Guards evaluate an arbitrary boolean expression after matching. This allows you to add further constraints on whether a case body should execute. When the guard clause evaluates to false, execution proceeds to the next case rather than exiting the entire switch.rrr + +### Error Handling +#### Exceptions +Your Dart code can throw and catch exceptions. Exceptions are errors indicating that something unexpected happened. If the exception isn't caught, the isolate that raised the exception is suspended, and typically the isolate and its program are terminated. + +In contrast to Java, all of Dart's exceptions are unchecked exceptions. Methods don't declare which exceptions they might throw, and you aren't required to catch any exceptions. + +Dart provides Exception and Error types, as well as numerous predefined subtypes. You can, of course, define your own exceptions. However, Dart programs can throw any non-null object—not just Exception and Error objects—as an exception. + +#### Throw +Here's an example of throwing, or raising, an exception: +```dart +throw FormatException('Expected at least 1 section'); +``` + +You can also throw arbitrary objects: +```dart +throw 'Out of llamas!'; +``` + +> **Note**: Production-quality code usually throws types that implement Error or Exception. + +Because throwing an exception is an expression, you can throw exceptions in `=>` statements, as well as anywhere else that allows expressions: +```dart +void distanceTo(Point other) => throw UnimplementedError(); +``` + +#### Catch +Catching, or capturing, an exception stops the exception from propagating (unless you rethrow the exception). Catching an exception gives you a chance to handle it: +```dart +try { + breedMoreLlamas(); +} on OutOfLlamasException { + buyMoreLlamas(); +} +``` + +To handle code that can throw more than one type of exception, you can specify multiple catch clauses. The first catch clause that matches the thrown object's type handles the exception. If the catch clause does not specify a type, that clause can handle any type of thrown object: +```dart +try { + breedMoreLlamas(); +} on OutOfLlamasException { + // A specific exception + buyMoreLlamas(); +} on Exception catch (e) { + // Anything else that is an exception + print('Unknown exception: $e'); +} catch (e) { + // No specified type, handles all + print('Something really unknown: $e'); +} +``` + +As the preceding code shows, you can use either on or catch or both. Use on when you need to specify the exception type. Use catch when your exception handler needs the exception object. + +You can specify one or two parameters to `catch()`. The first is the exception that was thrown, and the second is the stack trace (a StackTrace object). +```dart +try { + // ··· +} on Exception catch (e) { + print('Exception details:\n $e'); +} catch (e, s) { + print('Exception details:\n $e'); + print('Stack trace:\n $s'); +} +``` + +To partially handle an exception, while allowing it to propagate, use the rethrow keyword. +```dart +void misbehave() { + try { + dynamic foo = true; + print(foo++); // Runtime error + } catch (e) { + print('misbehave() partially handled ${e.runtimeType}.'); + rethrow; // Allow callers to see the exception. + } +} + +void main() { + try { + misbehave(); + } catch (e) { + print('main() finished handling ${e.runtimeType}.'); + } +} +``` + +#### Finally +To ensure that some code runs whether or not an exception is thrown, use a finally clause. If no catch clause matches the exception, the exception is propagated after the finally clause runs: +```dart +try { + breedMoreLlamas(); +} finally { + // Always clean up, even if an exception is thrown. + cleanLlamaStalls(); +} + +The finally clause runs after any matching catch clauses: + +try { + breedMoreLlamas(); +} catch (e) { + print('Error: $e'); // Handle the exception first. +} finally { + cleanLlamaStalls(); // Then clean up. +} +``` + +#### Assert +During development, use an assert statement— `assert(, );` —to disrupt normal execution if a boolean condition is false. +```dart +// Make sure the variable has a non-null value. +assert(text != null); + +// Make sure the value is less than 100. +assert(number < 100); + +// Make sure this is an https URL. +assert(urlString.startsWith('https')); + +To attach a message to an assertion, add a string as the second argument to assert (optionally with a trailing comma): + +assert(urlString.startsWith('https'), + 'URL ($urlString) should start with "https".'); +``` + +The first argument to assert can be any expression that resolves to a boolean value. If the expression's value is true, the assertion succeeds and execution continues. If it's false, the assertion fails and an exception (an AssertionError) is thrown. + +When exactly do assertions work? That depends on the tools and framework you're using: +- Flutter enables assertions in debug mode. +- Development-only tools such as webdev serve typically enable assertions by default. +- Some tools, such as dart run and dart compile js support assertions through a command-line flag: `--enable-asserts`. + +> In production code, assertions are ignored, and the arguments to assert aren't evaluated. + +### Classes +-> https://dart.dev/language/classes + + +Dart is an object-oriented language with classes and mixin-based inheritance. Every object is an instance of a class, and all classes except `Null` descend from `Object`. Mixin-based inheritance means that although every class (except for the top class, `Object?`) has exactly one superclass, a class body can be reused in multiple class hierarchies. Extension methods are a way to add functionality to a class without changing the class or creating a subclass. Class modifiers allow you to control how libraries can subtype a class. + +#### Using class member +Objects have members consisting of functions and data (methods and instance variables, respectively). When you call a method, you invoke it on an object: the method has access to that object's functions and data. + +Use a dot (`.`) to refer to an instance variable or method: +```dart +var p = Point(2, 2); + +// Get the value of y. +assert(p.y == 2); + +// Invoke distanceTo() on p. +double distance = p.distanceTo(Point(4, 4)); +``` + +Use `?.` instead of `.` to avoid an exception when the leftmost operand is null: +```dart +// If p is non-null, set a variable equal to its y value. +var a = p?.y; +``` + +#### Using constructors +You can create an object using a constructor. Constructor names can be either `ClassName` or `ClassName.identifier`. For example, the following code creates Point objects using the `Point()` and `Point.fromJson()` constructors: +```dart +var p1 = Point(2, 2); +var p2 = Point.fromJson({'x': 1, 'y': 2}); +``` + +The following code has the same effect, but uses the optional new keyword before the constructor name: +```dart +var p1 = new Point(2, 2); +var p2 = new Point.fromJson({'x': 1, 'y': 2}); +``` + +Some classes provide constant constructors. To create a compile-time constant using a constant constructor, put the `const` keyword before the constructor name: +```dart +var p = const ImmutablePoint(2, 2); +``` + +Constructing two identical compile-time constants results in a single, canonical instance: +```dart +var a = const ImmutablePoint(1, 1); +var b = const ImmutablePoint(1, 1); + +assert(identical(a, b)); // They are the same instance! +``` + +Within a constant context, you can omit the `const` before a constructor or literal. For example, look at this code, which creates a `const` map: +```dart +// Lots of const keywords here. +const pointAndLine = const { + 'point': const [const ImmutablePoint(0, 0)], + 'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)], +}; +``` + +You can omit all but the first use of the `const` keyword: +```dart +// Only one const, which establishes the constant context. +const pointAndLine = { + 'point': [ImmutablePoint(0, 0)], + 'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)], +}; +``` + +If a constant constructor is outside of a constant context and is invoked without `const`, it creates a non-constant object: +```dart +var a = const ImmutablePoint(1, 1); // Creates a constant +var b = ImmutablePoint(1, 1); // Does NOT create a constant + +assert(!identical(a, b)); // NOT the same instance! +``` + +#### Getting an object's type +To get an object's type at runtime, you can use the Object property `runtimeType`, which returns a `Type` object. +```dart +print('The type of a is ${a.runtimeType}'); +``` + +> **Warning**: Use a type test operator rather than `runtimeType` to test an object's type. In production environments, the test `object is Type` is more stable than the test `object.runtimeType == Type`. + +#### Instance variables +Here's how you declare instance variables: +```dart +class Point { + double? x; // Declare instance variable x, initially null. + double? y; // Declare y, initially null. + double z = 0; // Declare z, initially 0. +} +``` + +An uninitialized instance variable declared with a nullable type has the value `null`. Non-nullable instance variables must be initialized at declaration. + +All instance variables generate an implicit getter method. Non-final instance variables and late final instance variables without initializers also generate an implicit setter method. +```dart +class Point { + double? x; // Declare instance variable x, initially null. + double? y; // Declare y, initially null. +} + +void main() { + var point = Point(); + point.x = 4; // Use the setter method for x. + assert(point.x == 4); // Use the getter method for x. + assert(point.y == null); // Values default to null. +} +``` + +Initializing a non-late instance variable where it's declared sets the value when the instance is created, before the constructor and its initializer list execute. As a result, the initializing expression (after the `=`) of a non-late instance variable can't access this. +```dart +double initialX = 1.5; + +class Point { + // OK, can access declarations that do not depend on `this`: + double? x = initialX; + + // ERROR, can't access `this` in non-`late` initializer: + double? y = this.x; + + // OK, can access `this` in `late` initializer: + late double? z = this.x; + + // OK, `this.x` and `this.y` are parameter declarations, not expressions: + Point(this.x, this.y); +} +``` + +Instance variables can be `final`, in which case they must be set exactly once. Initialize final, non-late instance variables at declaration, using a constructor parameter, or using a constructor's initializer list: +```dart +class ProfileMark { + final String name; + final DateTime start = DateTime.now(); + + ProfileMark(this.name); + ProfileMark.unnamed() : name = ''; +} +``` + +If you need to assign the value of a `final` instance variable after the constructor body starts, you can use one of the following: + +- Use a factory constructor. +- Use `late final`, but be careful: a `late final` without an initializer adds a setter to the API. + +#### Implicit interfaces +Every class implicitly defines an interface containing all the instance members of the class and of any interfaces it implements. If you want to create a class A that supports class B's API without inheriting B's implementation, class A should implement the B interface. + +A class implements one or more interfaces by declaring them in an implements clause and then providing the APIs required by the interfaces. For example: +```dart +// A person. The implicit interface contains greet(). +class Person { + // In the interface, but visible only in this library. + final String _name; + + // Not in the interface, since this is a constructor. + Person(this._name); + + // In the interface. + String greet(String who) => 'Hello, $who. I am $_name.'; +} + +// An implementation of the Person interface. +class Impostor implements Person { + String get _name => ''; + + String greet(String who) => 'Hi $who. Do you know who I am?'; +} + +String greetBob(Person person) => person.greet('Bob'); + +void main() { + print(greetBob(Person('Kathy'))); + print(greetBob(Impostor())); +} +``` + +Here's an example of specifying that a class implements multiple interfaces: +```dart +class Point implements Comparable, Location {...} +``` + +#### Class variables and methods +##### Static variables +Static variables (class variables) are useful for class-wide state and constants: +Use the `static` keyword to implement class-wide variables and methods. +```dart +class Queue { + static const initialCapacity = 16; + // ··· +} + +void main() { + assert(Queue.initialCapacity == 16); +} +``` + +Static variables aren't initialized until they're used. + +##### Static methods +Static methods (class methods) don't operate on an instance, and thus don't have access to `this`. They do, however, have access to static variables. As the following example shows, you invoke static methods directly on a class: +```dart +import 'dart:math'; + +class Point { + double x, y; + Point(this.x, this.y); + + static double distanceBetween(Point a, Point b) { + var dx = a.x - b.x; + var dy = a.y - b.y; + return sqrt(dx * dx + dy * dy); + } +} + +void main() { + var a = Point(2, 2); + var b = Point(4, 4); + var distance = Point.distanceBetween(a, b); + assert(2.8 < distance && distance < 2.9); + print(distance); +} +``` + +> **Note**: Consider using top-level functions, instead of static methods, for common or widely used utilities and functionality. + +#### Constructors +Constructors are special functions that create instances of classes. + +Dart implements many types of constructors. Except for default constructors, these functions use the same name as their class. + +- **Generative constructors**: Creates new instances and initializes instance variables. +- **Default constructors**: Used to create a new instance when a constructor hasn't been specified. It doesn't take arguments and isn't named. +- **Named constructors**: Clarifies the purpose of a constructor or allows the creation of multiple constructors for the same class. +- **Constant constructors**: Creates instances as compile-type constants. +- **Factory constructors**: Either creates a new instance of a subtype or returns an existing instance from cache. +- **Redirecting constructor**: Forwards calls to another constructor in the same class. + + +##### Generative constructors +To instantiate a class, use a generative constructor. +```dart +class Point { + // Initializer list of variables and values + double x = 2.0; + double y = 2.0; + + // Generative constructor with initializing formal parameters: + Point(this.x, this.y); +} +``` + +##### Default constructors +If you don't declare a constructor, Dart uses the default constructor. The default constructor is a generative constructor without arguments or name. + +##### Named constructors +Use a named constructor to implement multiple constructors for a class or to provide extra clarity: +```dart +const double xOrigin = 0; +const double yOrigin = 0; + +class Point { + final double x; + final double y; + + // Sets the x and y instance variables + // before the constructor body runs. + Point(this.x, this.y); + + // Named constructor + Point.origin() + : x = xOrigin, + y = yOrigin; +} +``` + +A subclass doesn't inherit a superclass's named constructor. To create a subclass with a named constructor defined in the superclass, implement that constructor in the subclass. + +##### Constant constructors +If your class produces unchanging objects, make these objects compile-time constants. To make objects compile-time constants, define a `const` constructor with all instance variables set as `final`. +```dart +class ImmutablePoint { + static const ImmutablePoint origin = ImmutablePoint(0, 0); + + final double x, y; + + const ImmutablePoint(this.x, this.y); +} +``` + +Constant constructors don't always create constants. They might be invoked in a non-const context. + +##### Redirecting constructors +A constructor might redirect to another constructor in the same class. A redirecting constructor has an empty body. The constructor uses this instead of the class name after a colon (`:`). +```dart +class Point { + double x, y; + + // The main constructor for this class. + Point(this.x, this.y); + + // Delegates to the main constructor. + Point.alongXAxis(double x) : this(x, 0); +} +``` + +##### Factory constructors +When encountering one of following two cases of implementing a constructor, use the `factory` keyword: + +The constructor doesn't always create a new instance of its class. Although a factory constructor cannot return `null`, it might return: +- an existing instance from a cache instead of creating a new one +- a new instance of a subtype + +You need to perform non-trivial work prior to constructing an instance. This could include checking arguments or doing any other processing that cannot be handled in the initializer list. + +> **Tip**: You can also handle late initialization of a `final` variable with `late final` (carefully!). + +The following example includes two factory constructors. +- Logger factory constructor returns objects from a cache. +- Logger.fromJson factory constructor initializes a final variable from a JSON object. +```dart +class Logger { + final String name; + bool mute = false; + + // _cache is library-private, thanks to + // the _ in front of its name. + static final Map _cache = {}; + + factory Logger(String name) { + return _cache.putIfAbsent(name, () => Logger._internal(name)); + } + + factory Logger.fromJson(Map json) { + return Logger(json['name'].toString()); + } + + Logger._internal(this.name); + + void log(String msg) { + if (!mute) print(msg); + } +} +``` + +> **Warning**: Factory constructors can't access `this`. + +Use a factory constructor as any other constructor: +```dart +var logger = Logger('UI'); +logger.log('Button clicked'); + +var logMap = {'name': 'UI'}; +var loggerJson = Logger.fromJson(logMap); +``` + +##### Instance Variable Initialization +Dart can initialize variables in three ways. + +Initialize the instance variables when you declare the variables. +```dart +class PointA { + double x = 1.0; + double y = 2.0; + + // The implicit default constructor sets these variables to (1.0,2.0) + // PointA(); + + @override + String toString() { + return 'PointA($x,$y)'; + } +} +``` + +To simplify the common pattern of assigning a constructor argument to an instance variable, Dart has initializing formal parameters. + +In the constructor declaration, include `this.` and omit the body. The `this` keyword refers to the current instance. + +When the name conflict exists, use `this`. Otherwise, Dart style omits the `this`. An exception exists for the generative constructor where you must prefix the initializing formal parameter name with `this`. + +As noted earlier in this guide, certain constructors and certain parts of constructors can't access `this`. These include: +- Factory constructors +- The right-hand side of an initializer list +- Arguments to a superclass constructor + +Initializing formal parameters also allow you to initialize non-nullable or final instance variables. Both of these types of variables require initialization or a default value. +```dart +class PointB { + final double x; + final double y; + + // Sets the x and y instance variables + // before the constructor body runs. + PointB(this.x, this.y); + + // Initializing formal parameters can also be optional. + PointB.optional([this.x = 0.0, this.y = 0.0]); +} + +Private fields can't be used as named initializing formals. + +class PointB { +// ... + + PointB.namedPrivate({required double x, required double y}) + : _x = x, + _y = y; + +// ... +} +``` + +This also works with named variables. +```dart +class PointC { + double x; // must be set in constructor + double y; // must be set in constructor + + // Generative constructor with initializing formal parameters + // with default values + PointC.named({this.x = 1.0, this.y = 1.0}); + + @override + String toString() { + return 'PointC.named($x,$y)'; + } +} + +// Constructor using named variables. +final pointC = PointC.named(x: 2.0, y: 2.0); +``` + +#### Instance methods +Methods are functions that provide behavior for an object. + +Instance methods on objects can access instance variables and `this`. The `distanceTo()` method in the following sample is an example of an instance method: +```dart +import 'dart:math'; + +class Point { + final double x; + final double y; + + // Sets the x and y instance variables + // before the constructor body runs. + Point(this.x, this.y); + + double distanceTo(Point other) { + var dx = x - other.x; + var dy = y - other.y; + return sqrt(dx * dx + dy * dy); + } +} +``` + +#### Operators +Most operators are instance methods with special names. Dart allows you to define operators with the following names: +`<` `>` `<=` `>=` `==` `~` +`-` `+` `/` `~/` `*` `%` +`|` `ˆ` `&` `<<` `>>>` `>>` +`[]=` `[]` + +> **Note**: You may have noticed that some operators, like `!=`, aren't in the list of names. These operators aren't instance methods. Their behavior is built in to Dart. + +To declare an operator, use the built-in identifier `operator` then the operator you are defining. The following example defines vector addition (`+`), subtraction (`-`), and equality (`==`): +```dart +class Vector { + final int x, y; + + Vector(this.x, this.y); + + Vector operator +(Vector v) => Vector(x + v.x, y + v.y); + Vector operator -(Vector v) => Vector(x - v.x, y - v.y); + + @override + bool operator ==(Object other) => + other is Vector && x == other.x && y == other.y; + + @override + int get hashCode => Object.hash(x, y); +} + +void main() { + final v = Vector(2, 3); + final w = Vector(2, 2); + + assert(v + w == Vector(4, 5)); + assert(v - w == Vector(0, 1)); +} +``` + +#### Getters and setters +Getters and setters are special methods that provide read and write access to an object's properties. Recall that each instance variable has an implicit getter, plus a setter if appropriate. You can create additional properties by implementing getters and setters, using the `get` and `set` keywords: +```dart +class Rectangle { + double left, top, width, height; + + Rectangle(this.left, this.top, this.width, this.height); + + // Define two calculated properties: right and bottom. + double get right => left + width; + set right(double value) => left = value - width; + double get bottom => top + height; + set bottom(double value) => top = value - height; +} + +void main() { + var rect = Rectangle(3, 4, 20, 15); + assert(rect.left == 3); + rect.right = 12; + assert(rect.left == -8); +} +``` + +With getters and setters, you can start with instance variables, later wrapping them with methods, all without changing client code. + +#### Abstract methods +Instance, getter, and setter methods can be abstract, defining an interface but leaving its implementation up to other classes. Abstract methods can only exist in abstract classes or mixins. + +To make a method abstract, use a semicolon (`;`) instead of a method body: +```dart +abstract class Doer { + // Define instance variables and methods... + + void doSomething(); // Define an abstract method. +} + +class EffectiveDoer extends Doer { + void doSomething() { + // Provide an implementation, so the method is not abstract here... + } +} +``` + +Use extends to create a subclass, and super to refer to the superclass: +```dart +class Television { + void turnOn() { + _illuminateDisplay(); + _activateIrSensor(); + } + // ··· +} + +class SmartTelevision extends Television { + void turnOn() { + super.turnOn(); + _bootNetworkInterface(); + _initializeMemory(); + _upgradeApps(); + } + // ··· +} +``` + +#### Overriding members +Subclasses can override instance methods (including operators), getters, and setters. You can use the `@override` annotation to indicate that you are intentionally overriding a member: +```dart +class Television { + // ··· + set contrast(int value) {...} +} + +class SmartTelevision extends Television { + @override + set contrast(num value) {...} + // ··· +} +``` + +An overriding method declaration must match the method (or methods) that it overrides in several ways: +- The return type must be the same type as (or a subtype of) the overridden method's return type. +- Parameter types must be the same type as (or a supertype of) the overridden method's parameter types. In the preceding example, the contrast setter of SmartTelevision changes the parameter type from int to a supertype, num. +- If the overridden method accepts n positional parameters, then the overriding method must also accept n positional parameters. +- A generic method can't override a non-generic one, and a non-generic method can't override a generic one. + +#### Mixins +Mixins are a way of defining code that can be reused in multiple class hierarchies. They are intended to provide member implementations en masse. + +To use a mixin, use the `with` keyword followed by one or more mixin names. The following example shows two classes that use (or, are subclasses of) mixins: +```dart +class Musician extends Performer with Musical { + // ··· +} + +class Maestro extends Person with Musical, Aggressive, Demented { + Maestro(String maestroName) { + name = maestroName; + canConduct = true; + } +} +``` + +To define a mixin, use the `mixin` declaration. In the rare case where you need to define both a mixin and a class, you can use the `mixin class` declaration. + +Mixins and mixin classes cannot have an extends clause, and must not declare any generative constructors. + +For example: +```dart +mixin Musical { + bool canPlayPiano = false; + bool canCompose = false; + bool canConduct = false; + + void entertainMe() { + if (canPlayPiano) { + print('Playing piano'); + } else if (canConduct) { + print('Waving hands'); + } else { + print('Humming to self'); + } + } +} +``` + +##### Specify members a mixin can call on itself +Sometimes a mixin depends on being able to invoke a method or access fields, but can't define those members itself (because mixins can't use constructor parameters to instantiate their own fields). + +Declaring an abstract method in a mixin forces any type that uses the mixin to define the abstract method upon which its behavior depends. +```dart +mixin Musician { + void playInstrument(String instrumentName); // Abstract method. + + void playPiano() { + playInstrument('Piano'); + } + void playFlute() { + playInstrument('Flute'); + } +} + +class Virtuoso with Musician { + void playInstrument(String instrumentName) { // Subclass must define. + print('Plays the $instrumentName beautifully'); + } +} +``` + +##### Access state in the mixin's subclass +Declaring abstract memebers also allows you to access state on the subclass of a mixin, by calling getters which are defined as abstract on the mixin: +```dart +/// Can be applied to any type with a [name] property and provides an +/// implementation of [hashCode] and operator `==` in terms of it. +mixin NameIdentity { + String get name; + + int get hashCode => name.hashCode; + bool operator ==(other) => other is NameIdentity && name == other.name; +} + +class Person with NameIdentity { + final String name; + + Person(this.name); +} +``` + +##### Implement an interface +Similar to declaring the mixin abstract, putting an implements clause on the mixin while not actually implementing the interface will also ensure any member dependencies are defined for the mixin. +```dart +abstract interface class Tuner { + void tuneInstrument(); +} + +mixin Guitarist implements Tuner { + void playSong() { + tuneInstrument(); + + print('Strums guitar majestically.'); + } +} + +class PunkRocker with Guitarist { + void tuneInstrument() { + print("Don't bother, being out of tune is punk rock."); + } +} +``` + +Use the `on` clause to declare a superclass + +The `on` clause exists to define the type that super calls are resolved against. So, you should only use it if you need to have a super call inside a mixin. + +The `on` clause forces any class that uses a mixin to also be a subclass of the type in the on clause. If the mixin depends on members in the superclass, this ensures those members are available where the mixin is used: +```dart +class Musician { + musicianMethod() { + print('Playing music!'); + } +} + +mixin MusicalPerformer on Musician { + perfomerMethod() { + print('Performing music!'); + super.musicianMethod(); + } +} + +class SingerDancer extends Musician with MusicalPerformer { } + +main() { + SingerDance().performerMethod(); +} +``` + +In this example, only classes that extend or implement the Musician class can use the mixin MusicalPerformer. Because SingerDancer extends Musician, SingerDancer can mix in MusicalPerformer. + +### Enum +All enums automatically extend the `Enum` class. They are also sealed, meaning they cannot be subclassed, implemented, mixed in, or otherwise explicitly instantiated. + +Abstract classes and mixins can explicitly implement or extend Enum, but unless they are then implemented by or mixed into an enum declaration, no objects can actually implement the type of that class or mixin. + +To declare a simple enumerated type, use the enum keyword and list the values you want to be enumerated: +```dart +enum Color { red, green, blue } +``` + +Dart also allows enum declarations to declare classes with fields, methods, and const constructors which are limited to a fixed number of known constant instances. + +To declare an enhanced enum, follow a syntax similar to normal classes, but with a few extra requirements: + +- Instance variables must be `final`, including those added by mixins. +- All generative constructors must be constant. +- Factory constructors can only return one of the fixed, known enum instances. +- No other class can be extended as Enum is automatically extended. +- There cannot be overrides for index, hashCode, the equality operator ==. +- A member named values cannot be declared in an enum, as it would conflict with the automatically generated static values getter. +- All instances of the enum must be declared in the beginning of the declaration, and there must be at least one instance declared. + +Instance methods in an enhanced enum can use `this` to reference the current enum value. + +Here is an example that declares an enhanced enum with multiple instances, instance variables, getters, and an implemented interface: +```dart +enum Vehicle implements Comparable { + car(tires: 4, passengers: 5, carbonPerKilometer: 400), + bus(tires: 6, passengers: 50, carbonPerKilometer: 800), + bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0); + + const Vehicle({ + required this.tires, + required this.passengers, + required this.carbonPerKilometer, + }); + + final int tires; + final int passengers; + final int carbonPerKilometer; + + int get carbonFootprint => (carbonPerKilometer / passengers).round(); + + bool get isTwoWheeled => this == Vehicle.bicycle; + + @override + int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint; +} +``` + +#### Using enums +Access the enumerated values like any other static variable: +```dart +final favoriteColor = Color.blue; +if (favoriteColor == Color.blue) { + print('Your favorite color is blue!'); +} +``` + +Each value in an enum has an index getter, which returns the zero-based position of the value in the enum declaration. For example, the first value has index 0, and the second value has index 1. +```dart +assert(Color.red.index == 0); +assert(Color.green.index == 1); +assert(Color.blue.index == 2); +``` + +To get a list of all the enumerated values, use the enum's values constant. +```dart +List colors = Color.values; +assert(colors[2] == Color.blue); +``` + +You can use enums in switch statements, and you'll get a warning if you don't handle all of the enum's values: +```dart +var aColor = Color.blue; + +switch (aColor) { + case Color.red: + print('Red as roses!'); + case Color.green: + print('Green as grass!'); + default: // Without this, you see a WARNING. + print(aColor); // 'Color.blue' +} +``` + +If you need to access the name of an enumerated value, such as 'blue' from `Color.blue`, use the .name property: +```dart +print(Color.blue.name); // 'blue' +``` + +You can access a member of an enum value like you would on a normal object: +```dart +print(Vehicle.car.carbonFootprint); +```