Skip to content
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

Adapt implicit cast example for type system page #6478

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

parlough
Copy link
Member

@parlough parlough commented Mar 7, 2025

Adds a section about implicit cast runtime errors to the "Type system" page, based off the Invalid casts section of the deprecated sound problems page.

Contributes to #6265

Staged: https://dart-dev--pr6478-feat-type-system-implicit-casts-j5bzqnf7.web.app/language/type-system#implicit-casts

@dart-github-bot
Copy link
Collaborator

dart-github-bot commented Mar 7, 2025

Visit the preview URL for this PR (updated for commit a4175df):

https://dart-dev--pr6478-feat-type-system-implicit-casts-j5bzqnf7.web.app

@parlough parlough requested a review from antfitch March 7, 2025 19:13
@antfitch
Copy link

antfitch commented Mar 7, 2025

Thank you for adding that staged link! A dream: we have those created by default when we stage. ^_^

@antfitch antfitch requested a review from eernstg March 7, 2025 19:20
@antfitch
Copy link

antfitch commented Mar 7, 2025

@eernstg, adding you as our technical reviewer. Can you double-check the staged doc? If you want to triage this to another technical expert, please do so.

Note to Dart engineers: on reviews where any doc changes are added that modify technical content, we generally need to make sure we have at least one technical writer and one additional engineer on those PRs for review.

Copy link
Member

@eernstg eernstg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from a programming language perspective. I recommended a couple of simplifications.

}
```

In this example, if `objects` is a `List<String>`, the cast succeeds.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In this example, if `objects` is a `List<String>`, the cast succeeds.
In this example, if `object` is a `String`, the cast succeeds.

```

In this example, if `objects` is a `List<String>`, the cast succeeds.
If it's not a subtype of `List<String>`, such as `List<int>`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If it's not a subtype of `List<String>`, such as `List<int>`,
If it's not a subtype of `String`, such as `int`,

List<String> [!strings = objects!]; // Runtime downcast check.
String string = strings[0];
}
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend using a simpler example: The downcast in the current example takes two steps, but we would already have a perfectly useful example if it is adjusted to take just one step.

The first step in the current example is concerned with the class: Starting from dynamic, it is tested whether the given object is a list. We could say that we're checking for the type List, which is just an abbreviated notation for List<dynamic>. Next, when we know that it is a list, we check for the type argument String (which is a cast from List<dynamic> to List<String>). This second step is based on a subtype relation known as covariance.

I think the topic of the example should just be "implicit downcasts from dynamic", and there's no need to include anything that requires the reader to think about a two-step subtype relationship that also involves variance.

Here's one possible way to do this:

int assumeString(dynamic object) {
  String string = object; // Check at run time that it is a `String`.
  return string.length;
}

I'd suggest using 'run time' rather than 'runtime', because the latter commonly refers to the support system which is running along with a program (providing external functions like print, services like garbage collection, etc.) In contrast, 'run time' is a noun phrase that denotes a specific kind of point in time, namely: One that occurs during an execution of the program. If you want to use the corresponding adjective then it would be 'run-time', as in 'a run-time error occurs if it is not a string'.


<?code-excerpt "lib/strong_analysis.dart (fail-downcast-check)" replace="/\[.*\]/[!$&!]/g"?>
```dart tag=runtime-fail
assumeStrings(<int>[![1, 2, 3]!]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notation [!1!] should be a highlighted version of 1 (I'm not 100% sure about the syntax):

Suggested change
assumeStrings(<int>[![1, 2, 3]!]);
final length = assumeString([!1!]);

I introduced a local variable to store the returned result. That's still a bit artificial because it isn't used anywhere, but I thought it was one step more natural than just having a local variable inside assumeStrings and not returning anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants