Home > Software engineering >  Immutable classes with calculated fields
Immutable classes with calculated fields

Time:08-24

To initialize a final variable using logic that can’t be handled in the initializer list you can use a factory constructor. Even though that logic is a simple math operation, it apparently breaks Dart's const contract.

I am failing to find a way to use such an alternative constructor, i.e. allowing me to pass three points instead of the center and radius, while still keeping the immutability of the final object.

import 'dart:math';

class Circle {
  final Point center;
  final double radius;

  const Circle(this.center, this.radius);

  factory Circle.fromPoints(Point p1, Point p2, Point p3) {
    Point center = _getCenter(p1, p2, p3);
    return Circle(center, center.distanceTo(p1));
  }

  static Point _getCenter(Point p1, Point p2, Point p3) {
    double centerX = ...
    double centerY = ...

    return Point(centerX, centerY);
  }

I've also tried making that getCenter method public and calculating the center outside the constructor, but it again fails to compile as the calculated center is determined to be Null in the stage of initialization.

Point p1 = const Point(-1, 0);
Point p2 = const Point(0, 1);
Point p3 = const Point(1, 0);
  
Point center = Circle.getCenter(p1, p2, p2);
Circle circle = const Circle(center, center.distanceTo(p1));

But I still prefer having multiple constructors producing const objects instead of such workarounds.

CodePudding user response:

You can get an immutable result, but not a constant one.

The restrictions on constant evaluation are such that you are not allowed to call any but a select few functions in const expressions (mainly operators on numbers). You can't even extract the x and y positions of a Point during constant evaluation. If you need more than what constant evaluation allows, you cannot do the computation as a constant expression. You also cannot pass non-constant values into a const constructor invocations.

That doesn't mean that the result isn't immutable. It's still a class with a two final values, each holding immutable values.

So, what you are doing is fine, and correct, except for putting const in front of Circle(center, center.distanceTo(p1)), because the second argument is not a constant expression.

  • Related