StatelessWidget vs a function returning Widgets in terms of performance
Asked Answered
B

1

35

Is there any difference, performance wise, in using a StatelessWidget vs a function returning a Widget?

I'm well aware of at least the differences pointed out in this flutter's repo issue which don't have a relationship with performance.

The fact is that I have some colleagues claiming that functional widgets are worst in terms of performance but after reading a little bit about the subject I cannot find any conclusive piece of documentation that can give credit to that assertion so any kind of clarification regarding this matter will be very welcome!

As far as I can see the only difference between them would be in the case of using a const Widget, which seems that would avoid the rebuilding phase.

Barbershop answered 22/2, 2019 at 10:23 Comment(6)
Duplicate of #53235325, #51689935Crispate
My question is focused on performance not on use cases.Barbershop
It's mentioned in these answers that performance is one of the main differences.Crispate
I reopened it, because I think this question is more about "Why are classes more performant?"Fogbow
Could you point me out to the paragraph where they mention it and they reason about it? I cannot see the word performance in the article. Only in one of the referred articles and just to claim that a Class allows performance optimizations (which is not really the crux of my question as this would be an option). My question is related to some sort of inherent underperformance when using functions vs widgets.Barbershop
That's precisely the point @RémiRousselet. Thanks!Barbershop
A
29

First of all, I'd like to note that a package is available to make a StatelessWidget from a function: functional_widget


The gain is performance is not necessarily true. It depends on how you use your widgets, mostly how you use them to manage your state.

By default, classes may degrade performances when opposed to functions in an application that doesn't utilize their power.

The real question is: What is their power?

Simple: Classes can update independently from each other. Functions cannot

It is possible for classes to partially update the widget tree.

Consider a widget that rebuilds every frame and returns its child:

class InfiniteLoop extends StatefulWidget {
  const InfiniteLoop({Key key, this.child}) : super(key: key);
  final Widget child;
  @override
  _InfiniteLoopState createState() => _InfiniteLoopState();
}

class _InfiniteLoopState extends State<InfiniteLoop> {
  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));

    return widget.child;
  }
}

Now if we wrap our whole application in that widget, what happens?

void main() => runApp(InfiniteLoop(child: MyApp()));

Nothing

Sure, you'll have one widget that rebuilds often in your tree. But in reality, the build method of MyApp will be called only once.

That's because Flutter is able to abort the tree rebuild when the instance of a widget doesn't change.


Classes can abuse of this optimization.

Using classes it is possible to cleverly split the rebuilding of your widget tree into independent parts.

It's not reasonable to list all the potential optimization factors that a class allow, as there are too many.

The following example is a widget that takes an int and formats it into a Text. The catch is, this widget will rebuild only if the int passed change:

class Counter extends StatelessWidget {
  const Counter({Key key, this.value}) : super(key: key);

  final int value;

  @override
  Widget build(BuildContext context) {
    return Text(value.toString());
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) || (other is Counter && other.value == value);

  @override
  int get hashCode => value.hashCode;
}

This works because Flutter uses the == operator to know if a widget should update or not (hence why const constructor is a good optimization factor).

This is not the only solution, but it's a good example of something that functions can't do.

Apostate answered 22/2, 2019 at 12:5 Comment(4)
Thanks for the answer Rémi. I really appreciate it ;D For me, the crux of it is your first paragraph: it depends on the usage. That would mean that you don't have reasons to argue that a StatelessWidget is inherently most performant than a function (if we abstract ourselves from the other use cases where you need to be able to fine tune by overriding the operator== and so on). Then my next question to you, using the example of the InfiniteLoopWidget, I've tested it with a function and yet the function is only called onceBarbershop
I can't reasonably list all the reasons why classes are more performant here. But I can definitely say that functions can never beat an optimized classes architecture.Fogbow
The InfiniteLoop example is not about classes vs functions. It about showcasing one of the optimization factor that classes can use.Fogbow
To make my point clear, I absolutely agree that classes allow for more optimization cases in Flutter, but it seems to me, based on your answers, that you don't think that functions returning widgets are inherently bad in terms of performance. It's just a matter of usage and specificity of the case. What it's clear is that if you use classes you will be always open the case for optimization if needed. Is that right?Barbershop

© 2022 - 2024 — McMap. All rights reserved.