Dart initializer in constructor [duplicate] - flutter

This question already has an answer here:
Is there a difference in how member variables are initialized in Dart?
(1 answer)
Closed 9 months ago.
It looks easy, but not working. I have model in Dart like this:
class FormTab {
String caption;
FormTab(dynamic m) { // where m will be Map
this.caption = m['caption'] ?? "No caption";
}
}
But still I have error message: Non-nullable instance field 'caption' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
What is wrong? I set value caption, but still I have error. I tried caption

The body of a constructor in Dart is not part of the initializers. You need to put that into the initializer list:
class FormTab {
String caption;
FormTab(dynamic m) : caption = m['caption'] ?? "No caption";
}
Please note that if you know it's going to be a map, it might be better to make it a map. The earlier you switch from dynamic to actual types, the easier it is to catch errors.

Related

checking variable null-safety with ! and? [duplicate]

This question already has answers here:
What is Null Safety in Dart?
(2 answers)
Closed 11 months ago.
I trying to understand the basics of null-safety in dart
what is the best use for this:
// model
class MyModel {
String? name;
MyModel({this.name})
}
// view-controller
MyModel? response;
// do some async operations here, on success response get a value
if(response!.name == null){
}
if(response?.name == null){
}
// what is the best practice? and what should i use in this case?
// ! or ?
Go through this codelab excersie and you will get with basics of using '?' vs '!'.
For reference I am explaining both a bit:
suppose you want to have a string variable which could be, at any point null or can be used to store null value. For this case you can't use String to initialize your variable, instead you need to do it like this way :-
String? str
And now the '!' part which is called 'null assertion operator'. Sometimes flutter sdk thought that maybe any variable you have used might be null at runtime and so it throws you error that the object is nullabe. So for that case if you are sure that, the object could never be null at runtime so you need '!' operator to show flutter that it couldn't never be null.
If you have any confusion then do check that codelab exercise for sure.

Flutter class error , Try adding an initializer expression, or add a field initializer in this constructor, or mark it [duplicate]

This question already has an answer here:
How do I initialize non-nullable members in a constructor body?
(1 answer)
Closed 1 year ago.
Hi I'm trying to create generic API response class in flutter application and I'm getting this error
class ApiResponse<T> {
Status status;
T data;
String message;
ApiResponse.loading(this.message) : status = Status.LOADING;
ApiResponse.completed(this.data) : status = Status.COMPLETED;
ApiResponse.error(this.message) : status = Status.ERROR;
#override
String toString() {
return "Status : $status \n Message : $message \n Data : $data";
}
}
enum Status { LOADING, COMPLETED, ERROR }
IDE complains about below error
Non-nullable instance field 'data' must be initialized.
Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'
Could anyone tell me what is wrong wiht my code?
It is because like the error says, data field has a non-nullable type T. If you want to allow null for the field data, you will need to make its type nullable by putting a ? like so.
T? data;
Similarly, you will also need to make message field nullable.
String? message;
To see other ways you can go about this and to understand null-safety better, I'd suggest reading this.

Understanding Dart/Flutter Constructors with final Variables [duplicate]

