How do I initialize a final field in constructor's body? - dart

Basically, that's what I'm trying to do:
ClassName
{
final OtherClass field;
ClassName()
{
field = new OtherClass(this);
}
}

It's not possible to assign a final field in a constructor body. The final field needs to be assigned before the constructor body, in the initializer list or on declaration:
class ClassName
{
final OtherClass field = new OtherClass(); // Here
ClassName()
: field = new OtherClass() // or here
{
}
}
As you can't use this in the initializer list or on the declaration, you can't do what you plan to do.

With null safety, you can initialize a final field in different ways:
At declaration:
class Foo{
final int bar = 1;
}
In constructor parameter (initializing formal).
class Foo {
final int bar;
// Initializing in constructor parameter.
Foo(this.bar);
}
In the initializer list.
class Foo {
final int bar;
// Initializer list
Foo() : bar = 1;
}
Combination of above two.
class Foo {
final int bar;
Foo(int value) : bar = value;
}
Use late keyword for lazy initialization.
class Foo {
late final int bar; // Initialize it later, maybe in a method
}

Since Dart 2.12 it is possible by using late keyword.
The code below prints 5:
class ClassName
{
final int var1 = 5;
late final OtherClass field;
ClassName()
{
field = new OtherClass(this);
}
}
class OtherClass {
OtherClass(ClassName object) {
print(object.var1);
}
}
void main() {
final object = ClassName();
}
Please see this and the following sections

Related

I want to know, in the code provided what does 'this' keyword referring to.?

/*
I know this keyword is used to refer to class members but i am unable to understand what does 'this'.isEmpty() referring to. Some class ? class method? Or some variable?
For example:
this.value = value;
I understand that here, this.value is referring to class variable value but not for previous occurence of 'this'.
*/
public class StackWithMin extends Stack< NodeWithMin > {
public void push(int value) {
int newMin = Math.min(value, min());
super.push(new NodeWithMin(value,newMin));
}
public int min() {
if(this.isEmpty()) {
return Integer.MAX_VALUE; // Error value
} else {
return peek().min;
}
}
}
class NodeWithMin {
public int value;
public int min;
public NodeWithMin(int value, int min) {
this.value = v;
this.min = min;
}
}
"this" here is object of the class StackWithMin which is extending Stack class from java.util. so StackWithMin is instance of Stack class.
this.isEmpty() which is method defined in Stack, here checks if the stack has any element or not. if it has zero element it returns true else false.
Hope it clears your doubt.

Is it possible to invoke setters in class in Dart?

Is it possible to invoke setters which declaired with set keyword in class in Dart?
In the script written below, Dart does not recognize the setters:
class Cat {
String _size = '';
String _color = '';
int _age = 0;
Cat(String initialSize, String initialColor, int initialAge) {
size(initialSize);
color(initialColor);
age(initialAge);
}
// getter and setter fields are started
String get size {
return _size;
}
void set size(String animalSize) {
_size = animalSize;
}
String get color {
return _color;
}
void set color(String animalColor) {
_color = animalColor;
}
int get age {
return _age;
}
void set age(int animalAge) {
_age = animalAge;
}
// getter and setter fields are ended
}
Error: 'size' isn't a function or method and can't be invoked.
Error: 'color' isn't a function or method and can't be invoked.
Error: 'age' isn't a function or method and can't be invoked.
The way you are calling a setter/getter is how you would do an assignment of the field. So your code should be:
size = initialSize;
color = initialColor;
age = initialAge;
This will call the setter of size, color and age.
The point of having getter/setter is to be able to simulate a field but have some logic behind that field other than just direct access to a variable.
Unrelated to the question: I don't know if your class is just an example but your current class could be written as the following:
class Cat {
String size;
String color;
int age;
Cat(this.size, this.color, this.age);
}
Of if you want named parameters:
class Cat {
String size;
String color;
int age;
Cat({required this.size, required this.color, required this.age});
}
It is in general not needed to have getter/setters unless you need to have some logic or want to add restrictions. The great thing about getter/setter in Dart is that they behave like fields so we can just start by having fields and replace the field with a getter and/or setter later if we need to add extra logic.

Dart can't access property on a generic type function parameter despite providing the type

