Initialization error when creating an object - dart

When I compile the following code:
class Student {
int id;
Student() {
this.id = 12345;
}
}
void main() {
var student1 = new Student();
}
I get the following error:
Error: Field 'id' should be initialized because its type 'int' doesn't
allow null.
But why do I get this error? I did initialize id in the constructor!

In Dart, the creation of objects are split into two phases:
Initialization of all values.
Execution of constructor body.
So when you are running code inside the constructor body (between the {...} in the constructor definition) then all class defined variables must have been provided a default value that is valid for the type of variable.
In your case, the variable is typed int but are not provided a default value. In Dart, all variable will by default be set to null in case of no other value provided. But since int is a non-nullable type it does not allow null to be a value and the compiler are therefore giving you the error.
The solution are to provide a value before the constructor is running. You can do that like this:
class Student {
int id;
Student() : id = 12345;
}
Or:
class Student {
int id = 12345;
Student(); // The constructor can in theory just be removed here
}
In case you cannot define a value as part of the initialization phase, you can (but should be prevented if possible) mark the variable as late which makes it so you promise, the Dart compiler, that you are going to provide a value for the variable before the first time you are trying to read from that variable:
class Student {
late int id;
Student() {
this.id = 12345;
}
}
In case you are trying to read from id before it have been provided a value, the program will crash with a LateInitializationError at runtime.
And at last, you can set the type to be a nullable type, like int?, to allow the variable to have a default value of null. But doing so will require you to check for null when you are trying to do something with the value in a context where null is not allowed:
class Student {
int? id;
Student() {
this.id = 12345;
}
}

Related

Cannot assign type to same type in dart

