0

I have a question related to Dart Null Safety concept.

Imagine I have a class called Bird

class Bird{
Object character;

Bird();
}

and Pigeon

class Pigeon extends Bird{
String name;

Pigeon();
}

Now, because of Null Safety on Dart, the character object must be instantiated. I want to instantiate that in the constructor because I want the bird class can be testable using Mockito.

But, when I wrote this

class Bird{
late Object character;

Bird(this.character);
}

The Pigeon class shows an error because the Bird class doesn't have any zero-argument constructor.

My workaround is by using a not required argument like this.

class Bird{
late Object character;

Bird({Object? character}) : this.character= character ?? GetIt.I<Object>();;
}

But, I don't like the GetIt part for my default value. Moreover, another programmer may think it is an optional argument because I didn't mark it as required which can lead to an error.

So, how is the best practice to solve this case?

Darari Nur Amali
  • 465
  • 3
  • 13
  • Exactly what do you want `character` to be for a `Pigeon` instance? Why don't you have `Pigeon` pass an appropriate argument to the `Bird` constructor? You also seem to be misunderstanding some other things (e.g., you don't need to use `late`, and `required` is necessary for *named* arguments to distinguish required from optional named arguments). – jamesdlin Jan 17 '21 at 08:54
  • Don't use `late`. It is very bad idea. Try to find a better solution. – mezoni Jan 17 '21 at 09:03
  • @jamesdlin the character object is just an example. It can contain bird basic characteristic (e.g. type of the bird's beak). Furthermore, in a non-null variable, the "required" keyword is necessary if you declared that in the constructor as a namedArgs. – Darari Nur Amali Jan 17 '21 at 10:49
  • @mezoni agreed. Have any idea? That's is why I want a discussion here. – Darari Nur Amali Jan 17 '21 at 10:49
  • @DarariNurAmali No fair, the code you originally posted did not have `character` as a named argument, so as I said, `required` would *not* be necessary for that. Additionally, as I also said, `late` is *not* necessary at all (unless you have some other `Bird` constructor that neglects to initialize `character`). – jamesdlin Jan 17 '21 at 11:17
  • 1
    @DarariNurAmali Anyway, my point is that we can't give a good answer about how to solve your problem, because without knowing what you want `character` to be for `Pigeon`, we can't really tell how you should initialize it. If it should have the same initial value for all `Pigeon` instances, then the `Pigeon` constructor should just call the `Bird` constructor with an appropriate argument. Or if it's something that varies across `Pigeon`s, then it perhaps should be an argument to `Pigeon`'s constructor too. – jamesdlin Jan 17 '21 at 11:20

3 Answers3

0

You can either use Named Argument Constructor to make character optional or remove late and ? like this

class Bird{
  Object character;

  Bird(Object character) : this.character = character ?? GetIt.I<Object>();
}

Your Named Argument Constructor will look like this

class Bird{
  Object character;

  Bird({this.character = DEFAULT_CONST_VALUE});
}
dm_tr
  • 4,265
  • 1
  • 6
  • 30
  • Object character is an Object and to instantiate need new Object() which is not constant. So, it is impossible. Moreover, a non-null variable should be declared along with the "required" keyword in the namedArgs. – Darari Nur Amali Jan 17 '21 at 10:42
0

What about this solution?

class Bird {
  Object character;

  Bird({this.character});
}

class Pigeon extends Bird {
  String name;

  Pigeon({this.name, Object character}) : super(character: character);
}

Or even this?

class Bird<T> {
  T character;

  Bird({this.character});
}

class Pigeon extends Bird<String> {
  String name;

  Pigeon({this.name, String character}) : super(character: character);
}

Or this?

class Character {
  //
}

class Bird<T extends Character> {
  T character;

  Bird({this.character});
}

class Pigeon extends Bird<PigeonCharacter> {
  String name;

  Pigeon({this.name, PigeonCharacter character}) : super(character: character);
}

class PigeonCharacter extends Character {
  //
}
mezoni
  • 10,684
  • 4
  • 32
  • 54
  • Should we have to declare all non-null values from the parent class? – Darari Nur Amali Jan 17 '21 at 10:52
  • Three ways. Use the `late` keyword when declaring and initialize them later. Declare them as nullable. Declare them as non-nullable and initialize them with appropriate value. It is up to you to decide. – mezoni Jan 17 '21 at 10:58
0

You need to use the named constructor as below

class Bird{
 Object character;
  
 Bird({this.character});
  
 Bird withCharater(Object character) {
   return Bird(character: character);
 }
}

class Pigeon extends Bird{
 String name;

 Pigeon(); 
}