dart-lang / dart-lang/language

What's the right syntax for an implicit cast/inline cast operator?

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

Description

There is a longstanding desire to have better syntax for casts that appear inline in a method chain:

```dart
((a as Whatsit).frobIt(3) as Whosit).fizzle();
```

If we move ahead with #192 there is also a desire to have a short syntax for implicitly casting to the context type (see for example the hand-rolled `cast` function used in [this cl](https://dart-review.googlesource.com/c/sdk/+/69002/4/pkg/analyzer_cli/lib/src/options.dart) removing implicit casts).

It seems likely that we can solve both of these with a single piece of syntax. For example, we could add a postfix cast operator `!!` which casts to the context type, also usable in the form `!!` which casts to `T`. Code that formerly used an implicit cast:

```dart
takeList(List f) {}
Iterable mkIterable() {}
void test() {
takeList(mkIterable());
}
```

could be rewritten as follows:

```dart
takeList(List f) {}
Iterable mkIterable() {}
void test() {
takeList(mkIterable()!!);
}
```

And the example from above with inline casts could be written more cleanly as well:

```dart
a!!.frobIt(3)!!.fizzle();
```

We might wish to specify it to be an error to use `!!` to perform a side cast when the type is not explicitly written.

An alternative syntax which would be more consistent with existing Dart code would be to use `.as` and `.as`.

```dart
takeList(List f) {}
Iterable mkIterable() {}
void test() {
takeList(mkIterable().as);
}
```

```dart
a.as.frobIt(3).as.fizzle();
```

Unfortunately this would be a breaking change, since `as` is not a reserved word in Dart. In practice this is likely non-breaking, @munificent is proposing to scrape some code to verify this.

If we had extension methods + generic getters, we could specify this as a generic extension method:

```dart
extension Cast on Object {
T get as => this as T;
}
```

This doesn't capture a side cast restriction, but it may avoid the breaking change issue. It seems unlikely that we will have both of these features in place in a suitable time frame to use this encoding though.

Other ideas for syntax that have been put out for consideration:
- `x.(as T)` and something like `x.(as)` or `x.(as _)`
- this could possibly be a use of two general mechanisms:
- a way of using an operator in a postfix position
- enabling `await a` -> `a.await`, `a + b` -> `a.+(b)`, possibly also `foo(x, y)` -> `x.foo(y)`
- a prefix version of our existing cast operator
- `x.cast`
- This is probably not feasible, since we have `cast` methods on various core library types.

Contributor guide

Open the contributing guide

Research direction

Read the proposal and its relationship to #192, then compare the `!!`, `.as`, extension-method, and other syntax options described here. Check the referenced analyzer CLI change and the compatibility concern around `as`; done means the language-design tradeoffs are resolved into an agreed syntax and specification direction.

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
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.