I have this code below. I want to create BST but when I try to implement compareTO method inside get function I get the "The argument type 'Key' can't be assigned to the parameter type 'Key'.dartargument_type_not_assignable" error which does not make sense to me because it basically says cannot assign to the same type. Can anybody explain this? I commented on the erogenous line below.
class Key extends Comparable<Key> {
num key;
Key(this.key);
#override
int compareTo(Key other) {
return key.compareTo(other.key);
}
}
class Value {
dynamic value;
}
class Node {
Key key;
Value value;
Node? left, right;
Node(this.key, this.value);
}
class BST<Key extends Comparable<Key>, Value> {
Node? root;
Value get(Key key) {
Node? currentNode = root;
while (currentNode != null) {
int compare = key.compareTo(currentNode.key); // The argument type 'Key' can't be assigned to the parameter type 'Key'.dartargument_type_not_assignable
if (compare > 0) {
currentNode = currentNode.right;
} else if (compare < 0) {
currentNode = currentNode.left;
} else {}
...
...
}
}
I would suggest you to rename BST<Key extends Comparable<Key>, Value> into BST<T extends Comparable<T>, Value> to avoid confusion between the different identifiers Keys.
In BST, Key (let's call it T) refers to a generic type (=T) that extends Comparable<T>.
So T extends Comparable<T>
InBST.get(Key key), Key still refers to the generic type T.
So key has the type T.
Now I supposed that currentNode.key is of type Key (!= T).
key.comparyTo(x) requires x to be a T while currentNode.key is not (it is Key).
It is hard to be clear when you have 2 identifiers with the same name (Key).
As I said at the beginning of my answer, rename
class BST<Key extends Comparable<Key>, Value> {}
into
class BST<T extends Comparable<T>, Value> {}
to have a more understandable error message.
When you do it, the error message should become:
The argument type 'Key' can't be assigned to the parameter type 'T'.

why do I need to use a late modifier here?

class Car {
String model;
String brand;
String _engine;
static int carProduced = 0;
Car(String model, String brand, String engine) {
this._engine = engine;
this.brand = brand;
this.model = model;
}
}
I am getting this error.
Non-nullable instance field '_engine' must be initialized.
Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
I am not actually sure. As I am initializing that non-nullable field in the default constructor why do I need to use a late modifier here?
String model = "";
String brand = "";
String _engine = "";
Adding initializer expression solved the error.
Does it mean that object fields are created even before the constructor call ??
Dart objects are created in two steps/phases:
Initialization of values.
Execution of constructor body.
So all non-nullable non-late values must have a value before we executes the constructor body. The reason is that inside the constructor body we are allowed to use all values inside the object.
We can therefore in Dart run initialization code before running the constructor body like:
class Car {
String model;
String brand;
String _engine;
static int carProduced = 0;
Car(String model, String brand, String engine)
: this.model = model,
this.brand = brand,
this._engine = engine;
}
But since this is kinda redundant we have the follow shortcut to do the same:
class Car {
String model;
String brand;
String _engine;
static int carProduced = 0;
Car(this.model, this.brand, this._engine);
}

Initializing member with constructor in an optional parameter constructor in Dart

Based on my following code, I want to have a constructor of the class Hero that takes a Stats class as an optional parameter that has a default value based on its constructor (the one that set its health and attack fields to 100 and 10 by an optional named parameter) instead of null.
void main() {
Hero hero = Hero("Foo");
print('${hero.name} : HP ${hero.stats.health}');
}
class Stats {
Stats({this.health = 100, this.attack = 10});
double health;
double attack;
}
class Hero {
// error: The default value of an optional parameter must be constant
Hero(this.name,[this.stats = Stats()]);
String name;
Stats stats;
}
More things i've tried:
class Hero {
// error: Can't have a const constructor for a class with non-final fields
Hero(this.name,[this.stats = const Stats()]);
String name;
Stats stats;
}
class Hero {
// error: stats initialized as null
Hero(this.name,[this.stats]);
String name;
Stats stats = Stats();
}
This following code works but it doesn't have stats as an optional parameter:
class Hero {
Hero(this.name);
String name;
Stats stats = Stats();
}
(Credits to #jamesdlin for linking to his answer in the comments)
In general, if there isn't a const constructor available, you instead
can resort to using a null default value (or some other appropriate
sentinel value) and then setting the desired value later:
class Foo {
Bar bar;
Foo({Bar bar}) : bar = bar ?? Bar();
}
(Note that explicitly passing null as an argument will do something
different with this approach than if you had set the default value
directly. That is, Foo(bar: null) with this approach will initialize
bar to Bar(), whereas with a normal default value it would initialize
bar to null. In some cases, however, this approach's behavior might be
more desirable.)

How to automatically initialize parent field?

Is it possible to automatically initialize fields from a parent class in the constructor?
I get the syntax error:
Could not match parameter initializer 'this.name' with any field
class Type {
String name;
}
class Language extends Type {
String id;
Language(this.name) {
While your case is common, at this time the dart language spec specifically says:
Executing an initializing formal this.id causes the field id of the immediately surrounding class to be assigned the value of the corresponding actual parameter.
This essentially tells us that this.variable notation, in the constructor arguments, will only work on variables in the immediate class and not any parent classes. There are a couple of solutions available: The first is to assign it within the constructor's body:
class Type {
String name;
}
class Language extends Type {
String id;
Language(name) {
this.name = name;
}
}
Alternatively, if we can change the parent class to have a constructor which will initialize the variable then we can use the initializer list in the child class:
class Type {
String name;
Type();
Type.withName(this.name);
}
class Language extends Type {
String id;
Language(name) : super.withName(name);
}
This is assuming there's some reason that the default constructor for Type doesn't automatically initialize name so we created the 2nd named constructor instead.

Why do I get a "Null value was assigned to a property of primitive type setter of" error message when using HibernateCriteriaBuilder in Grails

I get the following error when using a primitive attribute in my grails domain object:
Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
at grails.orm.HibernateCriteriaBuilder.invokeMethod(HibernateCriteriaBuilder.java:1077)
According to this SO thread, the solution is to use the non-primitive wrapper types; e.g., Integer instead of int.
A null value cannot be assigned to a primitive type, like int, long, boolean, etc. If the database column that corresponds to the field in your object can be null, then your field should be a wrapper class, like Integer, Long, Boolean, etc.
The danger is that your code will run fine if there are no nulls in the DB, but will fail once nulls are inserted.
And you can always return the primitive type from the getter. Ex:
private Integer num;
public void setNum(Integer i) {
this.num = i;
}
public int getNum() {
return this.num;
}
But in most cases you will want to return the wrapper class.
So either set your DB column to not allow nulls, or use a wrapper class.
A primitive type cannot be null. So the solution is replace primitive type with primitive wrapper class in your tableName.java file.
Such as:
#Column(nullable=true, name="client_os_id")
private Integer client_os_id;
public int getClient_os_id() {
return client_os_id;
}
public void setClient_os_id(int clientOsId) {
client_os_id = clientOsId;
}
reference http://en.wikipedia.org/wiki/Primitive_wrapper_class to find wrapper class of a primivite type.
I'll try to make you understand with the help of an example. Suppose you had a relational table (STUDENT) with two columns and ID(int) and NAME(String). Now as ORM you would've made an entity class somewhat like as follows:-
package com.kashyap.default;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* #author vaibhav.kashyap
*
*/
#Entity
#Table(name = "STUDENT")
public class Student implements Serializable {
/**
*
*/
private static final long serialVersionUID = -1354919370115428781L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "NAME")
private String name;
public Student(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Lets assume table already had entries. Now if somebody asks you add another column of "AGE" (int)
ALTER TABLE STUDENT ADD AGE int NULL
You'll have to set default values as NULL to add another column in a pre-filled table. This makes you add another field in the class. Now the question arises whether you'll be using a primitive data type or non primitive wrapper data type for declaring the field.
#Column(name = "AGE")
private int age;
or
#Column(name = "AGE")
private INTEGER age;
you'll have to declare the field as non primitive wrapper data type because the container will try to map the table with the entity. Hence it wouldn't able to map NULL values (default) if you won't declare field as wrapper & would eventually throw "Null value was assigned to a property of primitive type setter" Exception.
use Integer as the type and provide setter/getter accordingly..
private Integer num;
public Integer getNum()...
public void setNum(Integer num)...
#Column(name ="LEAD_ID")
private int leadId;
Change to
#Column(name ="LEAD_ID")
private Integer leadId;
There are two way
Make sure that db column is not allowed null
User Wrapper classes for the primitive type variable like private int var; can be initialized as private Integer var;
Do not use primitives in your Entity classes, use instead their respective wrappers. That will fix this problem.
Out of your Entity classes you can use the != null validation for the rest of your code flow.
Either fully avoid null in DB via NOT NULL and in Hibernate entity via #Column(nullable = false) accordingly or use Long wrapper instead of you long primitives.
A primitive is not an Object, therefore u can't assign null to it.
#Dinh Nhat, your setter method looks wrong because you put a primitive type there again and it should be:
public void setClient_os_id(Integer clientOsId) {
client_os_id = clientOsId;
}
Change the parameter type from primitive to Object and put a null check in the setter. See example below
public void setPhoneNumber(Long phoneNumber) {
if (phoneNumber != null)
this.phoneNumber = phoneNumber;
else
this.extension = 0l;
}
Make sure your database myAttribute field contains null instead of zero.

Resources