On this page24 sections
- Prerequisites
- Connection With Previous Lectures
- Learning Objectives
- 1. What Is a Dot Shorthand?
- 2. The Context Type
- 3. Arguments, Defaults, and Return Values
- 4. Switch Expressions and Switch Cases
- 5. Comparing with == and !=
- 6. Static Members
- 7. Constructors: .new and Named Constructors
- 8. Where It Does Not Work: No Context Type
- 9. A Chain Must End in the Context Type
- 10. Which Dart Version Added It?
- 11. Readability: When to Use It
- 12. A Real-World Example
- Code Examples
- Common Beginner Mistakes
- Best Practices
- Mini Challenge
- Practice Questions
- Practice Answers
- Quick Revision
- Key Takeaways
- What's Next?
Lecture 129 — Dot Shorthands
| Category | 22 — Modern Dart Features |
| Lecture | 129 of 140 |
| Estimated video length | 10 min |
| Target | Dart 3.12.2 |
| Level | Advanced |
When Dart already knows which type a value must have, writing
Size.smallrepeats a name Dart can work out for itself. A dot shorthand lets you write just.small.
Contents
Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways
Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.
Prerequisites
Students should already understand, from Lectures 025–128:
- switch expressions and patterns in
switch(Lectures 025 and 081) - named,
const, andfactoryconstructors (Lectures 054–055) - static members (Lecture 058)
- enums and enhanced enums (Lectures 067–068)
Duration(Lecture 111)- language versions and the SDK constraint (Lecture 128)
Connection With Previous Lectures
Here is a coffee-size enum from Lecture 067, with a switch that prices each size:
int price(Size size) => switch (size) {
Size.small => 250,
Size.medium => 350,
Size.large => 450,
};The parameter already says size is a Size. Every arm still repeats Size. anyway. In a
longer switch, the type name is most of what you read. In Lecture 128 we saw that each new
Dart version adds features. Dart 3.10 added one aimed exactly at this repetition.
Learning Objectives
By the end of this lecture you will be able to:
- Understand what a dot shorthand is and what a context type is
- Use
.valuefor enum values in variables, arguments, defaults, and return values - Write switch cases and switch arms with dot shorthands
- Compare with
==and!=using a shorthand on the right - Reach static members and constructors with
.name,.new(), and.named() - Recognize the places where no context type exists, and their errors
- Name the Dart version that introduced the feature
- Decide when a shorthand helps readability and when it hurts
1. What Is a Dot Shorthand?
A dot shorthand is a name that starts with a dot, such as .small. Dart fills in the type
name for you.
Analogy — at a coffee counter you say "a small, please", not "a small-size coffee". The cashier knows you are talking about cup sizes, so the word "size" is not needed.
enum Size { small, medium, large }
void main() {
Size cup = .small;
print(cup);
}Size.small.small means exactly Size.small. The value is the same; only the code is shorter.
2. The Context Type
Dart can only fill in the name when it knows which type is expected at that spot. That
expected type is called the context type. In Size cup = .small;, the declared type
Size is the context, so Dart looks for small inside Size.
If the name does not exist in that type, Dart tells you which type it searched:
enum Size { small, medium, large }
void main() {
Size cup = .tiny; // ✗
print(cup);
}Error: The static getter or field 'tiny' isn't defined for the type 'Size'.3. Arguments, Defaults, and Return Values
A typed parameter is a context type, and so is a declared return type.
enum Size { small, medium, large }
void order({Size size = .medium}) => print('Ordered: ${size.name}');
Size biggest() => .large;
void main() {
order();
order(size: .small);
order(size: biggest());
}Ordered: medium
Ordered: small
Ordered: largeThe default value, the argument, and the return value all use the shorthand.
4. Switch Expressions and Switch Cases
The value being switched on gives every arm its context, so the opening example shrinks:
enum Size { small, medium, large }
int price(Size size) => switch (size) {
.small => 250,
.medium => 350,
.large => 450,
};
void main() {
print(price(.medium));
}350Switch statements work the same way, including || between values. The switch is still
exhaustive: forget a value and Dart still names it.
enum Size { small, medium, large }
void main() {
Size cup = .large;
switch (cup) {
case .small:
print('Sip');
case .medium || .large:
print('Big cup');
}
}Big cup5. Comparing with == and !=
In a == b, the left side gives the context for the right side.
enum Size { small, medium, large }
void main() {
Size cup = .small;
print(cup == .small);
print(cup != .large);
}true
trueTurn it around and there is nothing to the left to give a type:
enum Size { small, medium, large }
void main() {
Size cup = .small;
print(.small == cup); // ✗
}Error: No type was provided to find the dot shorthand 'small'.
print(.small == cup);
^^^^^Keep the variable on the left: cup == .small.
6. Static Members
Dot shorthands are not only for enums. Any static field, getter, or method of the context type can be reached the same way.
void main() {
Duration wait = .zero;
int count = .parse('42');
print(wait);
print(count);
}0:00:00.000000
42.zero means Duration.zero, and .parse('42') means int.parse('42'). Your own
static const fields work too, as the next step shows.
7. Constructors: .new and Named Constructors
.new(...) calls the unnamed constructor. A named constructor, including a factory, is
.name(...). With a const constructor you can write const in front as usual.
class Point {
final int x;
final int y;
const Point(this.x, this.y);
const Point.origin() : x = 0, y = 0;
factory Point.fromJson(Map<String, int> json) =>
Point(json['x']!, json['y']!);
static const Point unit = Point(1, 1);
@override
String toString() => '($x, $y)';
}
void main() {
Point a = .new(2, 3);
const Point b = .origin();
Point c = .fromJson({'x': 4, 'y': 5});
Point d = .unit;
print('$a $b $c $d');
}(2, 3) (0, 0) (4, 5) (1, 1)8. Where It Does Not Work: No Context Type
var and final without a type take their type from the value — but .small needs a
type before it can become a value. Neither side can start:
enum Size { small, medium, large }
void main() {
var cup = .small; // ✗
print(cup);
}Error: No type was provided to find the dot shorthand 'small'.
var cup = .small;
^^^^^A context of Object, Object?, or dynamic is no better. print takes an Object?, so
Dart searches the wrong type:
enum Size { small, medium, large }
void main() {
print(.small); // ✗
}Error: The static getter or field 'small' isn't defined for the type 'Object?'.9. A Chain Must End in the Context Type
You may continue after a shorthand, but the lookup still happens in the context type.
void main() {
int fee = .parse('-5').abs();
print(fee);
}5Here int.parse gives an int, and abs() keeps it an int. This fails, because the
context is String, so Dart searches String for small:
enum Size { small, medium, large }
void main() {
String label = .small.name; // ✗
print(label);
}Error: The static getter or field 'small' isn't defined for the type 'String'.Write Size.small.name instead.
10. Which Dart Version Added It?
Dot shorthands arrived in Dart 3.10. Pin a file to 3.9 with the comment from Lecture 128 and the feature is switched off:
// @dart=3.9
enum Size { small, medium, large }
void main() {
Size cup = .small;
print(cup);
}Error: This requires the experimental 'dot-shorthands' language feature to be enabled.
Try passing the '--enable-experiment=dot-shorthands' command line option.In a package, an SDK constraint of ^3.9.0 causes the same error. dart analyze gives the
real fix: "Try updating your pubspec.yaml to set the minimum SDK constraint to 3.10.0 or
higher, and running 'pub get'."
11. Readability: When to Use It
A shorthand removes a name. That is good when the type is obvious nearby — a switch on
size, a parameter called size:, a declaration that starts with Size. It is bad when the
reader must hunt for the type:
void main() {
Duration timeout = .new(seconds: 30); // the type is right there: fine
print(timeout);
}0:00:30.000000Compare apply(.fast, .low, .on): without opening apply, nobody knows what those three
values belong to. Spell out the type when the call site alone does not make it clear.
12. A Real-World Example
enum Size {
small(250),
medium(350),
large(450);
final int price;
const Size(this.price);
}
int total(List<Size> cups, {Size free = .small}) {
int sum = 0;
for (Size cup in cups) {
if (cup != free) sum += cup.price;
}
return sum;
}
void main() {
List<Size> order = [.large, .small, .medium];
print('Total: ${total(order)}');
print('Total: ${total(order, free: .large)}');
}Total: 800
Total: 600The list type gives each element its context, the parameter gives the default and the
argument theirs, and cup != free compares two variables, so nothing needs a shorthand there.
Code Examples
Example 1 — An Enum Value in a Variable
enum Level { beginner, intermediate, advanced }
void main() {
Level ali = .intermediate;
print(ali.name);
}intermediateExample 2 — An Argument
enum Level { beginner, intermediate, advanced }
void enroll(String name, Level level) => print('$name: ${level.name}');
void main() {
enroll('Sara', .advanced);
}Sara: advancedExample 3 — A Switch Expression
enum Level { beginner, intermediate, advanced }
void main() {
Level zayan = .beginner;
int lessons = switch (zayan) {
.beginner => 40,
.intermediate => 25,
.advanced => 10,
};
print(lessons);
}40Example 4 — Comparing
enum Level { beginner, intermediate, advanced }
void main() {
Level sara = .advanced;
if (sara == .advanced) print('Ready for the project');
}Ready for the projectExample 5 — A Static Constant
void main() {
Duration elapsed = .zero;
elapsed += const Duration(minutes: 15);
print(elapsed.inMinutes);
}15Example 6 — Constructors
void main() {
DateTime start = .new(2026, 3, 1);
DateTime parsed = .parse('2026-03-15');
print(parsed.difference(start).inDays);
}14.new(...) calls the DateTime constructor; .parse finds the static method DateTime.parse.
Example 7 — Student Marks
enum Grade { a, b, c, fail }
Grade gradeFor(int marks) => switch (marks) {
>= 80 => .a,
>= 65 => .b,
>= 50 => .c,
_ => .fail,
};
void main() {
print('Ali: ${gradeFor(84).name}');
print('Sara: ${gradeFor(47).name}');
}Ali: a
Sara: failThe return type Grade is the context for every arm's result.
Example 8 — Shopping Total
enum Size {
small(250),
large(450);
final int price;
const Size(this.price);
}
void main() {
List<Size> cart = [.small, .large, .large];
int total = 0;
for (Size item in cart) {
total += item.price;
}
print('Total: $total');
}Total: 1150Example 9 — Bank Balance
enum Kind { deposit, withdrawal }
int apply(int balance, Kind kind, int amount) => switch (kind) {
.deposit => balance + amount,
.withdrawal => balance - amount,
};
void main() {
int balance = 1000;
balance = apply(balance, .deposit, 500);
balance = apply(balance, .withdrawal, 200);
print('Balance: $balance');
}Balance: 1300Example 10 — Temperature Conversion
enum Unit { celsius, fahrenheit }
String show(double celsius, {Unit unit = .celsius}) => switch (unit) {
.celsius => '$celsius °C',
.fahrenheit => '${celsius * 9 / 5 + 32} °F',
};
void main() {
print(show(25));
print(show(25, unit: .fahrenheit));
}25.0 °C
77.0 °FCommon Beginner Mistakes
1. Using var or final without a type
var cup = .small;Error: No type was provided to find the dot shorthand 'small'.Write the type: Size cup = .small;.
2. Putting the shorthand on the left of ==
if (.small == cup) print('small');Error: No type was provided to find the dot shorthand 'small'.The left side gives the context. Write cup == .small.
3. Passing a shorthand where the type is Object?
print(.small);Error: The static getter or field 'small' isn't defined for the type 'Object?'.4. Expecting .values to give a list
List<Size> all = .values;Error: The static getter or field 'values' isn't defined for the type 'List<Size>'.The context is List<Size>, so Dart searches List. Write Size.values.
5. Using the feature with an older language version
A pubspec with sdk: ^3.9.0 reports "This requires the 'dot-shorthands' language feature
to be enabled." Raise the minimum to 3.10.0.
Best Practices
- Use shorthands where the type is visible nearby: switches, typed declarations, named arguments.
- Spell out the type when a bare
.fastor.onwould leave the reader guessing. - Keep the variable on the left of
==and!=. - Prefer
.new(...)only when the declared type is on the same line. - Be consistent inside one file — do not mix
Size.smalland.smallin the same switch.
Mini Challenge
Write enum Light { red, yellow, green } and a function String action(Light light) that
returns 'Stop', 'Wait', or 'Go' using a switch expression with dot shorthands. Call it
with .green and with .red.
Go
StopTry it yourself before opening the solution.
Show solution
enum Light { red, yellow, green }
String action(Light light) => switch (light) {
.red => 'Stop',
.yellow => 'Wait',
.green => 'Go',
};
void main() {
print(action(.green));
print(action(.red));
}Go
StopPractice Questions
Beginner
- Declare
enum Color { red, green, blue }, store.greenin aColorvariable, and print it. - Rewrite
Duration wait = Duration(seconds: 30);with a dot shorthand and printwait. - Which of these compile, and why? (a)
Color a = .red;(b)final b = .red;(c)print(.red);
Application
- Write
void paint(Color c)that printsPainting bluefor.blue, and call it with a shorthand. - Using the
Sizeenum{ small, medium, large }, write a switch expression that gives250,350,450, and print the price of.medium. - Fix this line so it compiles:
if (.small == cup) print('small'); - Give a class
Temperaturea fielddouble celsiusand a named constructorTemperature.fromFahrenheit(double f). Create.fromFahrenheit(212)with a shorthand and printcelsius. - Write
void brew({Size size = .medium})that printsBrewing medium, then call it with no argument and with.large.
Challenge
- Store
List<Size> cups = [.small, .large, .large];and print the total price using the prices from question 5. - Explain why
String n = .small.name;fails, and give two ways to fix it.
Practice Answers
Question 1 — Solution
enum Color { red, green, blue }
void main() {
Color c = .green;
print(c);
}Color.greenQuestion 2 — Solution
void main() {
Duration wait = .new(seconds: 30);
print(wait);
}0:00:30.000000Question 3 — Solution
Only (a) compiles. (b) final with no type gives no context: "No type was provided to find
the dot shorthand 'red'." (c) print expects Object?, so Dart searches Object? for
red and does not find it.
Question 4 — Solution
enum Color { red, green, blue }
void paint(Color c) => print('Painting ${c.name}');
void main() {
paint(.blue);
}Painting blueQuestion 5 — Solution
enum Size { small, medium, large }
int price(Size size) => switch (size) {
.small => 250,
.medium => 350,
.large => 450,
};
void main() {
print(price(.medium));
}350Question 6 — Solution
enum Size { small, medium, large }
void main() {
Size cup = .small;
if (cup == .small) print('small');
}smallQuestion 7 — Solution
class Temperature {
final double celsius;
Temperature.fromFahrenheit(double f) : celsius = (f - 32) * 5 / 9;
}
void main() {
Temperature boiling = .fromFahrenheit(212);
print(boiling.celsius);
}100.0Question 8 — Solution
enum Size { small, medium, large }
void brew({Size size = .medium}) => print('Brewing ${size.name}');
void main() {
brew();
brew(size: .large);
}Brewing medium
Brewing largeQuestion 9 — Solution
enum Size { small, medium, large }
int price(Size size) => switch (size) {
.small => 250,
.medium => 350,
.large => 450,
};
void main() {
List<Size> cups = [.small, .large, .large];
int total = 0;
for (Size cup in cups) {
total += price(cup);
}
print('Total: $total');
}Total: 1150Question 10 — Solution
The context type is String, so Dart looks for a static member small in String. Fix it
by naming the enum, or by giving the shorthand its own Size context first:
enum Size { small, medium, large }
void main() {
String n = Size.small.name;
Size cup = .small;
print(n);
print(cup.name);
}small
smallQuick Revision
- What is a context type?
- What does
.smallmean when the context type isSize? - Which side of
==gives the context? - How do you call an unnamed constructor with a shorthand?
- Why does
var cup = .small;fail? - Which Dart version introduced dot shorthands?
- When should you spell out the type instead?
Key Takeaways
- A dot shorthand like
.smalllets Dart fill in the type name from the context type. - Typed variables, parameters, defaults, return types, list types, and switches all give a context.
- In
==and!=, the left side gives the context:cup == .small, never.small == cup. - Static members (
.zero,.parse) and constructors (.new(),.origin(),.fromJson()) work too. var,finalwithout a type,Object?, anddynamicgive no useful context.- The lookup always happens in the context type, so a chain must end in that type.
- Dot shorthands need language version 3.10 or later.
- Use them where the type is obvious nearby; spell it out where it is not.
What's Next?
Lecture 130 — Class Modifiers. Dot shorthands make using a type shorter, but they say
nothing about how others may use your classes. Can another library extend your class,
implement it, or only construct it? Next we will meet base, interface, final, and the
other class modifiers that answer those questions.