dart-lang / dart-lang/language

String canonicalization

Open
#985 14 comments 5 reactions 0 assignees View on GitHub
enhanced-const question specification technical-debt
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

The degree to which canonicalization occurs in Dart, in particular for strings, has always been somewhat unclear.

We have explicit rules requiring that the following forms of constant expressions must be evaluated to the same (canonical) object when evaluating any of the occurrences of such an expression:

- Symbol literals (such as `#foo` or `#+`) are canonicalized.
- List, set, and map literals with the same elements/keys/values are canonicalized.
- The value of a `` (such as `const C(2)`) is canonicalized.

The definition of `identical()` ensures that instances of `bool`, `int`, and `double` are canonicalized, in the sense that they are considered identical when they represent the same value (and it is not observable whether this happens because the representation is a tagged bit string, or because `identical` treats distinct boxed representations in a special way).

Strings have traditionally been treated differently:

```dart
void main() {
var s1 = "ab";
var s2 = "a" "b"; // or `"a" + "b"`.
print(identical(s1, s2)); // 'false' with dart, 'true' with dart2js.
}
```

The specification of `identical` actually [requires](https://github.com/dart-lang/language/blob/5e31f64da811f568e81b9791db1995cecc2e5c64/specification/dartLangSpec.tex#L6200) that `identical(c1, c2)` must evaluate to true when

> `c1` and `c2` are constant strings and `c1 == c2`

which implies that the behavior of `dart` is wrong, and `dart2js` is correct: `"ab"` is a constant expression of type `String`, `"a" "b"` is a constant expression of type `String`, and the two strings are equal according to `operator ==`. (We haven't specified the behavior of `operator ==` on strings, but we hardly want to make those two strings unequal).

I believe that all non-string objects are canonicalized or not in a way which is well-defined: It is specified for the basic forms mentioned above that _every_ constant expression of these forms has a canonicalized value, and constant expressions do not allow for creating composite objects from existing objects, canonicalized or not, other than constant collection literals (e.g., we can't have `const C(x)`). In particular, we do not have to specify any additional rules saying that the value of a constant variable is canonicalized.

It is unfortunate that different tools behave differently, but it is also likely to be a serious breaking change to change the behavior of any of these tools. So do we wish to proceed and change the specification to make `identical()` implementation dependent on strings, or do we wish to choose a specific behavior and get that implemented?

@munificent, @lrhn, @leafpetersen, WDYT?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.