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.
Related
I remember that Dart objects have a method which does an object return a value by default without pointing to an property. Example:
class A {
final String name;
A(this.name);
...
}
main() {
var obj = A('chesu');
print(obj + ' locuaz');
}
Output: chesu locuaz
But I don't remember that method or decorator and it is not toString().
Use interpolation to compose strings and values. It will automatically call toString method of value.
class A {
A(this.name);
final String name;
#override
toString() => name;
}
main() {
var obj = A('chesu');
print('$obj locuaz');
}
I finally found what I was looking for, it's called callable classes.
We couldn't pass a DateTime? value to a function that requires a DateTime argument.
The code below results in an error.
class Spacecraft {
String name;
DateTime? launchDate;
// Read-only non-final property
int? get launchYear => launchDate?.year;
// Constructor, with syntactic sugar for assignment to members.
Spacecraft(this.name, this.launchDate) {
// Initialization code go here.
}
// Named constructor that forwards to the default one.
Spacecraft.unlaunched(String name) : this(name, null);
// Method
void describe() {
print('Spacecraft: $name');
if (launchDate != null) {
int years = DateTime.now().difference(launchDate).inDays ~/ 365;
print('Launched: $launchYear ($years years ago)');
} else {
print('Unlaunched');
}
}
}
The argument type 'DateTime?' can't be assigned to the parameter type
'DateTime'.
However, this worked:
class Spacecraft {
String name;
DateTime? launchDate;
// Read-only non-final property
int? get launchYear => launchDate?.year;
// Constructor, with syntactic sugar for assignment to members.
Spacecraft(this.name, this.launchDate) {
// Initialization code go here.
}
// Named constructor that forwards to the default one.
Spacecraft.unlaunched(String name) : this(name, null);
// Method
void describe() {
print('Spacecraft: $name');
// Type promotion doesn't work on getters
var launchDate2 = launchDate;
if (launchDate2 != null) {
int years = DateTime.now().difference(launchDate2).inDays ~/ 365;
print('Launched: $launchYear ($years years ago)');
} else {
print('Unlaunched');
}
}
}
And heck, launchDate2 is also a DateTime? type. Why the heck it could be passed to a function that requires a DateTime argument?
launchDate refers to a property so it couldn't be promoted or cast. See http://dart.dev/go/non-promo-property and also https://dart.dev/null-safety/understanding-null-safety
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;
}
}
I can conveniently change opsCount variable directly from inside the function,
because there is only one of that type of variable.
int opsCount = 0;
int jobXCount = 0;
int jobYCount = 0;
int jobZCount = 0;
void doStats(var jobCount) {
opsCount++;
jobCount++;
}
main() {
doStats(jobXCount);
}
But there are many jobCount variables, so how can I change effectively that variable, which is used in parameter, when function is called?
I think I know what you are asking. Unfortunately, the answer is "you can't do this unless you are willing to wrap your integers". Numbers are immutable objects, you can't change their value. Even though Dart's numbers are objects, and they are passed by reference, their intrinsic value can't be changed.
See also Is there a way to pass a primitive parameter by reference in Dart?
You can wrap the variables, then you can pass them as reference:
class IntRef {
IntRef(this.val);
int val;
#override
String toString() => val.toString();
}
IntRef opsCount = new IntRef(0);
IntRef jobXCount = new IntRef(0);
IntRef jobYCount = new IntRef(0);
IntRef jobZCount = new IntRef(0);
void doStats(var jobCount) {
opsCount.val++;
jobCount.val++;
}
main() {
doStats(jobXCount);
print('opsCount: $opsCount; jobXCount: $jobXCount; jobYCount: $jobYCount; jobZCount: $jobZCount');
}
EDIT
According to Roberts comment ..
With a custom operator this would look like:
class IntRef {
IntRef(this.val);
int val;
#override
String toString() => val.toString();
operator +(int other) {
val += other;
return this;
}
}
void doStats(var jobCount) {
opsCount++;
jobCount++;
}
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