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

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.

Related

Dart generics method not recognizing type

I have an abstract base class validator with a method which takes a generic type as parameter.
I will be passing generic type parameter to base class from the subclass inheriting the base class.
Base Class:
abstract class BaseValidator {
bool isValid<T>(T obj);
}
Child Class:
class IPv4Validator extends BaseValidator{
final IPV4_REGEX = "^((25[0-5]|(2[0-4]|1d|[1-9]|)d).?\b){4}\$";
#override
bool isValid<String>(String obj) {
bool hasMatch = RegExp(IPV4_REGEX).hasMatch(obj);
return hasMatch;
}
}
Here hasMatch takes in non nullable string. When I directly pass some string hasMatch doesn't throw an error.
But when I try to pass the generic value in the method parameter, it shows an error.
The argument type 'String' can't be assigned to the parameter type
'String'.
I couldn't able to understand why generic type is not accepting, even though its compile-time type.
The following code solves this particular problem. But it may be different from what you intended to implement. On the other hand, the code will be cleaner if you create a new concrete class for different data types.
abstract class BaseValidator<T> {
bool isValid(T obj);
}
class IPv4Validator extends BaseValidator<String>{
final IPV4_REGEX = "^((25[0-5]|(2[0-4]|1d|[1-9]|)d).?\b){4}\$";
#override
bool isValid(String obj) {
bool hasMatch = RegExp(IPV4_REGEX).hasMatch(obj);
return hasMatch;
}
}
Explanation.
In the line class IPv4Validator extends BaseValidator<String> we are not declaring a new class BaseValidator, it is already declared as BaseValidator<T>. Here we are inheriting the specialization of the existing generic class BaseValidator. While in the line bool isValid<String>(String obj), we declare a new function, so the compiler understands it as if we were declaring a new generic function with a parameter type named String. So, here bool isValid<String>(String obj) is equivalent to bool isValid<T>(T obj), just instead of name T we used name String, which is not an object String.
another fix that you can do is to use the covariant keyword, to implement that, try this:
abstract class BaseValidator<T> {
bool isValid(T obj);
}
class IPv4Validator extends BaseValidator {
final IPV4_REGEX = "^((25[0-5]|(2[0-4]|1d|[1-9]|)d).?\b){4}\$";
#override
bool isValid(covariant String obj) {
bool hasMatch = RegExp(IPV4_REGEX).hasMatch(obj);
return hasMatch;
}
}

how to get the extender or implementer child's Type

I have a class:
abstract class Foo {
String getName(T f);
}
and:
class Bar implements Foo {}
or
class Bar extends Foo {}
how can Foo know Bar and implement T as Bar?
UPDATE:
I considered statically passing the type of the child, like:
#override
String getName<Bar>(Bar p1) {
return p1.name;
}
this way I ran into this error: The property 'name' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!').
so, I edited it to be:
#override
String getName<Bar>(Bar p1) {
return p1!.name;
}
and now I'm getting this error: The getter 'name' isn't defined for the type 'Bar & Object'. Try importing the library that defines 'name', correcting the name to the name of an existing getter, or defining a getter or field named 'name'.
I guess the only solution, for now, is using dynamic type, like this:
abstract class Foo {
String getName(f);
}
and
class Bar implements Foo {
#override
String getName(f) {
return (f as Bar).name;
}
}
but I'd really like to know the answer to this question.
abstract class Foo {
String getName(T f);
}
should not be valid. T is not specified anywhere.
You need to specify a place for the generic to be passed:
abstract class Foo<T> {
String getName(T f);
}
Then pass that generic when you extend/implement the abstract class:
abstract class Foo<T> {
String getName(T f);
}
class Bar implements Foo<Bar> {
final String name = '';
#override
String getName(Bar p1) {
return p1.name;
}
}
If getName will always accept an implementer of Foo, you can remove the generic and instead use the covariant keyword:
abstract class Foo {
String getName(covariant Foo f);
}
class Bar implements Foo {
final String name = '';
#override
String getName(Bar p1) {
return p1.name;
}
}

How can I add a custom function inside the class annotated with the 'freezed' library?

I have defined a class like this and annotated with the freezed library.
#freezed
#immutable
abstract class CommentMediaAttachmentModel with _$CommentMediaAttachmentModel {
const factory CommentMediaAttachmentModel({
final String type,
final String mediaUrl,
final int width,
final int height
}) = _CommentMediaAttachmentModel;
bool isAnimated() {
return type == 'ANIMATED';
}
}
I'd like to add a quick function isAnimated to determine the type variable, but on compilation, it doesn't allow me to do so:
lib/presentation/comment/model/comment_attachment_model.freezed.dart:292:7: Error: The non-abstract class '_$_CommentMediaAttachmentModel' is missing implementations for these members:
- CommentMediaAttachmentModel.isAnimated
Try to either
- provide an implementation,
- inherit an implementation from a superclass or mixin,
- mark the class as abstract, or
- provide a 'noSuchMethod' implementation.
Upon checking the generated class _$_CommentMediaAttachmentModel, isAnimated function isn't implemented. How can I achieve that?
Edit: Below is the code of _$_CommentMediaAttachmentModel.
I'm not sure why I cannot paste that snippet to SO, it just said the code is malformed. I will use a screen capture instead:
To manually define methods/properties on the class, as stated in freezed documentation, you have to define a single private constructor:
#freezed
#immutable
abstract class CommentMediaAttachmentModel with _$CommentMediaAttachmentModel {
const CommentMediaAttachmentModel._(); // Added constructor
const factory CommentMediaAttachmentModel({
final String type,
final String mediaUrl,
final int width,
final int height
}) = _CommentMediaAttachmentModel;
bool isAnimated() {
return type == 'ANIMATED';
}
}
Basically You need to implement isAnimated inside the _$CommentMediaAttachmentModel too. because it is a mixin of the abstract class.

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?

How to extend a class in Dart/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();
}