Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dart typecasting error

Tags:

casting

dart

I have an abstract class Event and a concrete subclass that extends it called PlaceChangeEvent. Inside an event listener, I have the following code:

void onEvent(Event event) {
    PlaceChangeEvent pce = null;
    if(event is PlaceChangeEvent)
        pce = (PlaceChangeEvent)event;      // <== error is here
    else
        throw new Exception("Event is not a PlaceChangeEvent.");

    Place place = pce.place;

    presenterProvider.display(place);
}

So if the runtime type of event is PlaceChangeEvent, then I need to cast the event to that type so that I can access its properties. But I'm getting a compiler error on the typecast, stating:

A value of type 'Type' cannot be assigned to a variable of type 'PlaceChangeEvent'

Where am I going wrong, and what do I need to do to fix it?

like image 352
IAmYourFaja Avatar asked Dec 31 '13 15:12

IAmYourFaja


People also ask

Is Dart strongly typed?

🎯 Dart is strongly-typed language. When using Firestore, a NoSQL database, be careful with accessing fields in a document to ensure it is the expected type, & to handle nulls.

How do I check my Dart data type?

Dart objects have runtimeType property which returns Type . To check whether the object has a certain type, use == operator. Unlike is , it will only return true if compared to an exectly same type, which means comparing it with its super class will return false .

What is covariant Dart?

Covariant is a fancy type theory term, but it basically means 'this class or its subclasses'. Put another way, it means types that are equal or lower in the type hierarchy. You are explicitly telling Dart to tighten the type checking of this argument to a subclass of the original.


1 Answers

In Dart

  1. upcasts are implicit. If B is a subclass of A, then B b = a (where a is an instance of class A) is warning free and silently casts a to B. In Java you would have needed to write B b = (B) a.

  2. the dynamic type is an always-present escape hatch. If B and C are not in the same hierarchy, then temporarily assigning to the dynamic type will make the cast warning-free.

    B b = someB;
    var tmp = b;
    C c = tmp;
    
  3. One can do an explicit check using is. The is check returns true if the object is of the right type. There are also some very simple rules that propagate is-check types. For example, if is is used inside an if condition, then the corresponding branch uses this information for type-warnings.

    Object o;
    o.foo();  // warning: foo does not exist on Object.
    if (o is A) {  // assuming that A contains 'foo'.
      o.foo();  // warning-free.
    }
    
  4. One can explicitly check and throw if a type is not the expected one with as. This operator does not throw when the left-hand side is null.

For your example this boils down to:

No explicit check (1):

void onEvent(Event event) {
  // Implicit upcast. PlaceChangeEvent is subclass of Event.
  PlaceChangeEvent pce = event;
  Place place = pce.place;
  presenterProvider.display(place);
}

With an is-check (3):

void onEvent(Event event) {
  if (event is PlaceChangeEvent) {
    // Static type system propagates type. No need for variable.
    Place place = event.place;
    presenterProvider.display(place);
  } else {
    // Note: this doesn't look like an exception, but an error.
    throw new Exception("Event is not a PlaceChangeEvent.");
  }
}

Using as (4):

void onEvent(Event event) {
  Place place = (event as PlaceChangeEvent).place;
  presenterProvider.display(place);
}

Alternatively, if you expect to receive a PlaceChangeEvent, you should simply change the type of the argument:

void onEvent(PlaceChangeEvent event) {
  Place place = event.place;
  presenterProvider.display(place);
}

In checked mode this will catch bad types, and in unchecked mode it will throw when accessing event.place. This is generally the preferred way.

like image 184
Florian Loitsch Avatar answered Nov 05 '22 08:11

Florian Loitsch