I have found some strange behaviors trying to check the runtime type of some objects in Dart. Let's make a simple example:
main(List<String> args) {
List<Map> l1 = new List<Map>();
l1.add(new Map<String, int>());
List<int> l2 = ['Start', 'Stop'];
checkType(l1.runtimeType);
checkType(l1[0].runtimeType);
checkType(l2.runtimeType);
}
checkType(Type type) {
switch(type) {
case List:
print('it is a List!');
break;
case Map:
print('it is a List!');
break;
default:
print('Unmanaged type $type');
break;
}
}
this program has the following output:
Unmanaged type List<Map>
Unmanaged type _InternalLinkedHashMap<String, int>
Unmanaged type List
The first case cannot be checked in a switch statement because if I try to set a "List<Map>
" case I get the error: in constant expressions, operand(s) of this operator must be of type 'num'
The second cannot be matched because using the _InternalLinkedHashMap in a case gets the following error: Case expression must be constant.
In the last case I have defined the List as a List of ints (List<int>
), but the system ignores it and considers it as a simple List.
I think that this is misleading and such a declaration should be forbbiden.
Any help/suggestion?
If you want to do flow control based on object's type, you actually want to do it based on whether an object's class implements an interface, not what it's run time type is. This is what the Type Test Operators is
and is!
are for.
Remember that in Dart a class is also an interface, so you can test if an object is a specific class.
class Something {
...
}
var s = new Something();
print(s is Something); // true
Note that things we tend to think of as 'classes' such as List
an Map
, are not classes, they are interfaces. Anything that returns a instance of such (including constructors) in fact returns a class that implements the interface.
You can use generics, but be careful.
void main() {
var a = [1, 2, 'three'];
print(a is List); // True
print(a is List<int>); // True!!!!
print(a is List<String>); // True!!!!
var b = new List<int>.from([1, 2, 3]);
print(b is List); // True
print(b is List<int>); // True
print(b is List<String>); // False
}
A class can implement an interface via explicitly implementing it, inheriting from a class that implements it, or through a mix-in.
class Base {
void a() {}
}
class Mix {
void b() {}
}
class Mixed extends Base with Mix {}
class Explicit implements Base {
void a() {}
}
void main() {
var c = new Mixed();
print(c is Mixed); // True
print(c is Base); // True
print(c is Mix); // True
var d = new Explicit();
print(d is Base); // True
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With