dart-lang / dart-lang/language
What's the right syntax for an implicit cast/inline cast operator?
- 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
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