Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dart: How to efficiently initialize multiple final fields that depend on the same calculation?

Tags:

flutter

dart

I have a Dart class with multiple fields that have to be final, because the class extends another class marked with @immutable. The values of these fields are supposed to be calculated when an instance of the class is created. In Dart, "final instance variables must be initialized before the constructor body starts" (from dartlang.org). In that scope, you can only call static methods.

That works for me except some fields depend on the same calculation, meaning that the same calculation is done twice. Is there any way to avoid that, i.e. by saving some temporary result?

My current code:

class _IntegralCurve extends Curve {
  static double delta = 0.01;

  _IntegralCurve(this.original) :
      integral = calculateIntegral(original),
      values = calculateNormalizedValues(original);

  final Curve original;
  final double integral; // Accessible to other classes.
  final Map<double, double> values;

  /// Does the actual integrating work. Called twice.
  static Map<double, double> integrate(Curve original) {
    double integral = 0.0;
    final values = Map<double, double>();

    for (double t = 0.0; t <= 1.0; t += delta) {
      integral += original.transform(t) * delta;
      values[t] = integral;
    }
    values[1.0] = integral;
    return values;
  }

  /// Calculates the integral.
  static double calculateIntegral(Curve curve) => integrate(curve)[1];

  /// Calculates cumulative values.
  static Map<double, double> calculateNormalizedValues(Curve curve) {
    final values = integrate(curve);

    for (final double t in values.keys) {
      values[t] = values[t] / values[1];
    }
    return values;
  }

  double transform(double t) {
    for (final key in values.keys)
      if (key > t)
        return values[key];
    return values[1.0];
  }
}
like image 964
Marcel Avatar asked Oct 24 '18 08:10

Marcel


2 Answers

Calculate the values in a factory constructor:

class _IntegralCurve extends Curve {
  static double delta = 0.01;

  factory _IntegralCurve(Curve original) {
    final integral = calculateIntegral(original),
    final values = calculateNormalizedValues(original);
    return _IntegralCourve._(original, integral, values);
  }

  _IntegralCurve._(this.original, this.integral, this.values);
like image 188
Günter Zöchbauer Avatar answered Sep 21 '22 22:09

Günter Zöchbauer


You can use a factory to hide calculations within a constructor without loosing the final:

class Foo {
  final int computed;
  final int copy;

  Foo._(this.computed, this.copy);

  factory Foo() {
    // calculate value
    int value = 42;
    return Foo._(value, value);
  }
}
like image 39
Rémi Rousselet Avatar answered Sep 23 '22 22:09

Rémi Rousselet