Is there a quick way to create a new instance of a Dart class from an existing object? - flutter

Basically wondering if there is a quick way other than creating a method to create a new class instance from itself so the example below would print 9, not 15.
void main() {
final classOne = SomeClass(mutableString: 'Hello', mutableInt: 9);
final classTwo = classOne;
classTwo.mutableInt = 15;
print(classOne.mutableInt);
}
class SomeClass {
SomeClass({required this.mutableString, required this.mutableInt});
String mutableString;
int mutableInt;
}
Thanks

You can add a method in the class which retuns the same object.
For example :
I am ading copyWith method in SomeClass
class SomeClass {
SomeClass({required this.mutableString, required this.mutableInt});
String mutableString;
int mutableInt;
SomeClass copyWith({int? mutableInt}) {
return SomeClass(
mutableString: this.mutableString,
mutableInt: mutableInt ?? this.mutableInt,
);
}
}
Now you can use the method as :
void main() {
final classOne = SomeClass(mutableString: 'Hello', mutableInt: 9);
final classTwo = classOne.copyWith(mutableInt:15);;
print(classOne.mutableInt);
}

#anoncgain solution is correct up-to an extent.
You can also do the same as
class SomeClass {
//...other code ....
String? mutableString; //make your params nullable
int? mutableInt;
//declare a named constructor to copp the existing object value.
SomeClass.copy(SomeClass object){
mutableString = object.mutableString;
mutableInt = object.mutableInt;
}
}
Then you can use it as
final classTwo = SomeClass.copy(classOne);
//it will copy the values to the newly created object
//rather then storing the reference of the object

Related

Dart using variable to hold set of constructor parameters, to be used in multiple constructors?

is there a way to use some variable or any holder to store constructor parameters,
to be able to pass them to multiple constructors without repeating the values?
I think its possible if the constructor has only positional parameters (no named parameters).
var parametersHolder={
named1: "str",
named2: "lorem",
};
// normal usage
constructorA(named1: "str", named2: "lorem");
constructorB(named2: "lorem",named1: "str" );
my question is how to do the following in dart:
constructorA(parametersHolder);
constructorB(parametersHolder);
so is that achievable ?
Thanks
If you really want, you could use Function.apply with a constructor tear-off:
class Foo {
String named1;
String named2;
Foo({required this.named1, required this.named2});
#override
String toString() => 'Foo: $named1 $named2';
}
void main() {
var namedArguments = {
#named1: 'str',
#named2: 'lorem',
};
var foo = Function.apply(Foo.new, null, namedArguments) as Foo;
print(foo); // Prints: Foo: str lorem
}
Note that doing this sacrifices compile-time type-safety.
You can define a class to hold your parameters like this:
class MyClass{
late final int myInt;
late final String myString;
MyClass.firstConstructor(MyClassParams params){
this.myInt = params.myInt;
this.myString = params.myString;
}
MyClass.secondConstructor(MyClassParams params){
this.myInt = params.myInt;
this.myString = params.myString;
}
}
class MyClassParams{
final int myInt;
final String myString;
const MyClassParams(this.myInt, this.myString);
}

final variables can't be reassigned, but the object can be mutated in flutter

https://stackoverflow.com/a/55990137/462608
comment:
"Can't be changed after initialized" is ambiguous. final variables can't be reassigned, but the object can be mutated. –
jamesdlin
Feb 19 at 17:43
and https://stackoverflow.com/a/50431087/462608
a final variable's value cannot be changed. final modifies variables
What do both these statements mean? Please give examples.
Consider the following class:
class SampleObject {
int id;
String value;
SampleObject(this.id, this.value);
}
final variable can't be reassigned:
void main() {
final obj1 = SampleObject(1, "value1");
// the following line will gives error:
// The final variable 'obj1' can only be set once
obj1 = SampleObject(1, "value2");
}
But the object property can be changed (is mutable):
void main() {
final obj1 = SampleObject(1, "value1");
obj1.value = "value2";
print(obj1.value);
}
But it becomes an immutable object if you set all the property in the class to final:
class SampleObject {
final int id;
final String value;
SampleObject(this.id, this.value);
}
where it gives error when you're trying to reassign a value to its property:
void main() {
final obj1 = SampleObject(1, "value1");
// the following line will gives error:
// 'value' can't be used as a setter because it's final.
// Try finding a different setter, or making 'value' non-final
obj1.value = "value2";
}
Imagine the example below:
void main() {
final student = Student('Salih', 29);
print('Student before $student');
student.age = 30;
print('Student after $student');
}
class Student {
Student(this.name, this.age);
final String name;
int age;
#override
String toString() => 'Age is $age and name is $name';
}
One of the fields of the Student object is mutable. This way we can reassign it. What others mean above is that, the object reference of the final variables will be assigned first but internals of the object can be changed.
In our example, final would be preventing to re-assign something to student object but it will not prevent us to re-assign a value within the object.
You can run the code on dartpad.dev above and see the result as follows:
Student before Age is 29 and name is Salih
Student after Age is 30 and name is Salih

