-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
record.dart
143 lines (138 loc) · 6.33 KB
/
record.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.core;
/// A record value.
///
/// The `Record` class is a supertype of all *record types*,
/// but is not itself the runtime type of any object instances
/// _(it's an abstract class)_.
/// All objects that implement `Record` has a record type as their runtime type.
///
/// A record value, described by a record type, consists of a number of fields,
/// which are each either positional or named.
///
/// Record values and record types are written similarly to
/// argument lists and simplified function type parameter lists (no `required`
/// modifier allowed, or needed, since record fields are never optional).
/// Example:
/// ```dart
/// (int, String, {bool isValid}) triple = (1, "one", isValid: true);
/// ```
/// is syntactically similar to
/// ```dart
/// typedef F = void Function(int, String, {bool isValid});
/// void callIt(F f) => f(1, "one", isValid: true);
/// ```
///
/// Every record and record type has a *shape*,
/// given by the number of positional fields and the names of named fields.
/// For example:
/// ```dart continued
/// (double value, String name, {String isValid}) another = (
/// 3.14, "Pi", isValid: "real");
/// ```
/// is another record declaration with the same *shape* (two positional fields,
/// one named field named `isValid`), but with a different type.
/// The names written on the positional fields are entirely for documentation
/// purposes, they have no effect on the program _(same as names on positional
/// parameters in function types, like `typedef F = int Function(int value);`,
/// where the identifier `value` has no effect)_.
///
/// Record values are mainly destructured using patterns, like:
/// ```dart continued
/// switch (triple) {
/// case (int value, String name, isValid: bool ok): // ....
/// }
/// ```
/// The individual fields can also be accessed using named getters,
/// using `$1`, `$2`, etc. for positional fields, and the names themselves
/// for named fields.
/// ```dart continued
/// int value = triple.$1;
/// String name = triple.$2;
/// bool ok = triple.isValid;
/// ```
/// Because of that, some identifiers cannot be used as names of named fields:
/// * The names of `Object` members: `hashCode`, `runtimeType`, `toString` and
/// `noSuchMethod`.
/// * The name of a positional getter in the same record, so `(0, $1: 0)` is
/// invalid, but `(0, $2: 0)` is valid, since there is no positional field
/// with getter `$2` in *that* record shape. _(It'll still be confusing,
/// and should be avoided in practice.)_
/// * Also, no name starting with an underscore, `_`, is allowed. Field names
/// cannot be library private.
///
/// The run-time type of a record object is a record type, and as such, a
/// subtype of [Record], and transitively of [Object] and its supertypes.
///
/// Record values do not have a persistent [identical] behavior.
/// A reference to a record object can change *at any time* to a reference
/// to another record object with the same shape and field values.
///
/// Other than that, a record type can only be a subtype of another record
/// type with the same shape, and only if the former record type's field types
/// are subtypes of the other record type's corresponding field types.
/// That is, `(int, String, {bool isValid})` is a subtype of
/// `(num, String, {Object isValid})`, because they have the same shape,
/// and the field types are pointwise subtypes.
/// Record types with different shapes are unrelated to each other.
abstract final class Record {
/// A `Type` object representing the runtime type of a record.
///
/// The runtime type of a record is defined by the record's *shape*,
/// the number of positional fields and names of named fields,
/// and the runtime type of each of those fields.
/// (The runtime type of the record does not depend on
/// the `runtimeType` getter of its fields' values,
/// which may have overridden [Object.runtimeType].)
///
/// The `Type` object of a record type is only equal to another `Type` object
/// for a record type, and only if the other record type has the same shape,
/// and if the corresponding fields have the same types.
Type get runtimeType;
/// A hash-code compatible with `==`.
///
/// Since [operator==] is defined in terms of the `==` operators of
/// the record's field values, the hash code is also computed based on the
/// [Object.hashCode] of the field values.
///
/// There is no guaranteed order in which the `hashCode` of field values
/// is accessed.
/// It's unspecified how those values are combined,
/// other than it being consistent throughout a single program execution.
int get hashCode;
/// Checks whether [other] has the same shape and equal fields to this record.
///
/// A record is only equal to another record with the same *shape*,
/// and then only when the value of every field is equal,
/// occording to its `==`, to the corresponding field value of [other].
///
/// There is no guaranteed order in which field value equality is checked,
/// and it's unspecified whether further fields are checked after finding
/// corresponding fields which are not equal.
/// It's not even guaranteed that the order is consistent within a single
/// program execution.
///
/// As usual, be very careful around objects which break the equality
/// contract, like [double.nan] which is not equal to itself.
/// For example
/// ```dart
/// var pair = ("a", double.nan);
/// if (pair != pair) print("Oops");
/// ```
/// will print the "Oops", because `pair == pair` is defined to be equal to
/// `"a" == "a" & double.nan == double.nan`, which is false.
bool operator ==(Object other);
/// Creates a string-representation of the record.
///
/// The string representation is only intended for debugging,
/// and may differ between development and production.
/// There is no guaranteed format in production mode.
///
/// In development mode, the string will strive to be a parenthesized
/// comma separated list of field representations, where the field
/// representation is the `toString` of the value for positional fields,
/// and `someName:` followed by that for a named field named `someName`.
String toString();
}