The code is part of this class
class Category extends StatelessWidget {
final String name;
final ColorSwatch color;
final IconData iconLocation;
And the use of required is this:
const Category({
Key key,
#required this.name,
#required this.color,
#required this.iconLocation,
}) : assert(name != null),
assert(color != null),
assert(iconLocation != null),
super(key: key);
The use of Key key also confuses me.
The #required annotation indicates that the parameter is a required parameter (i.e an argument needs to be passed to the parameter).
You can instead create the function parameters without using the optional parameter syntax which implicitly makes it a required.
ie This
Category(
this.name,
this.color,
this.iconLocation,
)
Instead of
Category({
Key key,
#required this.name,
#required this.color,
#required this.iconLocation,
})
Why use the optional parameter syntax together with the #required annotation?
The major benefit of doing it this way is readability! It helps when passing values to your widget fields since you don't have to guess the position of the parameters.
according to Dart's Language tour
Flutter instance creation expressions can get complex, so widget constructors use named parameters exclusively. This makes instance creation expressions easier to read.
When you are creating object this keyword #required makes it required(needed).
Dart Language Tour
A function can have two types of parameters: required and optional. The required parameters are listed first, followed by any optional parameters. Named optional parameters can also be marked as #required. See the next section for details.
read about required
Related
I have this little class:
class WidgetToImage extends StatefulWidget {
final Function(GlobalKey key) builder;
const WidgetToImage({Key? key, #required this.builder}) : super(key: key);
#override
_WidgetToImageState createState() => _WidgetToImageState();
}
This chunk of code won't compile because anybody can pass a null value for the builder parameter when constructing the WidgetToImage widget. I know I could make the builder nullable but this is not what I want because later I must be checking if it is null, etc. and semantically it doesnt make any sense. A valid builder must be always passed.
Is there any way to annotate this in dart to avoid converting builder property to a nullable type?
If you use Dart version 2.12, you get null safety as a language feature.
It seems you are already using that since your code contains Key?, which is the null-safety way of writing "nullable".
On the other hand, your this.builder parameter should have been marked as required (a keyword in null safe code) instead of the older #required annotation, so it doesn't look like valid null safe code.
The code should read:
class WidgetToImage extends StatefulWidget {
final Function(GlobalKey key) builder;
const WidgetToImage({Key? key, required this.builder}) : super(key: key);
#override
_WidgetToImageState createState() => _WidgetToImageState();
}
and then it's a compile-time error for null-safe code to pass null as an argument to builder.
(Older non-null-safe code can still get away with passing null, but they're asking for trouble then.)
You can add an assertion:
const WidgetToImage({Key? key, required this.builder})
: assert(builder as dynamic != null),
super(key: key);
that will tell people developing against your library to not pass in null from non-null-sound code, but only while developing with assertions enabled.
I have this method
void doSomething<T>() { ... }
and a variable of type T
T someVar = ...;
how can I use doSomething method to perform an action on someVar, something like this?
doSomething<someVar.Type>();
in fact, I want to access Type T form variable.
here is the example
class BlocManagerProvider extends StatefulWidget {
const BlocManagerProvider({
#required this.child,
#required this.blocs,
Key key,
}) : super(key: key);
final Widget child;
final List<Cubit<Object>> blocs;
#override
_BlocManagerProviderState createState() => _BlocManagerProviderState();
}
class _BlocManagerProviderState extends State<BlocManagerProvider> {
#override
Widget build(BuildContext context) => widget.child;
#override
void dispose() {
for (final Cubit<Object> bloc in widget.blocs) {
BlocManager.instance.dispose<type>();
}
super.dispose();
}
}
Future<void> dispose<T extends Cubit<Object>>() async {
final String objectKey = _getKey<T>(key);
if (_repository.containsKey(objectKey)) {
await _repository[objectKey].close();
_repository.remove(objectKey);
await removeListener<T>(key);
}
}
Dart does not provide a way to go from an object of type X to a type variable bound to X. There are good technical reasons for not allowing that (it allows the web compilers to know at compile-time which types can ever be bound to a type variable, which allows it to reduce the compiled code).
The dispose method is treating the type argument as its only argument and acting on the value of that type argument.
It makes me think you're trying to do something that the language is not designed for.
You're passing in a type argument, and then the code inspects that type of argument and behaves differently depending on the value. That's not what's usually meant by being "generic" - to act the in the same (generic) way independently of the types, so the only real effect of passing a type is to make the return type match the argument type.
(That's why Java can erase type arguments at run-time).
So, if you need to know a type for some object, either that object must provide it for you, or you have to store it from earlier (perhaps when the object was created).
So, if you really need to access the type argument that the cubit is implementing Cubit<X> of, the Cubit class needs to make it available to you. That will usually be with a method with a callback (like a visitor), something like:
abstract class Cubit<T> ... {
...
R visit<R>(R Function<C extends Cubit<T>, T>(C value) action);
}
class SomeCubit<T> extends Cubit<T> {
...
R visit<R>(R Function<C extends Cubit<T>, T>(C value) action) =>
action<SomeCubit<T>, T>(this);
}
If something like that's available, then you can do what you want as:
bloc.visit(<C extends Cubit<T>, T>(_) => BlocManager.instance.dispose<C>());
If something like that is not available, then you are in trouble.
You can detect a number of known types, with a bunch of if statements, but that's unlikely to be sufficient.
That means you need to remember the type from earlier, but since it looks like you just get a List<Cubit<Object>> that has already been created, that doesn't seem practical either.
If the BlocManager is your own class, consider changing it to use Type objects instead of type arguments (which is contrary to everything I usually say you should do), because then you can call ..dispose(bloc.runtimeType). I'd prefer to avoid that, but if other constraints make what you do impossible, then it might be the lesser evil.
void main() {
foo(bar: 1);
}
void foo({#required int bar}) {} // Error
Error:
The parameter 'bar' can't have a value of 'null' because of its type, and no non-null default value is provided.
I am annotating bar with #required and it is also non-nullable. That means I'll always have to provide bar a non-null value. So, why does the compiler ask me to provide a default value?
#required is the old annotation tag coming from the meta package and was introduced as a way to give warnings from the analyzer. With NNBD this has been changed to a keyword called required. You can read more about this keyword in the following link:
https://dart.dev/null-safety/understanding-null-safety#required-named-parameters
I've created a small app to add items in list, however when i delete something from list, it gets deleted successfully but ListView.builder doesn't show correct values. i know its something related to keys given to class but i'm pretty new in flutter so don't know how to do that.
Gist: https://gist.github.com/OculusMode/213052325ec725aad3ab92c73599b187
Thanks in advance.!
Add this to constructor of your Widget:
:super(key:new ObjectKey(_data))
Example:
class TodoTile extends StatefulWidget {
String _data;
int _index;
ValueChanged<int> onDelete;
TodoTile(this._data,this._index,{ #required this.onDelete , Key key}):super(key:new ObjectKey(_data));
TodoTileState createState() {return new TodoTileState(_data, _index,this.onDelete);}
}
Not sure if this would cause problems too but I've also changed widget.onDelete to onDelete (passing the function pointer to the state too)
Source:
https://flutter.io/widgets-intro/#keys
TL;DR: Named parameters are optional as a result of a conscious design choice. Short of having official language support, is there any way to enforce (and inform) required named arguments?
I find it extremely useful to use named parameters when defining a class. Take, for instance, an Ability in an MMORPG:
class Ability {
final name;
final effectDuration;
final recast; // wait time until next use
// ...
}
effectDuration and recast both carry the same type of information (i.e. duration of time) and are likely represented by the same datatype. It is easy to mix up which number goes where. However, they are both information vital to the correctness of the object, so they can't be missing during instantiation.
I could just break the program via a try-catch to enforce the requirement of those parameters, but that doesn't sound like fun for someone who uses the class and has no idea (short of reading the docs and understanding intuitively what the class does) that they are required.
Is there any way to enforce the requirement of certain named parameters while managing to inform the caller of said requirement and/or help them use it correctly?
The meta package provides a #required annotation that is supported by the DartAnalyzer.
Flutter uses this a lot and provides #required directly from import 'package:flutter/foundation.dart'
foo({#required String name}) {...}
foo(); // results in static warning
#required doesn't check if the passed value is null or not, only that a value was actually passed on the call site.
To check for null you can also use assert() to check for passed values
class Ability {
Ability(this.name, this.effectDuration, this.recast) : assert(name != null), assert(effectDuration != null), assert(recast != null);
final name;
final effectDuration;
final recast; // wait time until next use
// ...
}
[Update] New as-of Dart 2.0
In dart 2.0 the required keyword has been added to the language as part of the null-safety update. This means that you get a compiler-enforced non-null value rather than one checked by the analyzer; this makes the null check completely redundant.
This means that this code does effectively the same as the old code below, except that you never have to worry about the assertion throwing as the values for name, effectDuration, and recast cannot be null.
class Ability {
final String name;
final Duration effectDuration;
final bool recast;
final String? description;
Ability({
required this.name,
this.effectDuration = Duration(seconds: 1),
this.recast = false,
this.description,
});
}
Before Dart 2.0
Yes, there is!
Here's an example:
class Ability {
final String name;
final Duration effectDuration;
final bool recast;
final String description;
Ability({
#required this.name,
this.effectDuration = new Duration(seconds: 1),
this.recast = false,
this.description,
}):
assert(name != null),
assert(effectDuration != null);
}
You don't have to assert that name is not equal to null, but it might be useful for you.
Although you could use the flutter foundation package as described in the accepted answer, when I am working with model classes that don't need to know about Flutter, I prefer to use the meta package directly. That way it doesn't create an unnecessary dependency on the framework. This allows you to share the Dart code even outside of Flutter.
Add meta to pubspec.yaml:
dependencies:
meta: ^1.1.7
Import it in your class file:
import 'package:meta/meta.dart';
Use the #required annotation in your code:
class Person {
String name;
int age;
Person({#required this.name, this.age,});
}
So name is a required parameter, but age isn't.
final person = Person(name: 'Bob');
Update:
In an upcoming version of Dart, the required keyword should be added by default, so no imports will be necessary at all.
As of 2.12 with null safety you can use required keyword (not #required). Also no need to import any additional packages.
In this example named parameter name is optional while effectDuration and recast are required.
class Ability {
final name;
final effectDuration;
final recast;
Ability({this.name, required this.effectDuration, required this.recast});
}
Update pubspec.yaml, for example:
environment:
sdk: ">=2.12.0-0 <3.0.0"
References:
Sound null safety
How does #required compare to the new required keyword?
With null safety:
Non-nullable named parameter:
You need to either mark the named parameter required or provide a default value or even mark it late. For example:
class Foo {
final int a;
final int b;
late final int c; // Mark late and provide value later.
Foo({
required this.a, // Mark required.
this.b = 0, // Provided a default value.
});
}
Nullable named parameter:
You don't need anything special to handle them.
class Foo {
final int? z;
Foo({
this.z,
});
}
If you want declare to a empty variable but that has methods inside , you can:
1)Use the late keyword
2)Declare the type like possible null returned example: int? number;
3)Initialize the variable empty, for example :
List listOfNumbers = [];
Map mapOfPerson1 = {};
And so you can use the methods of the variable to add them values