Copying objects bug in Flutter BLoC

I am building an app with Flutter using BLOC Architecture with the flutter_bloc package.
I have a data class for an object, which looks like this example:
class MyClass {
int? id;
List<MyOtherClass> myOtherClasses = [];
MyClass();
MyClass._(this.id, this.myOtherClasses);
MyClass copyWith({int? id, List<MyOtherClass>? myOtherClasses}) {
return MyClass._(
id ?? this.id,
myOtherClasses ?? this.myOtherClasses,
);
}
}
class MyOtherClass {
int value;
MyOtherClass(this.value);
}
Now I a Screen that shows the values of the class, and a Dialog to edit it. To store the state, I am using a Cubit, that looks like this:
#immutable
abstract class MyClassState {
final MyClass myClass;
MyClassState(this.myClass);
}
class MyClassInitial extends MyClassState {
MyClassInitial() : super(MyClass());
}
class MyClassEditing extends MyClassState {
final MyClass editingMyClass;
MyClassEditing(MyClass myClass, this.editingMyClass) : super(myClass);
}
class MyClassChanged extends MyClassState {
MyClassChanged(MyClass myClass) : super(myClass);
}
class MyClassCubit extends Cubit<MyClassState> {
MyClassCubit() : super(MyClassInitial());
void editMyClass({int? id, List<MyOtherClass>? myOtherClasses}) {
emit(MyClassEditing(state.myClass,
state.myClass.copyWith(id: id, myOtherClasses: myOtherClasses)));
}
void saveChanges() {
if (state is MyClassEditing)
emit(MyClassChanged((state as MyClassEditing).editingMyClass));
}
void discardChanged() {
emit(MyClassChanged(state.myClass));
}
}
So, basically, what I am trying to achieve here is to story a backup of MyClass in the MyClassEditing state in order to be able to discard the changes I made to MyClass. When I call the constructor of MyClassEditing here in this line: emit(MyClassEditing(state.myClass, state.myClass.copyWith(id: id, myOtherClasses: myOtherClasses)));, the state should contain the initial instance of MyClass without any changes, and the copy of the initial MyClass instance with the changes applied. But somehow, both instances have the changes applied, and I just don't get why this happens. Am I doing something wrong copying the instance?
Probably, the issue might be lists, if you make shallow copy of them.

How to cast static variable as a constant and use it to pass to class constructor that expecting final

Got an error for following code
Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
static const MyClass darkerText = MyClass(param);
Understood that using static in this instance might be inappropriate. Just wanted to look if there is any possible way to do so.
class MyClass {
final int total;
MyClass(total);
}
class Test {
static int param = 10;
static const MyClass darkerText = MyClass(param);
}
main() {
new Test();
}
You seem to have misunderstood the point of const and final. const is for values that are known at compile time, so in your case this is possible, though somewhat pointless, if all your values are compile time constants:
class MyClass {
final int total;
const MyClass(this.total);
}
class Test {
static const int param = 10;
static const MyClass darkerText = MyClass(param);
}
main() {
new Test();
}
What is more normal is to use final variables, which can be set during the program's lifecycle but don't change after being set, in which case you would use something like this:
class MyClass {
final int total;
MyClass(this.total);
}
class Test {
static int param = 10;
static final MyClass darkerText = MyClass(param);
}
main() {
new Test();
}
You can copy paste run full code in DartPad
You need to use this.total and remove const keyword of darkerText
class MyClass {
final int total;
MyClass(this.total);
}
class Test {
static int param = 10;
static MyClass darkerText = MyClass(param);
}
main() {
print(Test.darkerText.total);
}
As the error says, your MyClass is a non-const constructor.Make it const:
class MyClass {
final int total;
const MyClass(this.total);
}
class Test {
static const int param = 10;
static const MyClass darkerText = MyClass(param);
}
void main() {
new Test();
}

in Dart, problems with static method when called from variable

have class Klass with static method fn1
class Klass {
static String fn1() => 'hello';
}
> Klass.fn1(); // hello
but when Klass is assigned to a variable, calling the method fn1 fails
var k = Klass;
> k.fn1() // "Unhandled exception: Class '_Type' has no instance method 'fn1'.
don't quite know what's going on here
A simple workaround
class Klass {
static fn1(String name) {
return name;
}
fn1NonStatic(String name) {
return fn1(name);
}
}
Klass().fn1NonStatic("test");
I'm not sure what the intent of the code here is, but you might want to use dart:mirrors to reflectively call fn1(). I don't believe you can invoke it by assigning Klass to a variable. Here is how you can do it:
import 'dart:mirrors';
class Klass {
static String fn1() => 'hello';
}
main() {
final mirror = reflectClass(Klass);
print(mirror.invoke(#fn1, []).reflectee); // Prints 'hello'.
}