Skip to content

Automatically Type Casting from SuperClass to SubClass #839

New issue

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

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

Already on GitHub? Sign in to your account

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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