flutterdart

What's the difference between double.infinity and double.maxFinite in Dart?


What's the difference between double.infinity and double.maxFinite in Dart?

In Flutter, it looks like both do the same thing. When should I use each of them in Flutter?


Solution

  • From a strictly data-oriented view, the difference is that double.maxFinite represents the maximum-allowed value that the double data type can contain, whereas double.infinity represents, well, infinity. Since Dart strictly defines double as a 64-bit floating point number on all platforms, the value of double.maxFinite is therefore known to be 1.7976931348623157e+308. (The specific reason why is fairly technical, but jpopesculian's answer goes into that somewhat, and generally speaking, those details aren't usually necessary to understand for simple app development anyway.)

    In Flutter, most of the time, there isn't a huge practical difference between the two values. The place where you will see these constants is usually in terms of sizing widgets, and generally when you want a widget to be as big as possible, you pass double.infinity to its width and/or height:

    SizedBox(
      width: 500,
      height: 500,
      child: Container(
        width: double.infinity,
        height: double.infinity,
      ),
    )
    

    In this example, the child Container is given an infinite width and height. Flutter will calculate its size by using its parent to determine how much space is actually available to it and constraining it if necessary. In this case, the Container is being constrained by the SizedBox, which is enforcing a hard limit of 500 pixels by 500 pixels on the Container - no matter how much space the Container requests, it can't get any bigger than that. As such, replacing double.infinity with double.maxFinite doesn't change anything since the parent SizedBox still will only let it get so big.

    This will generally be the case, as most layout widgets in Flutter come with some kind of implicit constraint either as part of their function or inherited from their parent (which, ultimately, will be something like the MaterialApp or a Scaffold which constrains their children to the size of the screen). So a lot of the time, children attempting to be bigger than they have space for won't be too much of a problem since Flutter's layout rules are robust enough to prevent them from taking up more space than they are allowed.

    There are scenarios in which an infinite constraint can lead to problems, though. Take this very contrived example, for instance:

    Column(
      children: [
        Container(
          height: double.infinite,
        ),
      ],
    )
    

    Here, we have a Column which has the effect of creating an infinitely-big vertical space for its children to exist in. As its child, it has a Container that requests an infinite height. The problem is clear: how can Flutter constrain an infinitely tall widget within a parent widget that has infinite constraints? And true enough, trying to render this widget produces the following error:

    ════════ Exception caught by rendering library ═════════════════════════════════ 
    The following assertion was thrown during performLayout():
    BoxConstraints forces an infinite height.
    

    So if the problem is that an infinitely sized widget can't exist in an infinitely constrained space, what if we changed double.infinity to double.maxFinite in the Container? That would solve the problem, since the Container would no longer be infinitely-sized and Flutter could calculate its constraints normally:

    Column(
      children: [
        Container(
          height: double.maxFinite,
          color: Colors.red,
        ),
      ],
    )
    

    Success! The infinite height constraint error has gone away!

    ...We just get this error instead:

    ════════ Exception caught by rendering library ═════════════════════════════════
    The following assertion was thrown during layout:
    A RenderFlex overflowed by 1.7976931348623157e+308 pixels on the bottom.
    

    So yeah, while the height is being properly calculated now, Column will complain if its children are taller than the available space, and it turns out that roughly one hundred centillion pixels is a bit too tall for modern screens.[citation needed]

    (For those curious, the solution here is to wrap the Container in an Expanded, which will take up the visible space in the Column and will once again enforce finite constraints which restrict the Container from taking more space than it is allowed. [Or, you know, you could also not create such an ungodly-sized widget in the first place.])

    So in short, in the places where you might use double.infinity in Flutter, there usually isn't any practical difference between double.infinity and double.maxFinite. But on the occasion where there is, you usually just end up trading one problem for a different problem.

    All of that being said, much of the Flutter widget library was written with double.infinity being a potential valid input, so in most cases you will either get well-defined behavior or a detailed error message. Usage of double.maxFinite, however, I would expect to be much less directly supported, so while it may work anyway a lot of the time, in the cases where it doesn't, you might not get very clear feedback on what exactly went wrong. So, in general, just use double.infinity where appropriate, and for everywhere else, stick with numerical values that make more sense to our mere mortal minds.