dart-lang / dart-lang/language

What guarantees do we have around the runtimeType of primitive types?

Open
#2,895 41 comments 0 reactions 0 assignees View on GitHub
question
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

The co19 tests contain a [test for the runtime type semantics](https://github.com/dart-lang/co19/blob/master/LanguageFeatures/Records/runtime_type_A01_t01.dart) of records that looks like (simplified):

```dart
Type typeOf() => X;

main() {
(num, Object) r = (1, 2.3);
Expect.equals(typeOf<(int, double)>(), r.runtimeType);
}
```

This test implicitly relies on an assumption that `int` and `double` are effectively final types. By that, I mean that the runtime type of any int or double literal (or, I guess, at least `1` and `2.3`) will be `int` and `double` *exactly* and not some subtype of them (like `JSInt`, `_Smi`, etc.).

The test could alternately be written like:

```dart
Type typeOf() => X;

class A {}
class B {}

main() {
(Object, Object) r = (A(), B());
Expect.equals(typeOf<(A, B)>(), r.runtimeType);
}
```

It would still be testing the same functionality of record runtime types, but wouldn't rely on any policy of the built-in core library types. I believe we'll suggest that the test should be changed to that just to minimize the scope of what the test presumes.

However, that does still raise the question of what policy we allow users to rely on for the built-in core library types. Is it the case that all calls to `.runtimeType` on instances of `int` will return the same (equal? identical?) `Type` object? Likewise for the other built-in types?

It's obviously *not* the case for many other core types. For example:

```dart
var whereIterable = [1, 2, 3].where((n) => true);
var mapIterable = [1, 2, 3].map((n) => n);

(Iterable, Iterable) whereMap = (whereIterable, mapIterable);
(Iterable, Iterable) mapWhere = (mapIterable, whereIterable);

print(whereMap.runtimeType == mapWhere.runtimeType);
```

Here, the core libraries make absolutely no guarantee that this will print "true". And, in practice, it prints "false".

For the built-in primitive types, our implementations *do* in practice have subtypes of the declared core library type, sometimes multiple. But they try to obscure that fact and make them appear to have runtime types like `int`. It does sort of leak out sometimes in error messages. So it seems like we *try* to offer this policy.

But from talking to @rakudrama and @fishythefish, there is a code size and performance cost to fully guaranteeing that you can rely on every instance of `int` having the same runtime type.

Do we guarantee this? Should we? How much cost are we willing to push onto the implementers to do so?

Contributor guide

Open the contributing guide

Research direction

Start with the co19 test in LanguageFeatures/Records/runtime_type_A01_t01.dart and read the issue discussion about primitive runtime types. Determine whether the language specification should state a guarantee and whether the record test should use user-defined classes; done means the policy and any required test changes are clearly agreed.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.