How to extend a class in Dart/Flutter - flutter

I have class A:
class A{
String title;
String content;
IconData iconData;
Function onTab;
A({this.title, this.content, this.iconData, this.onTab});
}
How can i create class B that extends class A with additional variable like following:
class B extends A{
bool read;
B({this.read});
}
Tried with this but not working
let o = new B(
title: "New notification",
iconData: Icons.notifications,
content: "Lorem ipsum doro si maet 100",
read: false,
onTab: (context) => {
});

You have to define the constructor on the child class.
class B extends A {
bool read;
B({title, content, iconData, onTab, this.read}) : super(title: title, content: content, iconData: iconData, onTab: onTab);
}

Just to update for 2023, since Dart 2.17 we have Super Initializers - described in detail by Michael Thomsen here
You no longer need to make the explicit call to super.
Example:
class B extends A {
bool read;
B({super.title, super.content, super.iconData, super.onTab, this.read});
}

You can inherit from or extend a class using the extends keyword. This allows you share properties and methods between classes that are similar, but not exactly the same. Also, it allows different subtypes to share a common runtime type so that static analysis doesn't fail. (More on this below);
The classic example is using different types of animals.
class Animal {
Animal(this.name, this.age);
int age;
String name;
void talk() {
print('grrrr');
}
}
class Cat extends Animal {
// use the 'super' keyword to interact with
// the super class of Cat
Cat(String name, int age) : super(name, age);
void talk() {
print('meow');
}
}
class Dog extends Animal {
// use the 'super' keyword to interact with
// the super class of Cat
Dog(String name, int age) : super(name, age);
void talk() {
print('bark');
}
}
void main() {
var cat = Cat("Phoebe",1);
var dog = Dog("Cowboy", 2);
dog.talk();
cat.talk();
}

Related

How to make inheritance hierarchy for Type Converter of Dart Floor?

As below, I define ListConverter<T> to make inheritance hierarchy.
abstract class ListConverter<T> extends TypeConverter<List<T>, String> {
static const delimiter = "!DELIMITER!";
T fromDB(String databaseValue);
String toDB(T value);
#override
List<T> decode(String databaseValue) {
return databaseValue
.split(delimiter)
.where((element) => element.isNotEmpty)
.map((e) => fromDB(e))
.toList();
}
#override
String encode(List<T> value) {
return value.map((e) => toDB(e)).join(delimiter);
}
}
Using ListConverter<T>, I implement IntListConverter.
class IntListConverter extends ListConverter<int> {
#override
int fromDB(String databaseValue) {
return int.parse(databaseValue);
}
#override
String toDB(int value) {
return value.toString();
}
}
My plan was to use ListConverter<T> also on StringListConverter, etc.
But unfortunately, I got this error message while running floor_generator.
[SEVERE] floor_generator:floor_generator on lib/persistence/db/app_database.dart:
Only classes that inherit from TypeConverter can be used as type converters. Make sure use a class that inherits from TypeConverter.
I know that Hierarchy (B) works well, but I want to build (A) structure for managing other list converters.
(A) TypeConverter -> ListConverter -> IntListConverter
(B) TypeConverter -> IntListConverter
How to make inheritance hierarchy for Type Converter of Dart Floor?
I resolved this problem in a roundabout way.
I use mixin keyword instead of direct inheritance.
class IntListConverter extends TypeConverter<List<int>, String>
with ListConverter<int> {
#override
int fromDB(String databaseValue) {
return int.parse(databaseValue);
}
#override
String toDB(int value) {
return value.toString();
}
}

How to set a function parameter's default value as an object of a class which extends an abstract class?

Let's say I have several classes which extend an abstract class. Now I want to pass a default value to a function argument, where the type of the argument is the abstract class. Dart expects a const value, and I couldn't create a const constructor for an abstract class. How can I pass a default value of the abstract class?
Sample code is as following:
class Main {
late A objOfA;
Main({ A nObjOfA = const B() }); // <===== Error here
}
abstract class A {
abstract String name;
abstract int id;
}
class B extends A {
#override
String name = "B";
#override
int id = 1;
}
class C extends A {
#override
String name = "C";
#override
int id = 1;
}
Here, how can I pass a default value of nObjOfA in the constructor of Main?
Dart expects a const value, and I couldn't create a const constructor for an abstract class.
There is no rule that you cannot create a const constructor for an abstract class. Abstract classes can have constructors; you just can't call them directly to instantiate an abstract class. The following code is legal:
class Main {
A objOfA;
Main({this.objOfA = const B()});
}
abstract class A {
const A();
abstract final String name;
abstract final int id;
}
class B extends A {
const B();
#override
final String name = "B";
#override
final int id = 1;
}
class C extends A {
#override
String name = "C";
#override
int id = 1;
}
Note that I needed to add final qualifiers since const objects must be immutable. (Unrelated, but I also fixed the inappropriate use of the late keyword.)
In general, there will be cases where you cannot create a const constructor. If you want to use an instance of that type as a default argument in such cases, you can use null as a default value and assign a non-const value later.

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.

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

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

Polymorphism in Dart/Flutter

I have a number of classes that all extend StatefulWidget. I want each class to provide its own version of a method bool foo(), so that I can iterate over a collection of objects of these classes, calling foo() on each. What is the best/correct way to do this in Dart/Flutter? Mixins? What would the type of that collection be?
The functionality described can be achieved with Interfaces in Dart
class Widget {
}
abstract class MyCustomWidget extends Widget {
String foo( String argName);
}
class Widget1 implements MyCustomWidget {
String foo( String argName) {
return argName;
}
}
class Widget2 implements MyCustomWidget {
String foo( String argName) {
return '$argName$argName';
}
}
void main() {
Widget1 w = new Widget1();
Widget2 w2 = new Widget2();
var widgets = [w, w2];
for (int i = 0; i < widgets.length; i++) {
print(widgets[i].foo('hello ${i + 1}'));
}
}
That said, flutter recommends composition over inheritance.
See: Flutter StatefulWidget - State class inheritance?