Flutter Widgets Deep Dive Part 1: Square Peg in a Round Hole — Generics in Dart
Hello Flutterisans :), after giving more than 40 talks about Flutter within the past year, all of which were in different countries, I found there are some repeated questions beginners keep asking me. There are also some ambiguous points about Flutter new developers misunderstand.
In this series of articles I’ll try to explain some important concepts about Flutter and Dart that are important for anyone at the beginning of his or her Flutter journey. I’ll also try to explain the general theory of how things work inside of Flutter & Dart.
These articles will cover the following points:
- Generics in Dart: Both the Problem and the Solution.
- Why there are two types of widgets inside flutter(
Stateless
&Stateful
) and when each should be used. - Life without
StatefulWidget
- Why the
StatefulWidget
and it’sState
are separate classes. - Widgets and the Render Tree
- Flutter widgets you should know.
- Testing in Flutter (Unit testing — Widget testing — Integration testing)
Square Peg in a Round Hole
Let’s simulate a classic game, putting a square peg into a round hole. You might say we can’t put a square peg into a round hole, and that’s a problem. So how can we solve this problem using Dart?
Let’s create three classes:
- One class to represent the
Slot
. - Another class to represent the square peg.
- The third class to represent the circle peg.
The Slot
class has a method called “insert”. This method will be used to insert the shape.
So what is the problem?
The problem is when the Slot
class is instantiated, I need to know if this particular slot is made for a circle or for a square.
You might be wondering why we don’t just create two types of slots, one for a Circle and another for a Square:
But when we try to insert a shape that’s not compatible with the slot type we’re trying to use, the compiler complains:
At this point, you might be wondering:
- Is this really the best approach for solving this problem?
2. Might there be a better way to solve the problem without writing custom code for every different Slot
type?
3. Is there a solution that would still work if we added more types besides Circle
and Square
?
The answer is Yes, Yes and Yes! You can do all of this using Generics.
Generics allow us to write code we’ll be able to reuse easily; without needing to write custom code for each different type of shape.
Let’s refactor our code again but this time we’ll use Generics:
From the snippet above, you can see we used letter T inside a pair of <> brackets to denote a generic type. We can specify the Slot
type when creating the instance of our shape as shown in line 2.
This code is more elegant, easier to work with plus it’s now reusable; and if we try to insert a shape type that doesn’t match our Slot
type, the code still won’t let that happen:
Why am I explaining all of this? Why do I need to understand this when starting with Flutter?
The answer to this lies in the standard code that is generated when you create a new Flutter app. In main.dart
, you’ll find two classes: MyHomePage
and _MyHomePageState
. MyHomePage
extends StatefulWidget
(Line #1) and _MyHomePageState
extends State
class (Line #7 ). This is shown in the code snippet below:
Something commonly misunderstood by people new to Flutter, or to statically typed languages in general, is the following line:
As you can see, we want to create a _MyHomePageState
class that extends State
. If you look carefully, you’ll see that the State
class has a generic type <T>, and so we’re going to want to specify what Type we’re going to be using in place of T for our new _MyHomePageState
class. When creating a State
we need to define what it is the State
of. We do this by defining T, which in this case is going to be our StatefulWidget
, MyHomePage
.
If you were to check the source code, this is what you’d find:
Since the source code needs to be reusable anytime we need to create a State
for a StatefulWidget
, it uses a generic type <T>.
Simply put, we’re telling Flutter to create a class _MyHomePageState
which will borrow some functionality from State
. Since we need to make sure this State
is only responsible for a single StatefulWidget
, we type it by adding that Widget’s type in <> brackets (here we use MyHomePage
) . By doing so, we tie this instance ofState
to the MyHomePage
class.
This process is exactly what we did to our Slot class earlier.
So when you see State<MyHomePage>
remember Slot<Circle>
. This is how Flutter’s State
class uses generics from Dart. It ensures that when you create a State
, it’s only referenced by one the StatefulWidget
it belongs to.
Generics having been addressed, we can focus on what StatefulWidget
& StatelessWidget
mean and when, or why, we should be using each. This will be discussed in our next article :)
See you soon and best regards,
— Ahmed