My Code
class Book {
String title;
String author;
int numOfPages;
Book(String title, String author, int pages) {
this.title = title;
this.author = author;
this.numOfPages = pages;
}
}
void main() {
Book bk = Book("Modern Operating Systems", "S.Tannabeaum", 1250);
print(bk.title);
}
Hey, I'm pretty a newbie to dart and programming. Here actually I wanted to make a class and it's constructor and three instances within it. And when I wanted to make an object from this class, I caught up with this error!
My code's error message!
I think something is wrong with my code, any help would be appreciable:)
There are two problems in your code. First, constructors in Dart has two "phases" where you first initialize the object and then runs the constructor body before returning the object to the caller of the constructor.
That means that you are here creating a Book object first without setting the three variables. Yes, you are setting these variables later in the constructor body but at that time it is too late.
The next problem is that if you are not setting value for a variable in Dart it will always default to the value null. With Dart 2.12, we got non-nullable types by default (NNBD) which mean all types in Dart does not allow the value null unless specified. You specify the validity of the null value by typing a ? after the name of the type. E.g. String? allows a variable to point to a String object, or null.
In this case, we don't need to specify nullable types since the problem is mostly you need to move the initialization of the variables from the constructor body in to initialization phase of the object like this:
class Book {
String title;
String author;
int numOfPages;
Book(String title, String author, int pages)
: this.title = title,
this.author = author,
this.numOfPages = pages;
}
The same can be rewritten as the following which is also the recommended way to do it:
class Book {
String title;
String author;
int numOfPages;
Book(this.title, this.author, this.numOfPages);
}
Since we are here just directly referring to each field we want to give a value. Dart will then automatically assign the values with the parameters from the constructor.
If your constructor takes a lot of arguments, it might be more readable to use named arguments. The required keyword here means that we most provide a given named parameter. If not specified, the named argument is optional (which means we most provide a default value or allow null for our parameter to be valid):
class Book {
String title;
String author;
int numOfPages;
Book({
required this.title,
required this.author,
required this.numOfPages,
});
}
void main() {
final book = Book(
title: "Modern Operating Systems",
author: "S.Tannabeaum",
numOfPages: 1250,
);
print(book.title); // Modern Operating Systems
}
Related
I've created my class in Dart this way, but I'm getting the Non-nullable instance field 'text' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'. I would like to know if there's a way to do it in a 'Python' style where this kind of class creation is possible, thank you in advance.
class Lexer {
String _text;
int _pos;
String _current_char;
Lexer(String text) {
this._text = text;
this._pos = -1;
this._current_char = '';
this.advance();
}
void advance() {
this._pos++;
this._current_char = this._pos < this._text.length ? this._text[this._pos] : '';
}
}
class Lexer {
String _text;
int _pos;
String _current_char;
This declares several members with type String. Since they are declared as String and not as String?, these members are non-nullable; they are not allowed to ever be null. (This is part of the new null-safety feature from Dart 2.12.)
Dart initializes objects in two phases. When the constructor's body runs, Dart expects all member variables to already be initialized. Because your members are non-nullable and haven't been initialized to non-null values yet, this is an error. The error message explains what you can do:
Non-nullable instance field 'text' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
Use initializer expressions. This means using an initializer list:
Lexer(String text)
: _text = text,
_pos = -1,
_current_char = '' {
advance();
}
Note that if you're initializing members with a construction parameter of the same name, you can use shorthand:
Lexer(this._text)
: _pos = -1,
_current_char = '' {
advance();
}
Adding field initializers. This means initializing members inline in the class declaration.
class Lexer {
String _text = '';
int _pos = -1,
String _current_char = '';
Marking your members as late. This means that you promise that the variables will be initialized before anything attempts to use them.
class Lexer {
late String _text;
late int _pos,
late String _current_char;
Making your members nullable, which allows them to be implicitly null by default:
class Lexer {
String? _text;
int? _pos,
String? _current_char;
However, that will require that all accesses explicitly check that the members aren't null before using them.
You also might want to read: Dart assigning to variable right away or in constructor?
I am new to dart and I have some basicaly question to the language itself.
During the last days I started with classes in dart.
Now I have a short question about how to declare a class correct.
void main() {
Book harryPotter =
Book(title: "Goblet of Fire", author: "J. K. Rolling", pageCount: 300);
print(harryPotter._title); // 1 -> print "A" to the console
print(harryPotter._author); // 2 -> LateInitializationError: Field '_author#18448617' has not been initialized.
}
class Book {
String _title = "A";
late String _author;
late int _pageCount;
Book(
{required String title,
required String author,
required int pageCount}); // 3
}
Why can I access to the variable even if it's set to private?
Why does the late keyword throw an error, the variable is set during the constructor call?
Do I need to write in the constructor "Book({required String this.title});", or "Book({required String title});" like in the example? If it doesn't matter, why?
Thanks for helping!
Benjamin
Your constructor is not initializing the variables!
It should be:
Book({required String title, required String author, required int pageCount})
: _title = title,
_author = author,
_pageCount = pageCount;
Without that, the _author field is not set at all, and reading an unset late field is an error.
You can't use this.something because the fields have private names (_author) and named parameters cannot have private names. Otherwise that would have been the correct approach. Instead you need to have public-named parameters and then use the value to initialize the field in an initializer list.
With that change, the fields also don't need to be late and can instead be final:
class Book {
final String _title;
final String _author;
final int _pageCount;
Book({required String title, required String author, required int pageCount})
: _title = title,
_author = author,
_pageCount = pageCount;
}
You can access the private variables from inside the same library because Dart privacy is library based.
The following code does not compile with sound null safety because it is possible to pass null to the constructor which initializes a non-nullable field myString.
class MyClass {
String myString;
MyClass({#required this.myString});
}
I would expect that adding a question mark after this.myString would solve the problem, but it doesnt and another compile error is shown.
A default value is no option for me and it seems that the only other solution is something like this:
class MyClass {
late String myString;
MyClass({#required myString}) {
this.myString = myString;
}
}
Imo this decreases readability if there are a lot of parameters. Is there a more convenient solution which suppports initialization with this. in named constructors?
For non-nullable types, either use required or provide a default value. You can also use late but make sure to provide a value at some later point before using it. It's like a bang operator.
Example:
class Foo {
// All are non-nullable.
final int a;
final int b;
late final int c; // I trust you that you'll provide me a value later.
Foo({
required this.a, // <-- Mark it required
this.b = 0, // <-- or provide a default value.
});
}
If i am not getting the idea wrong, if you want to have a String param which is nullable from the constructor, you can declare a 'String?' type.
class MyClass {
String? myString;
MyClass({required this.myString});
}
Although I thought being familiar with programming language Dart, i stumbled upon this syntax in an example for Bloc:
class AuthenticationState extends Equatable {
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
this.user = User.empty,
});
const AuthenticationState.unknown() : this._();
const AuthenticationState.authenticated(User user)
: this._(status: AuthenticationStatus.authenticated, user: user);
const AuthenticationState.unauthenticated()
: this._(status: AuthenticationStatus.unauthenticated);
final AuthenticationStatus status;
final User user;
#override
List<Object> get props => [status, user];
}
I know how to define a class constant and a const constructor.
However, why is the classname prefixed here everywhere?
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
this.user = User.empty,
});
That's a named constructor. In dart you can define constructors in two ways, either using ClassName or ClassName.someOtherName.
Eg: Consider you have a class called person with 2 variables, name and carNumber. Everyone has a name but carNumber is not necessary. In that situation, if you implement the default constructor, you have to initialise it like:
Person("Name", "");
So if you want to add some syntactic sugar, you can add a named constructor like below:
class Person {
String name;
String carNumber;
// Constructor creates a person with name & car number
Person(this.name, this.carNumber);
// Named constructor that only takes name and sets carNumber to ""
Person.withOutCar(String name): this(name, "");
// Named constructor with no arguments, just assigns "" to variables
Person.unknown(): this("", "");
}
And you can initialise the object like:
Person.withOutCar("Name");
In the above example the named constructors are being redirected to your actual constructor with pre-defined default values.
You can read more about named constructors here: Dart Language Tour
As the above answer was not really clear/complete to me, when I stumbled upon this, please me let me know, whether my understanding is correct:
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
this.user = User.empty,
});
The constructor using ._() is private to the library, I guess this is a security feature, so you can create an instance only from within the library.
const AuthenticationState.unknown() : this._();
If the object is created as .unknown, the default constructor from above is called (as private), such using the default values. In the other 2 cases, one or both default values are replaced.
I am very new to flutter and dart and trying to use singleton instance for global state(?).
which is company info that gets from backend server.
When flutter app starts, send request to the server and get a response and build a singleton instance based on the response.
So I created class
class Company {
static final Company _instance = new Company._internal();
factory Company() {
return _instance;
}
#protected
String name;
#protected
String intro;
String get companyName => name;
String get companyIntro => intro;
void setCompany(String name, String intro) {
name = name;
intro = intro;
}
Company._internal();
}
in main.dart
// companyResult is the response from server
final String companyName = companyResult["name"];
final String companyIntro = companyResult["intro"];
// create singleton instance
var company = Company();
// set company info
company.setCompany(companyName, companyIntro);
// cheking
print(company.companyName)
prints null
What am I doing wrong?
Singletons are better avoided, I would recommend that you use Provider instead and inject a simple object reference on your widget tree, so you can grab that reference whenever you want.
The reason your example prints null is because you are wrongly referencing your variables on setCompany(), the variables name and intro are all the same variable, you are changing the variables internal to the function, not the class variables, in order to fix it change it to:
void setCompany(String name, String intro) {
this.name = name;
this.intro = intro;
}
Also, I would suggest you name your variables _name and _intro, as there's no sense in having a get for a variable that's no private.