Skip to content

Adjusted generalized type alias feature spec to indicate ongoing discussion #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Author: [email protected] (@eernst).

Version: 0.1.
Version: 0.2.


## Motivation and Scope
Expand Down Expand Up @@ -114,14 +114,32 @@ evaluated as an expression, it is subject to instantiation to bound.
*This treatment of generic type aliases is again the same as it was
previously, but it involves a larger set of types.*

*Note that type aliases introduce types and not classes. Consequently, a
type alias can **not** be used in a position where a class is expected: in the
`extends`, `with`, `implements`, or `on` clause of a class or mixin
declaration; for a static member access; or in an instance creation
expression (`new F()`, `const F<int>()`). On the other hand, it **can** be
used as a type annotation, as a type argument, as part of a function type
or function signature, as a type literal, in an `on` clause of a `try`
statement, in a type test (`e is F`), and in a type cast (`e as F`).*
A type alias application of the form _F_ or the form
_F&lt;T<sub>1</sub>..T<sub>k</sub>&gt;_ can be used as a type annotation,
as a type argument, as part of a function type or a function signature, as
a type literal, in an `on` clause of a `try` statement, in a type test
(`e is F`), and in a type cast (`e as F`).

**The following is under discussion. Exactly one rule will be confirmed.
The following two variants are considered, along with small variations or
hybrids thereof:**

* A type alias can _not_ be used in a position where a class is
expected: in the `extends`, `with`, `implements`, or `on` clause of a
class or mixin declaration; for a static member access; or in an
instance creation expression (`new F()`, `const F<int>()`). OR

* A type alias can _not_ be used for static member accesses. When a type
alias _F_ resp. _F&lt;T<sub>1</sub>..T<sub>k</sub>&gt;_ occurs as the
entity that a class `extends` and when it occurs in a `with` clause or
`implements` clause of a class or an `on` clause of a mixin, or it is
used in an instance creation expression, it is a compile-time error
unless it denotes a class, otherwise it is treated as if that class had
been specified explicitly.
(*E.g., `class C extends myPrefix.F<int> {}` would be equivalent to
`class C extends D<List<int>, int> {}` if the library imported as
`myPrefix` contains `typedef F<X> = D<List<X>, X>;`, assuming that
`D` is accessible to the current library and has no prefix.*)


### Dynamic Semantics
Expand All @@ -146,4 +164,7 @@ fresh type variable bound to the denoted type.

## Versions

* Nov 8th, 2018, version 0.2: Marking the design decision of where to allow
usages of type aliases denoting classes as under discussion.

* Nov 6th, 2018, version 0.1: Initial version of this document.
43 changes: 40 additions & 3 deletions working/spread-collections/feature-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,9 @@ become strict subtype checks instead.

### Const spreads

Spread elements are not allowed in const lists or maps. Because the spread must
be imperatively unpacked, this could require arbitrary code to be executed at
compile time:
We must be careful with spread elements in const collections. Because the spread
is imperatively unpacked, even a "const" object could cause arbitrary
computation at compile time:

```dart
class InfiniteSequence implements Iterable<int> {
Expand All @@ -300,6 +300,43 @@ class InfiniteSequence implements Iterable<int> {
const forever = [...InfiniteSequence()];
```

However, if the spread expression is a valid const expression and the resulting
value is exactly the built-in List or Map classes, then it's safe because we
know exactly how constants of those classes behave. Thus, we state:

* In a constant list, a spread element expands at compile time to the series
of elements contained in the spread object list.

* In a constant map, a spread element expands to the series of entries
contained in the spread object map.

* It is a compile-time error to use a spread element in a constant list unless
the spread object was created by a constant list literal expression.

* It is a compile-time error to use a spread element in a constant map unless
the spread object was created by from a constant map literal expression.

This enables in-place literals (which aren't very useful):

```dart
const list = [...["why"]];
```

It also enables const expressions that refer to constant lists and maps defined
elsewhere, which is useful:

```dart
const list = [2, 3];
const another = [1, ...list, 4]; // [1, 2, 3, 4].
```

The existing rules against self-reference prohibit a list or map from spreading
into itself:

```dart
const list = [...list]; // Error.
```

### Type inference

Inference propagates upwards and downwards like you would expect:
Expand Down