-
Notifications
You must be signed in to change notification settings - Fork 718
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -277,6 +277,43 @@ void main() { | |||||
} | ||||||
``` | ||||||
|
||||||
### Implicit casts | ||||||
|
||||||
Expressions with a static type of `dynamic` can be | ||||||
implicitly cast to a more specific type. | ||||||
If the actual type doesn't match, the cast throws an error at runtime. | ||||||
Consider the following `assumeStrings` method: | ||||||
|
||||||
<?code-excerpt "lib/strong_analysis.dart (downcast-check)" replace="/strings = objects/[!$&!]/g"?> | ||||||
```dart tag=passes-sa | ||||||
void assumeStrings(dynamic objects) { | ||||||
List<String> [!strings = objects!]; // Runtime downcast check. | ||||||
String string = strings[0]; | ||||||
} | ||||||
``` | ||||||
|
||||||
In this example, if `objects` is a `List<String>`, the cast succeeds. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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>`, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
a `TypeError` is thrown: | ||||||
|
||||||
<?code-excerpt "lib/strong_analysis.dart (fail-downcast-check)" replace="/\[.*\]/[!$&!]/g"?> | ||||||
```dart tag=runtime-fail | ||||||
assumeStrings(<int>[![1, 2, 3]!]); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The notation
Suggested change
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 |
||||||
``` | ||||||
|
||||||
:::tip | ||||||
To prevent implicit downcasts from `dynamic` and avoid this issue, | ||||||
consider enabling the analyzer's _strict casts_ mode. | ||||||
|
||||||
```yaml title="analysis_options.yaml" highlightLines=3 | ||||||
analyzer: | ||||||
language: | ||||||
strict-casts: true | ||||||
``` | ||||||
|
||||||
To learn more about customizing the analyzer's behavior, | ||||||
check out [Customizing static analysis](/tools/analysis). | ||||||
::: | ||||||
|
||||||
## Type inference | ||||||
|
||||||
|
@@ -291,9 +328,9 @@ pairs string keys with values of various types. | |||||
|
||||||
If you explicitly type the variable, you might write this: | ||||||
|
||||||
<?code-excerpt "lib/strong_analysis.dart (type-inference-1-orig)" replace="/Map<String, dynamic\x3E/[!$&!]/g"?> | ||||||
<?code-excerpt "lib/strong_analysis.dart (type-inference-1-orig)" replace="/Map<String, Object\?\x3E/[!$&!]/g"?> | ||||||
```dart | ||||||
[!Map<String, dynamic>!] arguments = {'argA': 'hello', 'argB': 42}; | ||||||
[!Map<String, Object?>!] arguments = {'argA': 'hello', 'argB': 42}; | ||||||
``` | ||||||
|
||||||
Alternatively, you can use `var` or `final` and let Dart infer the type: | ||||||
|
There was a problem hiding this comment.
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 typeList
, which is just an abbreviated notation forList<dynamic>
. Next, when we know that it is a list, we check for the type argumentString
(which is a cast fromList<dynamic>
toList<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:
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'.