What does the Object<type> syntax mean in Dart? - dart

In the following code example, from the flutter docs:
class RandomWords extends StatefulWidget {
#override
createState() => RandomWordsState();
}
class RandomWordsState extends State<RandomWords> {
#override
Widget build(BuildContext context) {
final wordPair = WordPair.random();
return Text(wordPair.asPascalCase);
}
}
What exactly does the State<RandomWords> syntax mean?
I understand that you can specify the type for the objects contained in a collection, like lists, using this syntax - List <String>
But I cannot understand the motive behind State<RandomWords>.
Moreover, how can you reference RandomWordsState in RandomWords declaration and also reference RandomWords in RandomWordsState declaration? Shouldn't that cause a circular reference error or something?
I come from dynamically typed languages like python, and this looks a little odd to me, can someone please point me to the right place?

<RandomWords> is a generic type parameter passed to the State class.
The State class looks like
abstract class State<T extends StatefulWidget> extends Diagnosticable {
and RandomWords will be passed to the T type parameter which has a constraint that T needs to be a subclass of StatefulWidget.
State also has a field and getter where the type parameter is used
T get widget => _widget;
T _widget;
This results in a property of the type of the widget
which provides proper autocompletion and type checks in its subclass RandomWordsState
Assume you have
class RandomWords extends StatefulWidget {
RandomWords({this.fixed});
final WordPair fixed;
#override
createState() => RandomWordsState();
}
class RandomWordsState extends State<RandomWords> {
#override
Widget build(BuildContext context) {
// vvvv here we can access `fixed` in a strongly typed manner
final wordPair = widget.fixed ?? WordPair.random();
return Text(wordPair.asPascalCase);
}
}
See also https://www.dartlang.org/guides/language/language-tour#generics

Related

How to create a mixin for advanced enum and use it in a generic widget?

My goal is to write a generic Widget that, in this case, enables the user for selecting an enum value among all the values from the enum.
So I'd like to write something like so:
class WheelPickerWidget<T extends Enum> extends StatelessWidget {
/// The initial value
final T? value;
/// The onChanged callback
final void Function(T)? onChanged;
/// Retuns the wheel enum picker
const WheelPickerWidget(
{super.key, required this.value, required this.onChanged});
#override
Widget build(BuildContext context) {
return ListWheelScrollView(
physics: const BouncingScrollPhysics(),
itemExtent: 50,
diameterRatio: 0.6,
//offAxisFraction: -0.4,
squeeze: 1.8,
//useMagnifier: true,
//overAndUnderCenterOpacity: 0.8,
clipBehavior: Clip.antiAlias,
onSelectedItemChanged: (value) => onChanged?.call(T.fromValue(value)),
children: T.values.map((c) => Text("$c")).toList());
}
}
But I see T.fromValues() and T.values are generating errors as follows:
The method 'fromValue' isn't defined for the type 'Type'.
Try correcting the name to the name of an existing method, or defining a method named 'fromValue'.
The getter 'values' isn't defined for the type 'Type'.
Try importing the library that defines 'values', correcting the name to the name of an existing getter, or defining a getter or field named 'values'.
I usually write my enums as follows:
/// Theme to use for the app
enum AppTheme {
green(0),
yellow(1),
nightBlue(2);
const AppTheme(this.value);
final int value;
factory AppTheme.fromValue(int v) => values.firstWhere((x) => x.value == v,
orElse: () => throw Exception("Unknown value $v"));
/// Returns the name corresponding to the enum
#override
String toString() {
switch (this) {
case green:
return i18n_Green.i18n;
case yellow:
return i18n_Yellow.i18n;
case nightBlue:
return i18n_Night_blue.i18n;
}
}
}
Where I make fromValue() readily available.
And I guess I could use mixin to create a specific form of enum that complies to the requirements.
/// Advanced enum
mixin EnumMixin {
}
But I didn't manage to do it: one reason is the factory cannot be supported by the mixin.
So to sum up, my questions are:
How to make my wheel picker class works with my enum?;
How to create a generic way (possibly being a mixin) to conform all my enums to a way it can be supported by my generic wheel picker?
You cannot make T.someConstructor() or T.someStaticMethod() work for some generic type T. Dart does not consider constructors and static methods to be part of the class interface, and they are not inherited.
In general, whenever you want to use something like T.someConstructor() or T.someStaticMethod(), you're probably better off using a callback instead. Similarly, instead of using T.values, you can accept a List<T> argument.
For example:
class WheelPickerWidget<T extends Enum> extends StatelessWidget {
WheelPickerWidget({required this.values, required this.fromValue});
final List<T> values;
final T Function(int) fromValue;
...
#override
Widget build(BuildContext context) {
return ListWheelScrollView(
...
onSelectedItemChanged: (value) => onChanged?.call(fromValue(value)),
children: values.map((c) => Text("$c")).toList());
}
}
and then callers would use:
WheelPickerWidget(values: AppTheme.values, fromValue: AppTheme.fromValue);
Note that fromValue is a bit redundant in principle if you already have values; you could just iterate over values to find the Enum you want. For example, you could do:
abstract class HasValue<T> {
T get value;
}
enum AppTheme implements HasValue<int> {
green(0),
yellow(1),
nightBlue(2);
const AppTheme(this.value);
#override
final int value;
...
}
class WheelPickerWidget<T extends Enum> extends StatelessWidget {
WheelPickerWidget({required this.values})
final List<T> values;
...
#override
Widget build(BuildContext context) {
return ListWheelScrollView(
...
onSelectedItemChanged: (value) => onChanged?.call(values.findValue(value)),
children: values.map((c) => Text("$c")).toList());
}
}
extension<T extends Enum> on List<T> {
T findValue<U>(U value) {
for (Object e in this) {
if (e is HasValue<U> && e.value == value) {
return e as T;
}
}
throw Exception("Unknown value $value");
}
}
Unfortunately, findValue is slightly awkward because there doesn't seem to be a good way to enforce that T derives from both Enum and HasValue, so it must perform runtime type-checking. Additionally, Dart will not perform automatic type promotion between unrelated types (in this case, Enum and HasValue), so findValue upcasts to Object first as a workaround.
If you don't want callers to pass extra arguments, one alternative would be to store those arguments in a global lookup table with the generic type as the key. This isn't a great general approach since a Map<Type, ...> depends on exact Type matches, so looking up a subtype wouldn't match a supertype in the Map. However, Enums are not allowed to be extended nor implemented, so that is not a concern. I would consider it to be less robust, however, since it would require extra work to initialize such a Map, and there's no way at compile-time that it's been initialized with all of the types you care about. As an example of how this could look:
final _fromValueMap = <Type, Enum Function(int)>{
AppTheme: AppTheme.fromValue,
};
final _lookupValuesMap = <Type, List<Enum>>{
AppTheme: AppTheme.values,
};
T fromValue<T>(int value) => _fromValueMap[T]!(value) as T;
List<T> lookupValues<T>() => _lookupValuesMap[T]! as List<T>;
class WheelPickerWidget<T extends Enum> extends StatelessWidget {
...
#override
Widget build(BuildContext context) {
return ListWheelScrollView(
...
onSelectedItemChanged: (value) => onChanged?.call(fromValue<T>(value)),
children: lookupValues<T>().map((c) => Text("$c")).toList());
}
}

Why is recommended to use final variables in widget as public?

The standard that I see in repos is
class A extends StatelessWidget {
final String title;
...
What would be the reason to use
class A extends StatelessWidget {
final String _title;
...
On using public variable, you don't see error while assigning values to the named optional parameters like:
class AnyClass extends StatelessWidget {
final String title;
AnyClass({this.title}); // no error
}
But if you use private variable, like:
class AnyClass extends StatelessWidget {
final String _title;
AnyClass({this._title}); // Error: named optional parameters can't start with an underscore
}
Reason for the error:
Named/optional arguments with constructor shorthand leaks impl details, see more

Is a good practice pass Widgets as class argument in flutter?

I mean create a class like this:
class HighLightAnimationState extends State<HighLightAnimation> {
HighLightAnimationState(Card this.child, this._elevation, this._boxShadow);
final Card child;
final double _elevation;
final double _boxShadow;
#override
Widget build(BuildContext context) {
return this.child;
}
}
class HighLightAnimation extends StatefulWidget {
HighLightAnimation(Card this.child, [this._elevation = 1.0, this._boxShadow = 0.0]);
final Card child;
final double _elevation;
final double _boxShadow;
#override
createState() => new HighLightAnimationState(this.child, this._elevation, this._boxShadow);
}
It remarks on Card Widget and indicates "Don't type annotate initializing formals"
When I google it, I went redirected to https://www.dartlang.org/guides/language/effective-dart/usage, so, that's why I wanna know if the thing that I am doing is right.
It's OK to pass widgets to constructors, of course. Remove the type Card from Card this.child. That type is not wrong, just unnecessary, that's why you are getting the warning.
It should be:
HighLightAnimationState(this.child, this._elevation, this._boxShadow);
HighLightAnimation(this.child, [this._elevation = 1.0, this._boxShadow = 0.0]);

Understanding Dart private class [duplicate]

This question already has an answer here:
Dart: should the instance variables be private or public in a private class?
(1 answer)
Closed 4 years ago.
In Flutter we commonly have something like this:
class MyStatefulWidget extends StatefulWidget {
#override
_MyState createState() => _MyState();
}
class _MyState extends State<MyStatefulWidget> {
void doSomething() => print('hi');
#override
Widget build(BuildContext context) {
return Container();
}
}
So _MyState is declared with a _, which makes it library private.
So how come the Flutter render engine can use _MySate if it's sopposed to be private?
It's funny because I can access doSomething() from other files, but if I make it _doSomething(), I can't access it anymore...So how come I can access a public method from a private class, but I can't access a private method from a private class?
While _MyState is private, StatefulWidget and State are not.
The framework doesn't manipulate _MyState, it manipulates these lower layer that he has access to, with a well-defined prototype.
This basically sums up into:
StatefulWidget widget;
State foo = widget.createState();
foo.initState();
final newWidget = foo.build(this);
...

#override of Dart code

I noticed PetitParserDart has a lot of #override in the code, but I don't know how do they be checked?
I tried IDEA dart-plugin for #override, but it has no effect at all. How can we use #override with Dart?
From #override doc :
An annotation used to mark an instance member (method, field, getter or setter) as overriding an inherited class member. Tools can use this annotation to provide a warning if there is no overridden member.
So, it depends on the tool you use.
In the current Dart Editor(r24275), there's no warning for the following code but it should (it looks like a bug).
import 'package:meta/meta.dart';
class A {
m1() {}
}
class B extends A {
#override m1() {} // no warning because A has a m1()
#override m2() {} // tools should display a warning because A has no m2()
}
The #override annotation is an example of metadata. You can use Mirrors to check for these in code. Here is a simple example that checks if the m1() method in the child class has the #override annotation:
import 'package:meta/meta.dart';
import 'dart:mirrors';
class A {
m1() {}
}
class B extends A {
#override m1() {}
}
void main() {
ClassMirror classMirror = reflectClass(B);
MethodMirror methodMirror = classMirror.methods[const Symbol('m1')];
InstanceMirror instanceMirror = methodMirror.metadata.first;
print(instanceMirror.reflectee); // Instance of '_Override#0x2fa0dc31'
}
it's 2021 . the override it's optional
Use the #override annotation judiciously and only for methods where the superclass is not under the programmer's control, the superclass is in a different library or package, and it is not considered stable. In any case, the use of #override is optional. from dart api https://api.dart.dev/stable/2.10.5/dart-core/override-constant.html
example
Class A {
void say (){
print ('Say something 1') ;
}
}
Class B extends A {
#override
void adds() { // when i don't type the same name of super class function show an
// warning not an error say 'The method doesn't override an inherited
// method.' because it's not same name but when type the same name must be
// overriding
print ('Say something 2 ')
}
Update : the main use of #override is when try to reach abstract method inside abstract class in sub class that inherited to the abstract super class . must use #override to access the abstract method .

Resources