0

I have two related classes: Animal and Cat (which extends Animal) then I make an instance of Cat and check if the instance is type Cat so I set amount of paws to four.

abstract class Animal {
}

class Cat extends Animal {
  int? pawsAmount;
}

void main(List<String> arguments) async {

  Animal barsik = Cat();

  if (barsik is Cat) {
    barsik.pawsAmount = 4;
  }

}

and it works well BUT the follow code is not:

abstract class Animal {
}

class Cat extends Animal {
  int? pawsAmount;
}


class Consumer {

  Animal _animal;

  Consumer(Animal animal) : _animal = animal;

  void init() {
    if (_animal is Cat) {
      _animal.pawsAmount = 4;
    }
  }

}

void main(List<String> arguments) async {

  Animal barsik = Cat();

  if (barsik is Cat) {
    barsik.pawsAmount = 4;
  }

  final consumer = Consumer(barsik);
  consumer.init();

}

it has got an error:

bin/constest.dart:17:15: Error: The setter 'pawsAmount' isn't defined for the class 'Animal'.
 - 'Animal' is from 'bin/constest.dart'.
Try correcting the name to the name of an existing setter, or defining a setter or field named 'pawsAmount'.
      _animal.pawsAmount = 4;
              ^^^^^^^^^^




if I change

if (_animal is Cat) {
  _animal.pawsAmount = 4;
}

to

if (_animal is Cat) {
  (_animal as Cat).pawsAmount = 4;
}

it works fine

Is there any way to make the code work?

Thank you!

Cyrax
  • 688
  • 6
  • 12

1 Answers1

1

Dart only promotes local variables. The _animal is an instance variable, which means that it can potentially change value at any time (the compiler won't start trying to predict whether it actually does), and therefore you can't promote it - the value might change between the check and the later use, making the check an insufficient guarantee.

I would move the value into a local variable before checking it:

  void init() {
    var animal = _animal;
    if (animal is Cat) {
      animal.pawsAmount = 4;
    }
  }
lrn
  • 64,680
  • 7
  • 105
  • 121
  • Thank you for your answer! But if I make _animal 'final' the problem will exist – Cyrax Mar 18 '21 at 10:07
  • It doesn't matter if the variable is `final` or not. It could be overridden by a getter in a derived class. – jamesdlin Mar 18 '21 at 12:08
  • 1
    There is no way to make the compiler believe that a non-local variable won't change. In many cases, there are non-obvious ways it could fail. Even if it's a final static variable, which surely cannot change, allowing you to promote that variable would make it a breaking change to change the variable to a getter. Because of that, you cannot promote non-local variables. – lrn Mar 18 '21 at 13:41