mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 05:36:49 +00:00
3e0ca136b6
Smaller clean-ups. CoreLibraryReviewExempt: Documentation only. Change-Id: Idfe543f18927043ae8ec73e81dc7d9d333bb88df Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/294542 Reviewed-by: Erik Ernst <eernst@google.com> Commit-Queue: Lasse Nielsen <lrn@google.com>
144 lines
6.3 KiB
Dart
144 lines
6.3 KiB
Dart
// 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();
|
|
}
|