This question already has answers here:
What is the difference between named and positional parameters in Dart?
(7 answers)
Closed 4 years ago.
I have this constructor in my class. Now when it's like this, I get
The type parameter icon is annotated with #required
but only named parameters without default value can be annotated with it.
-
const Category(
#required this.name,
#required this.icon,
#required this.color
) : assert(name != null),
assert(icon != null),
assert(color != null);
And when calling the constructor like this:
Category(name: _categoryName, icon: _categoryIcon, color: _categoryColor),
It's an error.
All of this goes away when I surround my constructor arguments with {}.
What does this mean?
{} are missing to make them named parameters
const Category({
#required this.name,
#required this.icon,
#required this.color
}) : assert(name != null),
assert(icon != null),
assert(color != null);
or just remove #required
Without {} they are positional parameters which are required anyway.
Category('foo', someIcon, Colors.white)
vs
Category(name: 'foo', icon: someIcon, color: Colors.white)
[] makes them optional positional parameters.
Positional (non-optional) need to be declared first, optional parameters come at the end.
Optional positional and optional named parameters can not be used together.
Optional parameters (positional and named) can have default values
this.name = 'foo'
Default values need to be compile-time constants.
You have used named optional arguemnts but your constructor accept postional optional parameter.
named optional parameter {}:
Use to omit/avoid arguments and for readability.
argument position doesnt matter since refer using name.
Since you can avoid the argument, to denote that this argument is required use #required. Most of the time this annotation use to say this is cannot avoid(like a notice).
const Category({
#required this.name,
#required this.icon,
#required this.color
}) : assert(name != null),
assert(icon != null),
assert(color != null);
//Category(name: _categoryName, icon: _categoryIcon, color: _categoryColor),
positional optional parameter []:
Also use to avoid or omit args.
Cannot mention name because of that no readability(as a example for boolean params).
Argument position matters.
No need of #required because we must provide args.
const Category(
this.name,
this.icon,
this.color
) : assert(name != null),
assert(icon != null),
assert(color != null);
//Category(_categoryName, _categoryIcon, _categoryColor),
Read more from this SO answer.
#required is a hint that some value should be passed as an argument to this parameter, even if it's just the default.
This hint only makes sense when used with optional parameters, such as when you surround the parameters with braces, because otherwise arguments are mandatory anyways (like what you would be used to in e.g. java.
Naming is a bit unfortunate here but named parameters in dart also mean they're optional, you can call a function without any of them.
Related
I have the following basic class with its constructor in Dart:
class ChartData {
String? name;
Color? color;
Duration? duration;
ChartData(
String name, List rgbo, Duration duration) {
this.name = name;
this.color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]);
this.duration = duration;
}
}
How can I make it so that the constructor arguments are required, and the class arguments are non-nullable thus don't need any null safety? I'm aware of the keyword required, but from what I understand it works only for initializing formal class constructors.
How could we use initializing formal for this class, especially regarding constructing the color class argument?
First of all, you should use an initializer list to initialize the fields, not do assignments in the constructor body. Dart is like C++ in that regard, not Java.
class ChartData {
final String name;
final Color color;
final Duration duration;
ChartData(String name, List<int> rgbo, Duration duration)
: this.name = name,
this.color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]),
this.duration = duration;
}
This change allows your fields to be final and non-nullable, because now they are initialized before they can ever be read. Your arguments are required. They already were, but they still are.
If you want to use initializing formals, and you do, you can replace an initializer list entry of the form this.name = name (or name = name, because the this is already optional) with a parameter of the form this.name:
class ChartData {
final String name;
final Color color;
final Duration duration;
ChartData(this.name, List<int> rgbo, this.duration)
: color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]);
}
The color parameter cannot be an initializing formal because it doesn't store the argument directly into the field. Just keep that as an initializer list entry instead.
This works, the fields are final and non-nullable, the parameters are required and non-nullable, and you use initializing formals where possible.
You asked about required. That modifier works with named parameters, and your parameters are positional.
If you wanted them to be named instead, you could write it as:
class ChartData {
final String name;
final Color color;
final Duration duration;
ChartData(
{required this.name, required List<int> rgbo, required this.duration})
: color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]);
}
The {...} surrounding the parameters makes them named. Required named parameters need a required in front, named parameters default to being optional.
Whether you like required named parameters or not is a matter of taste. Some hate writing and reading the extra name, others prefer it because they find it easier to read.
Either version works.
To set the arguments to non-null, you must add required to each argument in a constructor.
If you want to initialize the arguments, you could call the class and set the values. Also you can initialize in some initState()
For example:
class ChartData {
String name;
Color color;
Duration duration;
ChartData({
required this.name,
required this.color,
required this.duration
});
}
class OtherClass extends StatelessWidget {
//initialize
final chartData = ChartData(
name: "name1",
color: Color.fromRGBO(38, 38, 38, 0.4),
duration: const Duration(seconds:15));
#override
Widget build(BuildContext context) {
return Container();
}
}
can somebody explain why
class SaveGlove {
final String serialNumber;
final String productionDate;
SaveGlove(this.serialNumber, this.productionDate);
SaveGlove.fromJson(Map<String, Object?> json)
: this(
serialNumber: json['serialNumber']! as String,
productionDate: json['prductionDate']! as String,
);
Map<String, Object?> toJson() {
return {
'serialNumber': serialNumber,
'prductionDate': productionDate,
};
}
}
doesn't work but when I change parameter in constructor like that:
SaveGlove({required this.serialNumber, required this.productionDate});
it works?
Your original code doesn't work because your constructor is declared to take two positional arguments,
SaveGlove(this.serialNumber, this.productionDate);
but you are calling it with named arguments:
: this(
serialNumber: json['serialNumber']! as String,
productionDate: json['prductionDate']! as String,
);
(This is a redirecting generative constructor, which tries to redirect to the SaveGlove constructor by passing it two named arguments.)
That doesn't work, positional parameters need positional arguments.
If you had written the redirecting constructor as:
: this(
json['serialNumber']! as String,
json['prductionDate']! as String,
);
then it would have worked.
Changing the constructor to take two named parameters also makes the redirection be valid.
It is because Null Safety is added in Dart. In simple words, Null Safety means a variable cannot contain a ‘null’ value unless you initialized with null to that variable. All the runtime null-dereference errors will now be shown in compile time with null safety.
So as you are initializing variables serialNumber & productionDate you have two options:
Either make it compulsory to provide those variables values from constructor by adding required keyword.
class SaveGlove{
String serialNumber;
final String productionDate;
SaveGlove({required this.serialNumber, required this.productionDate});
}
Or declare those variables as nullable, i.e which can accept null values. So you don't need the required keyword:
class SaveGlove{
String? serialNumber;
String? productionDate;
SaveGlove({this.serialNumber,this.productionDate});
}
I am trying to figure out how to pass a null argument in the constructor, but I am getting this error:
Don't explicitly initialize variables to null
class Dog {
final id int;
final String name;
final int age;
Dog({this.id=null, this.name, this.age});
}
I don't want to pass an id to the constructor. I want to call the constructor like this:
var dog = Dog(
name: 'Rex',
age: 15,
);
How do I accomplish this?
By not explicitly assigning to null
class Dog {
final id int;
final String name;
final int age;
Dog({this.id, this.name, this.age});
}
Remember, be default value of id is set to null. So if the consumer doesn't pass a value for id it will continue to have null and so will name
If you want to make any parameter mandatory then you should mark that with #required
If you don't set variable the default value will be null.
In my application, I use these 2 classes but I don't know which one I should prioritize.
Image.asset('icons/heart.png')
AssetImage('icons/hear.png')
Maybe there is one who fetches the image faster.
Image is a StatefulWidget and Image.asset is just a named constructor, you can use it directly on your widget tree.
AssetImage is an ImageProvider which is responsible for obtaining the image of the specified path.
If you check the source code of the Image.asset you will find that it's using AssetImage to get the image.
Image.asset(String name, {
Key key,
AssetBundle bundle,
this.semanticLabel,
this.excludeFromSemantics = false,
double scale,
this.width,
this.height,
this.color,
this.colorBlendMode,
this.fit,
this.alignment = Alignment.center,
this.repeat = ImageRepeat.noRepeat,
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
String package,
this.filterQuality = FilterQuality.low,
}) : image = scale != null
? ExactAssetImage(name, bundle: bundle, scale: scale, package: package)
: AssetImage(name, bundle: bundle, package: package),
assert(alignment != null),
assert(repeat != null),
assert(matchTextDirection != null),
super(key: key);
Thanks #diegoveloper
From flutter version 2.5, it is recommended to use the Image StatefulWidget with the const modifier which is impossible with Image.asset. However, you'll need to provide the image path as a parameter to the AssetImage object, where this object is the value of the named parameter 'image' of the Image StatefulWidget, like so.
Image(
image: AssetImage('asset/dice1.png'),
)
From the recommended Dart tutorial book Dart Apprentice const and final modifiers on objects reduce subsequent compile-time and runtime.
Therefore for clean and few lines of code, use Image.asset, but for fast and CPU-friendly code, use Image StatefulWidget.
Background: I'm trying to inherit from AnimatedCrossFade to apply this patch https://github.com/flutter/flutter/issues/10243 as a subclass (rather than forking flutter). I'm just learning dart/flutter, and honestly I thought that creating a cross-fade from a loading widget to a network image would have been a really simple thing to try first (it's not easy at all, FadeInImage doesn't crossfade nor does it take a widget [despite the design goal of nearly everything in flutter being a widget],Image.network does not have a onDownloadCompleted callback, and AnimatedCrossFade has the aforementioned bug with centering). Anyway...
Here's the code I'm calling:
class FixedCrossFade extends AnimatedCrossFade {
const FixedCrossFade({
Key key,
#required firstChild,
#required secondChild,
firstCurve: Curves.linear,
secondCurve: Curves.linear,
sizeCurve: Curves.linear,
alignment: Alignment.topCenter,
#required crossFadeState,
#required duration,
layoutBuilder: AnimatedCrossFade.defaultLayoutBuilder,
}) : super(
key,
firstChild,
secondChild,
firstCurve: firstCurve,
secondCurve: secondCurve,
alignment: alignment,
crossFadeState: crossFadeState,
duration: duration,
layoutBuilder: layoutBuilder
);
}
For reference, this is AnimatedCrossFade's constructor:
const AnimatedCrossFade({
Key key,
#required this.firstChild,
#required this.secondChild,
this.firstCurve: Curves.linear,
this.secondCurve: Curves.linear,
this.sizeCurve: Curves.linear,
this.alignment: Alignment.topCenter,
#required this.crossFadeState,
#required this.duration,
this.layoutBuilder: defaultLayoutBuilder,
}) : assert(firstChild != null),
assert(secondChild != null),
assert(firstCurve != null),
assert(secondCurve != null),
assert(sizeCurve != null),
assert(alignment != null),
assert(crossFadeState != null),
assert(duration != null),
assert(layoutBuilder != null),
super(key: key);
My FixedCrossFade class errors with:
error: line 33 pos 8: invalid arguments passed to super class constructor 'AnimatedCrossFade.': 3 passed, 0 expected
Where line number 33 corresponds to the line }) : super(
I'm not actually changing the constructor, I believe all I need to do is overrride createState, and completely reimplement the state object. Coming from a python / C++ background, I was quite surprised that extending AnimatedCrossFade without any changes causes an error:
class FixedCrossFade extends AnimatedCrossFade {}
...
No constructor 'FixedCrossFade' declared in class 'FixedCrossFade'
I'm very very new to dart and flutter, so this is probably a very simple mistake. Any help is appreciated!
As you noticed, the super-constructor has only named parameters, but you are passing key, firstChild and secondChild without a name, so they are positional arguments. Change those to:
}) : super(
key : key,
firstChild: firstChild,
secondChild: secondChild,
firstCurve: firstCurve,
and the super-invocation will work.
You need to add a constructor because constructors are not inherited. They are not instance methods, they are rather more like static methods which are also not inherited. So, for your class to have any constructor, it needs to declare it, and then call a suitable generative super-constructor to create the superclass. It's, admittedly, annoying when all you do is forward arguments.