freezed
freezed copied to clipboard
feat: generate proxies for shared methods implementation
Currently, this implementation is valid.
@freezed
class Shape with _$Shape {
const Shape._();
const factory Shape.square({
required double side,
}) = Square;
const factory Shape.circle({
required double radius,
}) = Circle;
double get area => when(
square: (side) => pow(side, 2).toDouble(),
circle: (radius) => pi * pow(radius, 2),
);
}
extension ExtendedCircle on Circle {
double get diameter => 2 * radius;
}
void main() {
const square = Shape.square(side: 2);
final squareArea = square.area;
const circle = Shape.circle(radius: 5);
final circleArea = circle.area;
const shape = Shape._();
final area = shape.area;
final maybeDiameter = shape.whenOrNull(circle: (radius) => 2 * radius);
if (circle is Circle) {
final diameter = circle.diameter;
}
}
However, if the implementation of the area
getter were too complex or long, it would be handy to isolate it.
One alternative to accomplish this is by using top-level functions. However, a more straightforward option would be the use of mixins that implement this shared/common behaviour, that might be identified by freezed and exposed by the base class.
@freezed
class Shape with _$Shape {
const Shape._();
@With<SquareMixin>()
const factory Shape.square({
required double side,
}) = Square;
@With<CircleMixin>()
const factory Shape.circle({
required double radius,
}) = Circle;
double get area => $area;
Shape scale(double scale) => $scale(scale);
}
mixin SquareMixin {
double get side;
double get area => pow(side, 2).toDouble();
Square scale(double scale) => Square(side: scale * side);
}
mixin CircleMixin {
double get radius;
double get area => pi * pow(radius, 2);
Circle scale(double scale) => Circle(radius: scale * radius);
double get diameter => 2 * radius;
}
// GENERATED BY FREEZED vvvvvvvvvvvvvvvvvvvv
extension __$Shape on _$Shape {
double get $area => map(
square: (value) => value.area,
circle: (value) => value.area,
);
Shape $scale(double scale) => map(
square: (value) => value.scale,
circle: (value) => value.scale,
).call(scale);
}
// GENERATED BY FREEZED ^^^^^^^^^^^^^^^^^^^^
void main() {
const square = Shape.square(side: 2);
final squareArea = square.area;
const circle = Shape.circle(radius: 5);
final circleArea = circle.area;
const shape = Shape._();
final area = shape.area;
final maybeDiameter = shape.whenOrNull(circle: (radius) => 2 * radius);
if (circle is Circle) {
final diameter = circle.diameter;
}
}
Hello!
I don't quite understand what you're trying to solve. Could you explain more in depth the problem?
The mixins are already providing implementations for area and scale, so there's no need to create an extension. Your code will work as intended just by changing the Shape area/scale implementations to throw UnimplementedError()
or similar.
(You can enforce that all shapes must provide implementations of area/scale by making Shape abstract, but then Freezed will output a warning informing you that declaring Freezed classes abstract is not needed anymore.)
I have no plan to implement this. Closing :)