0

I have a problem with dart equality checks on a Function.

I have a CustomPainter and I want to implement it's shouldRepaint() method efficiently.

There is a Function field (ColorResolver) in the painter that gives a y value and gets a color for drawing on the line, I want this logic to be handled outside of the painter.

check this code:

typedef ColorResolver = Color Function(double value);

class MyPainter extends CustomPainter {
  final ColorResolver colorResolver;
  MyPainter(this.colorResolver);

  @override
  void paint(Canvas canvas, Size size) {
    for (double y = 0; y <= size.height; y += 10) {
      final paint = Paint()..color = colorResolver(y);
      canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
    }
  }

  @override
  bool shouldRepaint(MyPainter old) => old.colorResolver != colorResolver;
}

How can I prevent repaint as long as the provided ColorResolver logic is the same as before?

imaN NeoFighT
  • 480
  • 4
  • 13
  • As long as the callback passed to `MyPainter`'s constructor is a named top-level function or a named method (whether on a class or instance) and *not* an anonymous function or a nested function, the equality check should work since it will be the same `Function` instance passed in. – jamesdlin Apr 04 '20 at 07:10
  • The instance check does not work for this, determine the user is using named top-level function, and it returns `Colors.blue` for all values at the first, then he decides to change the returns value to `Colors.blue` for odd values and `Colors.red` for even values, in this situation, instance check doesn't work because the content of function is changed and we have to repaint our painter. – imaN NeoFighT Apr 04 '20 at 07:20
  • And also I cannot force the user to use a top-level function, as long as I implement it in a library, I'm looking for a better approach to make the painter efficient. – imaN NeoFighT Apr 04 '20 at 07:21
  • 1. You're not *forcing* library consumers to use top-level functions; they could still pass any `Function` they want, but they'd have to be willing to sacrifice an optimization opportunity. You can leave that decision to your consumers. 2. I don't understand your comment about "the content of function is changed". You can't change a function at runtime. – jamesdlin Apr 04 '20 at 07:29
  • Determine I pass this function `(value) => Colors.green;`, then everytime I call `setState()` on mya StateFull wrapper (with no changes), It will repaint itself again because the function's reference is changed. – imaN NeoFighT Apr 04 '20 at 07:33
  • That's why I specifically mentioned *named* top-level functions (or methods). You would not be able to do this optimization for anonymous functions or nested functions. As long as you inform library consumers about this, they should be able to work around it if necessary. – jamesdlin Apr 04 '20 at 07:36
  • That's not a great solution, at the basic level it breaks the hot reload functionality. – imaN NeoFighT Apr 04 '20 at 07:44
  • It should not break hot reload. At worst, it means that hot reload would perform one unnecessary paint. – jamesdlin Apr 04 '20 at 07:57
  • Ok please run [this](https://textuploader.com/14r1s) code and change the green color to anything else (line 20) and click on hot reload, boom, nothing has changed! You should hot-restart it to see the effect. – imaN NeoFighT Apr 04 '20 at 08:24
  • Oops, you're right, a named function would satisfy the identity check after a hot reload. You could address that by implementing a mechanism to invalidate the cached `Function` when a hot reload occurs. – jamesdlin Apr 04 '20 at 08:51
  • Could you please implement that mechanism in that sample? – imaN NeoFighT Apr 04 '20 at 09:01
  • See https://stackoverflow.com/a/55282550/179715. – jamesdlin Apr 04 '20 at 17:46

1 Answers1

0

You cannot override the == of a function in Dart. Your only choice is to cache the function instance.

Caching the function is largely dependent on what it does, so there is no finite answer to your problem here. But overall, a StatefulWidget is a good start.

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432