This question already has answers here:
Difference between assigning the values in parameter list and initializer list
(2 answers)
Closed 1 year ago.
This code snippet
class SomeWidget extends StatelessWidget {
final String aString;
SomeWidget(this.aString);
compiles without error or warning. However, this code snippet
class SomeWidget extends StatelessWidget {
final String aString;
SomeWidget(String inputString) {
this.aString=inputString;
}
gives an error message that all final variables must be initialized and aString isn't, and how aString can't be used as a setter because it's final. Removing the final keyword eliminates the error messages.
I'm unclear what's going on here. I saw this and this SO item, but honestly I'm still struggling to understand. I think the problem, for me, stems from how I was taught my two code snippets are functionally identical.
When you declare a variable as final, this means that the state\value of this variable will not change during the life cycle of this widget.
Thus, when you declare:
final String aString;
You are telling the framework, that the value of aString, will not change, because it's final. However, when you use the setter, you are trying to do the exact opposite of what you just promised Flutter, and you are attempting to change what should be final = aka non-changeable.

The argument type 'String?' can't be assigned to the parameter type 'String'

when I upgrade my flutter to 2.0.1, shows this error:
The argument type 'String?' can't be assigned to the parameter type 'String'.
this is my code:
enum SubStatus {
SUB,
UNSUB,
}
extension ResponseStatusExtension on SubStatus{
static const statusCodes = {
SubStatus.SUB: "sub",
SubStatus.UNSUB: "unsub",
};
String? get statusCode => statusCodes[this];
}
This is how to use it:
String url = "/post/sub/source/" + subStatus.statusCode + "/" + channelId;
this is the error UI:
what should I do to fix it? I tried to return String but in the enum code tell me should return String?:
what should I do?
Change the return type of statusCode to String and provide a default value.
String get statusCode => statusCodes[this] ?? '';
When accessing a map, there is a chance that you will get a null return value if the key does not exist in the map. Simply providing a default value will allow this code to compile. That default value should never be used unless you add something to the enum without adding a value to the map as well.
Edit:
After the comment from #Christopher Moore, I realized my mistake. So, I am going to directly use his solution over here as it is the correct one.
This is because of the new null-safety feature of Dart.
You will need to make the following change in the code and it will work:
String get statusCode => statusCodes[this] ?? '';
With new null-safety rules, the following data-type? x, the data type is followed by a question mark, means that the value x can be null. However, without the '?', it means that data-type x, it cannot be null.
So, basically String and String? are two different data types. That is why you get the error.
You can learn more here.
restart analysis server
add !
like this
subStatus.statusCode!

Dart Class with ":" vs Dart Class without [duplicate]

I have a class that I am creating that looks like this:
class Movie {
final String title, posterPath, overview;
Movie(this.title, this.posterPath, this.overview);
Movie.fromJson(Map json) {
title = json["title"];
posterPath = json["poster_path"];
overview = json['overview';
}
}
I am getting a warning that says that "The final variables 'overview', 'posterPath', & '1' more must be initialized. There are also warnings around each variable saying 'title' can't be used as a setter because it is final.
When I write the constructor using this syntax, the warnings go away:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
What exactly is going on here?
Dart objects must be fully initialized before anyone gets a reference to the new object. Since the body of a constructor can access this, the object needs to be initialized before entering the constructor body.
To do that, generative Dart constructors have an initializer list, looking similiar to C++, where you can initialize fields, including final fields, but you cannot access the object itself yet. The syntax:
Movie.fromJson(Map json)
: title = json["title"],
posterPath = json["poster_path"],
overview = json['overview'];
uses an initializer list (the list of assignments after the :) to initialize the final instance variables title, posterPath and overview.
The first constructor uses an "initializing formal" this.title to directly put the parameter into the field.
The constructor
Movie(this.title, this.posterPath, this.overview);
is effectively a shorthand for:
Movie(String title, String posterPath, String overview)
: this.title = title, this.posterPath = posterPath, this.overview = overview;
Your constructor can combine all of these and a body:
Movie(this.title, this.posterPath, String overview)
: this.overview = overview ?? "Default Overview!" {
if (title == null) throw ArgumentError.notNull("title");
}
(A const constructor cannot have a body, but it can have an initializer list with some restrictions on the allowed expressions to ensure that they can be evaluated at compile-time).
Dart separates properties initialization from the constructor body.
A constructor has 3 parts :
the name/parameters definition
properties initialization/super call/asserts
A body, similar to a function immediately run on construction
Both the initialization and body parts are optional.
final variables must be initialized on the first 2 parts. They cannot be initialized inside the body.
A full constructor will look like the following :
MyClass(int value)
: assert(value > 0),
property = value,
super();
{
print("Hello World");
}
The main purpose of this initializer part is for body-less constructors which allows const constructors, a dart specific feature. See How does the const constructor actually work? for more details on these.
I just found some documentation around this, & it seams that the second version with the : is what's called the "initializer list" which allows you to initialize instance variables before the constructor body runs.
There is more detail around this in the documentation here.