Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Automatically Type Casting from SuperClass to SubClass #839

Closed
LuizMoratelli opened this issue Feb 14, 2020 · 2 comments
Closed

Automatically Type Casting from SuperClass to SubClass #839

LuizMoratelli opened this issue Feb 14, 2020 · 2 comments
Labels
bug There is a mistake in the language specification or in an active document

Comments

@LuizMoratelli
Copy link

LuizMoratelli commented Feb 14, 2020

Automatically type casting from the SuperClass A to the SubClass B if in the initial value t there is only one type of SubClass.

import 'dart:collection';

class A {}

class B extends A {}

void main() {
  final Map<String, A> t = {"0": B(),} as LinkedHashMap<String, A>; // Without object of another extended type of A or an object of type A 
  print(t.runtimeType);

  t.addAll({"2": A()});
  print(t);
}

Output:

_InternalLinkedHashMap<String, B>
Unhandled exception:
type '_InternalLinkedHashMap<String, A>' is not a subtype of type 'Map<String, B>' of 'other'
#0      MapMixin.addAll (dart:collection/maps.dart)
#1      main (file:///home/runner/WonderfulUnwelcomeRar/main.dart:11:6)
#2      _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:305:19)
#3      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:172:12)
exit status 255

But if I set more than one type of SubClass, or also use the SuperClass, it works fine.

import 'dart:collection';

class A {}

class B extends A {}

void main() {
  final Map<String, A> t = {"0": B(), "1": A()} as LinkedHashMap<String, A>; // With more than one SubClass or also using the SuperClass

  print(t.runtimeType);

  t.addAll({"2": A()});
  print(t);
}

Output:

_InternalLinkedHashMap<String, A>
{0: Instance of 'B', 1: Instance of 'A', 2: Instance of 'A'}
@LuizMoratelli LuizMoratelli added the bug There is a mistake in the language specification or in an active document label Feb 14, 2020
@eernstg
Copy link
Member

eernstg commented Feb 14, 2020

The problem is that you are using a type cast, as LinkedHashMap<String, A>. This means that there is no context type for the map itself (because a type cast is all about saying "I know what the type is, so the type checker should stay out of this"), and this means that the type argument for {"0": B(),} is chosen by a bottom-up analysis: The best type we can give this map when the context has no opinion is Map<String, B> (ok, it's a subtype of that, but inference on map literals constrains the type in terms of Map).

Further down this creates a problem, because you can't and an A to a Map<String, B>`.

So you should avoid the cast in the case where you want to rely on inference from the context. Alternatively, you could give the type arguments to the map itself: <String, A>{...}.

When you actually put an A into the map when it is created it will have type Map<String, A>, which is the reason why you don't get the dynamic error in example 2.

Of course, there is a connection to variance (cf. #524, #753) here as well, because the reason why it is unsafe to have a Map<String, B> where the static type is Map<String, A> is that you can do things like addAll, and we're considering adding variance to Dart in order to make that statically safe.

@eernstg
Copy link
Member

eernstg commented Feb 14, 2020

I'll close this issue because this is working as intended.

@eernstg eernstg closed this as completed Feb 14, 2020
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug There is a mistake in the language specification or in an active document
Projects
None yet
Development

No branches or pull requests

2 participants