In Dart 3.10 and later, how does a dot shorthand like .start or .parse('8080') resolve, and where does it fail to compile?
answer
- the expected type decides
- static members, constructors, enum values
- .new() for the unnamed constructor
- Color slot, but red lives on Colors
- shorthand on the right of ==
basics
~20 sA Dart dot shorthand such as .start omits the type name and is resolved against the context type, the type expected at that position; it fails where no context exists, like var x = .a, or where that type lacks the member.
solid answer
~40 sDot shorthands arrived in Dart 3.10 and need a package SDK lower bound of 3.10. The compiler takes the **context type**, the type the position expects, and looks up a static member, constructor or enum value of that exact type: `int port = .parse('8080')` calls `int.parse`, `.new()` calls the unnamed constructor, and in Flutter `crossAxisAlignment: .start` resolves on `CrossAxisAlignment`. `padding: .all(16)` works because `EdgeInsetsGeometry` declares a forwarding factory to `EdgeInsets.all`, while `color: .red` fails because `Color` has no static `red`; that lives on `Colors`. Other failures: `var x = .running` has no context, `==` only accepts the shorthand on its right-hand side, and a statement cannot start with a dot.
code
dart · 21 linesimport 'package:flutter/material.dart';
enum SyncState { idle, running, failed }
Widget statusRow(SyncState state, List<Widget> children) {
final label = switch (state) {
.idle => 'Idle',
.running => 'Syncing',
.failed => 'Failed',
};
return Container(
padding: .all(16), // EdgeInsetsGeometry.all
color: .fromARGB(255, 33, 150, 243), // Color.fromARGB
// color: .red, // error: Color has no static red
child: Column(
crossAxisAlignment: .start,
mainAxisSize: .min,
children: [Text(label), ...children],
),
);
}go deeper
Recall that .start or .all(16) omits a type name the compiler already expects. Know it needs Dart 3.10 or later.
Explain resolution through the context type, list what can be looked up (statics, constructors, .new(), enum values), and name the failing cases: no context, left side of ==, leading statement dot.
Diagnose a failing shorthand by checking the declared parameter type, explain Flutter's forwarding factories on EdgeInsetsGeometry, and set team conventions on when the full type name reads better.
Weigh adoption across packages: a 3.10 lower SDK bound for every package that uses them, and a style rule so shorthands appear where the type is obvious rather than everywhere.
## What a dot shorthand is Since **Dart 3.10**, an expression can start with a leading dot and omit the type name when the compiler already knows which type it expects. `.running` means `Status.running`, `.parse('8080')` means `int.parse('8080')`, `.origin()` means `Point.origin()`, and `.new()` calls an unnamed constructor. The feature needs a package whose SDK constraint lower bound is 3.10 or greater; Flutter 3.47 ships Dart 3.13, so current Flutter apps can use it. ## How the name is resolved: the context type The compiler resolves a shorthand against the **context type**, the type the surrounding code expects at that position. It then looks for a **static member, constructor or enum value of that exact type**: - `Status s = .running;` looks up `running` on `Status`. - `int port = .parse('8080');` finds the static method `int.parse`. - `List<int> xs = .filled(5, 0);` finds the constructor `List.filled` and infers the type argument. - `const Point p = .origin();` works in a constant context when the member is a const constructor or constant. - Named arguments carry their parameter type as context, which is where Flutter code benefits most: `crossAxisAlignment: .start`, `mainAxisSize: .min`. For a nullable context `T?`, the static members of `T` are searched (not those of `Null`). For `FutureOr<T>`, the members of `T` are searched, mainly so `async` functions can return shorthands. ## The Flutter detail: forwarding members on abstract types Many Flutter parameters are typed with an **abstract geometry class**, such as `EdgeInsetsGeometry` for `padding` or `AlignmentGeometry` for `alignment`. A shorthand looks only at that declared type, so Flutter declares forwarding members on it. In Flutter 3.47, `EdgeInsetsGeometry` has `const factory EdgeInsetsGeometry.all(double value) = EdgeInsets.all;`, and `AlignmentGeometry` has static constants such as `topLeft`. That is why `padding: .all(16)` and `alignment: .topLeft` compile. The same rule explains a common failure. `Container(color: .red)` does **not** compile: the parameter type is `Color?`, and `Color` has no static `red`; the named colours live on the separate `Colors` class. `.fromARGB(255, 33, 150, 243)` does compile, because `Color.fromARGB` is a constructor of `Color` itself. ## Where shorthands fail | Code | Result | Why | |---|---|---| | `var s = .running;` | error | `var` gives no context type | | `myColor == .green` | OK | the left operand's type is the context | | `.green == myColor` | error | the shorthand must be on the right of `==` or `!=` | | `myColor == (flag ? .green : .blue)` | error | a complex right-hand side is not supported | | `(myColor as Object) == .green` | error | the cast removes the useful type | | `.log('Hello');` as a statement | error | an expression statement may not start with `.` | | `Color c = flag ? .green : .blue;` | OK | the declaration supplies the context to both branches | **Chains are allowed but checked.** `String lower = .fromCharCode(72).toLowerCase();` resolves `.fromCharCode` on `String`, then calls the instance method. The whole chain must still produce a value of the context type. ## Using them well 1. **Prefer shorthands where the type is obvious from the line**: enum values in switch cases and named arguments, `.new()` for field initialisers such as `final ScrollController _controller = .new();`. 2. **Keep the type name when it carries meaning** for a reader, for example a factory whose class is not visible nearby. 3. **Do not fight the context rule**: when a shorthand fails, check the declared parameter type first. The fix is usually the full name, not a cast. 4. **Remember the language version**: a package whose lower SDK bound is below 3.10 cannot use them, even on a newer SDK. ## What an interviewer listens for - That resolution is driven by the **context type**, and only that type's own static members, constructors and enum values are candidates. - A concrete Flutter example of both success (`.start`, `.all(16)`) and failure (`.red` in a `Color` slot). - The asymmetric `==` rule and the ban on starting a statement with `.`. - The Dart 3.10 language-version requirement.
- Why does padding: .all(16) compile in Flutter when the parameter type is the abstract EdgeInsetsGeometry?A shorthand only searches the context type, here `EdgeInsetsGeometry`. Flutter declares forwarding members on that abstract class, such as `const factory EdgeInsetsGeometry.all(double value) = EdgeInsets.all;`, so `.all(16)` resolves to it and produces an `EdgeInsets`. `AlignmentGeometry` does the same with static constants like `topLeft`.
- Why is myColor == .green allowed in Dart but .green == myColor is not?The `==` rule is asymmetric: when a shorthand is the right operand of `==` or `!=`, Dart uses the static type of the left operand as its context. On the left there is nothing to supply a context, so `.green == myColor` does not compile. A conditional expression on the right, or a left operand cast to `Object`, also loses the context.
saying these in an interview costs you the question
- Thinks color: .red works because Colors.red exists
- Believes shorthands work only for enum values
- Expects var x = .running to infer the enum
- Assumes .green == myColor is equivalent to myColor == .green
- Says dot shorthands shipped with Dart 3.0