The Bang
operator does nothing more than tell Dart
that even if we have defined some variable as a Nullable
type, it will definitely
not be null.
Dart's Nullable safety
and Flow Analysis
are here to make the developer's life easy by avoiding runtime error and catching them at compile-time itself.
When you define,
final void Function(int index)? onSelected;
You are telling dart that this variable may or may not
be assigned a value and thus it may or may not be null
.
Now, whenever you try to use it like this,
widget.onSelected()
Dart will warn you that, this is a Nullable
typed variable hence take extra care.
If Dart didn't tell you this before hand, then you would've realized it after you ran the app and it crashed while trying to call the function.
Now, since Dart has warned you that you cannot use it like that, there are two ways to approach it.
Put a null check before using it. This way we are avoiding runtime errors.
var onSelected = widget.onSelected;
if (onSelected != null) onSelected(_selectedIndex);
This creation of a new local variable is necessary since Dart's flow analysis only works on local variable null checks and not class level variable null checks.
Use the bang
operator,
widget.onSelected!(_selectedIndex)
Now the issue with this is that, you are just assuring Dart that it will never be null, but if it were actually null, it will still result in a runtime crash.
So, the Bang
operator is just a way to bypass Dart's flow analysis
when you have to access a nullable typed variable.
Hope this clears at least a bit of your doubt.
required
keyword, not the old@required
annotation. Using that will remove the need foronSelected
to be nullable. The!
null-assertions operator simply performs a runtime assertion that the object is not null; if it turns out to actually be null, it will throw an exception at runtime. – Surovy