I'm trying to specify a function parameter as a generic type T:
enum MyEnum {
Foo,
Bar
}
class DbColumn {
final Function<T>(T value) serializer;
const DbColumn({this.serializer});
}
class MyClass {
static final DbColumn rating = DbColumn(
serializer: <MyEnum>(v) {
var i = v.index;
}
);
}
However when trying to access index on v I get this type error message:
The getter 'index' isn't defined for the type 'Object'.
Try importing the library that defines 'index', correcting the name to the name of an existing getter, or defining a getter or field named 'index'.
When I hover over v in VSC it says that it's of type MyEnum.
If I instead remove the generic type and do a cast like this it works as expected:
class DbColumn {
final Function(dynamic value) serializer;
const DbColumn({this.serializer});
}
class MyClass {
static final DbColumn rating = DbColumn(
serializer: (v) {
var casted = v as MyEnum;
var i = casted.index;
}
);
}
Why is the generic type not working as expected?
EDIT:
What is even weirder is that this example works too if I put it inside MyClass:
x<T>(Function(T) c) {}
y() {
x<MyEnum>((v) {
print(v.index); // No error given and type of v is MyEnum
});
}
EDIT 2: The same problem happens when overriding methods:
abstract class MyInterface {
int someFunction<T>(T value);
}
class MyClass implements MyInterface {
#override
someFunction<MyEnum>(v) {
return v.index; // Gives same error and no intellisense happens in VSC
}
}
Instead of making the function generic, declare the class as generic and it will work as expected. Like this :
enum MyEnum {
Foo,
Bar
}
class DbColumn<T> {
final Function(T value) serializer;
const DbColumn({this.serializer});
}
class MyClass {
static final DbColumn<MyEnum> rating = DbColumn(
serializer: (v) {
var i = v.index;
print('Index : $i');
}
);
}
void main() {
MyClass.rating.serializer(MyEnum.Bar);
}
OUTPUT :
Index : 1

Default values of an optional parameter must be constant

I've been trying to get this right for some time and can't figure out what is wrong.
enum MyEnum { a, b }
class ClassA {
final MyEnum myEnum;
ClassA({this.myEnum = MyEnum.a});
}
class ClassB {
final ClassA classA;
ClassB({this.classA = ClassA()}); // ClassA expression is underlined with red
}
The IDE (Visual Studio Code) complains with:
[dart] Default values of an optional parameter must be constant.
I've tried to prefix it with const, new, and passing values to the ClassA constructor, but nothing works. Can anyone see what I am doing wrong here?
Try
enum MyEnum { a, b }
class ClassA {
final MyEnum myEnum;
ClassA({this.myEnum});
}
class ClassB {
final ClassA classA;
ClassB({this.classA}); // ClassA expression is underlined with red
}
no need for '=' operator. It will automatically assign the value when you will pass it to the constructor.
Use the '=' operator only when you need to pass a default value to your variables hence, making them optional parameters.
Edit
enum MyEnum { a, b }
class ClassA {
final MyEnum myEnum;
const ClassA({this.myEnum = MyEnum.a});
}
class ClassB {
final ClassA classA;
ClassB({this.classA = const classA()}); // ClassA expression is underlined with red
}
This is the only way i could find to achieve what you want, the constructor should be default
This is called a canonicalized constructor.
For ClassA to be able to create constant values, the constructor must be marked as const.
enum MyEnum { a, b }
class ClassA {
final MyEnum myEnum;
const ClassA({this.myEnum = MyEnum.a}); // <- constructor is const.
}
class ClassB {
final ClassA classA;
ClassB({this.classA = const ClassA()}); // <- creation is const
}
You need to write const for the object creation, even if only constant values are allowed as default values. The language do not automatically insert a const in that position because the language team wants to reserve the option of allowing non-constant default values at some point.
If the Order date wasn't specified, use DateNow..
If the Order date was specified, use it.
class Order {
final String id;
final double amount;
final List cartItems;
final DateTime? dateTime;
Order(
{required this.id,
required this.amount,
required this.cartItems,
dateTime
})
:this.dateTime = ( dateTime != null ? dateTime : DateTime.now() );
}
void main() {
var order_use_default_date = Order(id:"1",amount:1000,cartItems:[1,2,3]);
var order_use_param_date = Order(id:"1",amount:1000,cartItems:[1,2,3],dateTime:DateTime.now().subtract(Duration(days: 2)) );
print(order_use_default_date.dateTime);
print(order_use_param_date.dateTime);
}
Have you tried?
class ClassB {
final ClassA _classA;
ClassB({ClassA classA}): _classA = classA ?? ClassA();
}
Suppose let's say you want to set empty list as a default value for a list member, adding 'const' to that default value, will prevent any actions like add() etc. In that case you can use
class A{
List<int> numbers;
// will raise : Uncaught Error: Unsupported operation: add
// when you call the addEle() method
// A({this.numbers= const []});
A({var passedNumbers}) : this.numbers = passedNumbers??[];
void addEle(int n){
numbers.add(n);
}
}
void main() {
var obj = A();
obj.addEle(5);
}
Use of initializer list
Don't define the parameter in the constructor but rather in the initializer list:
enum MyEnum { a, b }
class ClassA { // a non constant class
final MyEnum myEnum;
ClassA({this.myEnum = MyEnum.a});
}
class ClassB {
final ClassA classA;
ClassB({ClassA? classA}) : classA = classA ?? ClassA(); //init in initalizer list
}
Also, make sure to check if you can make your ClassA a constant class as already described.

