dart-lang / dart-lang/language

Type decomposition

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

Description

It can be useful to test _whether_ a type satisfies certain constraints, and when more than one type satisfies them: _how_ this particular type satisfied them. Here are a couple of examples:

In response to #40 about adding functionality to existing types, scoped static extension methods were proposed in #41. They call for a mechanism that will enable the specification of certain constraints on types as well as the ability to declare type variables that are bound to specific types as a result of the procedure whereby it is verified that the constraints are satisfied. The basic idea is that an extension is _applicable_ to a given expression if the static type of that expression matches the extension, and the matching procedure can make such things as the type arguments of a class available for the extension methods. The specification of static extension methods is still under construction, but here's an example illustrating the idea:

```dart
// Example from scoped static extension method proposal.
extension ListFancy on List {
List copyReversed() => List(this.length)..setAll(0, this.reversed);
}
```
In this example, the extension method mechanism could be specified such that the type variable `T` is bound to the value of the actual type argument to the dynamic type of the list denoted by `this`, which enables the creation of a list with the same type argument in the body of `copyReversed`. Alternatively, the mechanism could be specified such that `T` is the static type of the expression which is the receiver of the invocation of `copyReversed`.

The language team has previously discussed mechanisms for performing an 'existential open' operation (coming up, e.g., in https://github.com/dart-lang/sdk/issues/31953#issuecomment-364954189 and https://github.com/dart-lang/sdk/issues/33841#issuecomment-405109060), in which the ability to introduce new type variables and bind them to values obtained by inspecting the dynamic type of a given instance is the main purpose of the mechanism. Here is an example of how that mechanism could be used:

```dart
main() {
List xs = ...; // Some non-trivial computation, such that the exact type is not known.
if (xs is List) {
// Here, `X` denotes the exact type argument of the
// dynamic type of `xs` at `List`.
List ys = [];
ys.add(xs[0]); // No dynamic check needed.
}
}
```
In this example, it is tested whether there exists a type `S` such that `xs` has type `List`, and if this is true then the type variable `X` is introduced into the scope of the following block `{}`, bound to `S`.

The general point here is that it can be useful to perform a check, at compile time or at run time, of whether a given type satisfies some constraints which may be expressed in a form which is itself similar to a type, and also to introduce and bind certain type variables to types in order to provide information about how those constraints were satisfied.

Contributor guide

Open the contributing guide

Research direction

Start by reading the issue examples and the linked discussions in #40, #41, #31953, and #33841. The issue describes a language-design direction rather than naming files, tests, or an implementation entry point; completion would require settling the semantics and specification for type decomposition.

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
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.