Problem Statement
When upgrading from freezed 2.x to 3.x, all existing code that uses pattern-matching methods (.when(), .maybeWhen(), .map(), .maybeMap()) as instance methods breaks with compilation errors:
error: The method 'maybeWhen' isn't defined for the type 'MyState'
Impact on Large Codebases
For projects with hundreds of freezed classes:
- Our codebase: 716 freezed classes, 442+ pattern matching call sites
- Result: 442+ compilation errors after upgrading to freezed 3.x
- Refactoring effort: 20-40 hours of manual work
- Risk: High chance of introducing bugs during mass refactoring
This effectively blocks adoption of freezed 3.x for large existing codebases.
Root Cause
Freezed 2.x Behavior
Pattern methods were generated as instance methods on the mixin:
mixin _$MyState {
TResult when<TResult>(...) { ... } // Instance method
TResult maybeWhen<TResult>(...) { ... }
}
Freezed 3.x Behavior
Pattern methods are only generated as extension methods:
extension $MyStateExtension on MyState {
TResult when<TResult>(...) { ... } // Extension only
}
Existing code calling .maybeWhen() as an instance method fails to compile.
Proposed Solution
Add a build.yaml configuration option to generate pattern methods as instance methods (in addition to extensions):
# build.yaml
targets:
$default:
builders:
freezed:
options:
# New option (default: false for backward compatibility)
generate_pattern_methods_as_instance: true
Implementation Approach
When this option is enabled:
- Generate pattern methods in the mixin (as instance methods)
- Also generate extension methods (for new code)
- Both syntaxes work simultaneously
Result:
// ✅ Instance method (freezed 2.x style) - works
myState.maybeWhen(
success: (data) => print(data),
orElse: () => print('other'),
);
// ✅ Extension method (freezed 3.x style) - also works
myState.maybeWhen(
success: (data) => print(data),
orElse: () => print('other'),
);
Benefits
- Zero breaking changes for existing codebases
- Gradual migration path: Teams can migrate at their own pace
- Backward compatible: Old code continues to work
- Forward compatible: New code can use either syntax
- Opt-in: Doesn't affect users who don't need it
Proof of Concept
We've implemented this as a local patch and it works perfectly:
- ✅ 0 compilation errors (down from 442+)
- ✅ All 716 freezed classes work correctly
- ✅ Full freezed 3.x feature support
- ✅ Zero code changes required
- ✅ Production-tested for [X weeks]
Technical Implementation
Modified three template files:
pattern_template.dart: Added patternMethods() function (generates methods without extension wrapper)
abstract_template.dart: Inject patternMethods() into mixin body
concrete_template.dart: Ensure concrete classes use with _$ClassName
Code changes: ~50 lines total
Complexity: Low
Performance impact: None (same methods, different location)
Use Cases
This feature would benefit:
- Large existing codebases (hundreds of freezed classes)
- Teams with limited refactoring time
- Projects in active development (can't pause for mass refactoring)
- Gradual migration scenarios (migrate module by module)
Alternative Considered
Mass refactoring: Refactor all 442+ call sites to use Dart 3 switch expressions
- ❌ Time-consuming (20-40 hours)
- ❌ High risk of bugs
- ❌ Blocks other development work
- ❌ Not feasible for all teams
Willingness to Contribute
If this feature is acceptable, I'm willing to:
Additional Context
Related
Problem Statement
When upgrading from freezed 2.x to 3.x, all existing code that uses pattern-matching methods (
.when(),.maybeWhen(),.map(),.maybeMap()) as instance methods breaks with compilation errors:Impact on Large Codebases
For projects with hundreds of freezed classes:
This effectively blocks adoption of freezed 3.x for large existing codebases.
Root Cause
Freezed 2.x Behavior
Pattern methods were generated as instance methods on the mixin:
Freezed 3.x Behavior
Pattern methods are only generated as extension methods:
Existing code calling
.maybeWhen()as an instance method fails to compile.Proposed Solution
Add a build.yaml configuration option to generate pattern methods as instance methods (in addition to extensions):
Implementation Approach
When this option is enabled:
Result:
Benefits
Proof of Concept
We've implemented this as a local patch and it works perfectly:
Technical Implementation
Modified three template files:
pattern_template.dart: AddedpatternMethods()function (generates methods without extension wrapper)abstract_template.dart: InjectpatternMethods()into mixin bodyconcrete_template.dart: Ensure concrete classes usewith _$ClassNameCode changes: ~50 lines total
Complexity: Low
Performance impact: None (same methods, different location)
Use Cases
This feature would benefit:
Alternative Considered
Mass refactoring: Refactor all 442+ call sites to use Dart 3 switch expressions
Willingness to Contribute
If this feature is acceptable, I'm willing to:
Additional Context
Related