Dart Multiple Constructors

Is it really not possible to create multiple constructors for a class in dart?
in my Player Class, If I have this constructor
Player(String name, int color) {
this._color = color;
this._name = name;
}
Then I try to add this constructor:
Player(Player another) {
this._color = another.getColor();
this._name = another.getName();
}
I get the following error:
The default constructor is already defined.
I'm not looking for a workaround by creating one Constructor with a bunch of non required arguments.
Is there a nice way to solve this?
You can only have one unnamed constructor, but you can have any number of additional named constructors
class Player {
Player(String name, int color) {
this._color = color;
this._name = name;
}
Player.fromPlayer(Player another) {
this._color = another.getColor();
this._name = another.getName();
}
}
new Player.fromPlayer(playerOne);
This constructor
Player(String name, int color) {
this._color = color;
this._name = name;
}
can be simplified to
Player(this._name, this._color);
Named constructors can also be private by starting the name with _
class Player {
Player._(this._name, this._color);
Player._foo();
}
Constructors with final fields initializer list are necessary:
class Player {
final String name;
final String color;
Player(this.name, this.color);
Player.fromPlayer(Player another) :
color = another.color,
name = another.name;
}
If your class uses final parameters the accepted answer will not work. This does:
class Player {
final String name;
final String color;
Player(this.name, this.color);
Player.fromPlayer(Player another) :
color = another.color,
name = another.name;
}
If you already used a constructor with params in the project and now you figured out that you need some no params default constructor you can add an empty constructor.
class User{
String name;
User({this.name}); //This you already had before
User.empty(); //Add this later
}
Try the below code on DartPad
class MyClass {
//These two are private attributes
int _age;
String _name;
//This is a public attribute
String defaultName = "My Default Name!";
//Default constructor
MyClass() {
_age = 0;
_name = "Anonymous";
}
MyClass.copyContructor(MyClass fromMyClass) {
this._age = fromMyClass._age;
this._name = fromMyClass._name;
}
MyClass.overloadedContructor(String name, int age) {
this._age = age;
this._name = name;
}
MyClass.overloadedContructorNamedArguemnts({String name, int age}) {
this._age = age;
this._name = name;
}
//Overriding the toString() method
String toString() {
String retVal = "Name:: " + _name + " | " + "Age:: " + _age.toString();
return retVal;
}
}
//The execution starts from here..
void main() {
MyClass myClass1 = new MyClass();
//Cannot access oprivate attributes
//print(myClass1.name);
//print(myClass1.age);
//Can access the public attribute
print("Default Name:: " + myClass1.defaultName);
print(myClass1.toString());
MyClass myClass2 = new MyClass.copyContructor(myClass1);
print(myClass2.toString());
MyClass myClass3 = new MyClass.overloadedContructor("Amit", 42);
print(myClass3.toString());
MyClass myClass4 =
new MyClass.overloadedContructorNamedArguemnts(age: 42, name: "Amit");
print(myClass4.toString());
}
Dart doesn't support parameter overloading (having multiple functions of the same name but with different parameters). This applies to constructors as well - that's the reason why in SDK there're so many classes with named constructors.
In Dart you can use Default Constructor, Named Constructor, Factory Method and Static Method to instantiate classes:
class A {
// Default constructor
A() : msg = '1';
// Named constructor with positional param
A.message(this.msg);
// Factory method with named param
factory A.underscore({String msg = ''}) {
return A.message('_'+msg);
}
// Factory method with arrow func body
static A bang(msg) => A.message('!'+msg);
final String msg;
}
void main() {
print(A().msg);
print(A.message('2').msg);
print(A.underscore(msg: '3').msg);
print(A.bang('4').msg);
}
Output:
1
2
_3
!4
You can use factory constructors
factory Player.fromPlayer(Player another) => Player(another.name, another.color);
i had found solution to solve this problem depend on checked the type of data you are passed it to function
Try this Solution
As Günter Zöchbauer already specified in his answer:
You can only have one unnamed constructor, but you can have any number of additional named constructors in Flutter.
By using named constructor you can create multiple constructors in the same class.
Each constructor will have a unique name. So that you can identify each of them.
Syntax for named constructor :
class_name.constructor_name (arguments) {
// If there is a block of code, use this syntax
// Statements
}
or
class_name.constructor_name (arguments);
// If there is no block of code, use this syntax
For more insights Click Here
To know about various types of constructors in Flutter Click Here
Class User{
User();
User.fromName(this.name);
String? name;
}
If you want to do some more elaborated property calculation (I'm a Swift guy), you can do like this:
class FooProvider {
int selectedFoo;
FooProvider(List<String> usageObjects)
: selectedFoo = firstOne(usageObjects);
static int firstOne(List<String> usageObjects) {
return 2;
}
}

Resources