Skip to content
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

List<T>.map loses type information when passing to constructor #32721

Closed
passsy opened this issue Mar 30, 2018 · 3 comments
Closed

List<T>.map loses type information when passing to constructor #32721

passsy opened this issue Mar 30, 2018 · 3 comments
Labels
closed-duplicate Closed in favor of an existing report

Comments

@passsy
Copy link

passsy commented Mar 30, 2018

It seems like dart is losing the type when calling a generic constructor inside map (and reduce). Is this intended? Is there a workaround?

I did not expect this from a statically typed language.

class Generic<T> {
  final T thing;
  Generic(this.thing);
}

void main() {
    print(Generic("test").runtimeType);
    // Expected: Generic<String>
    // Actual: Generic<String>

    var list = ["a", 1, new Text("hello")];

    list.forEach((it) => print(it.runtimeType));
	// Expected: String, int, Text
    // Actual: String, int, Text

    list.map((it) => Generic(it)).forEach((it) => print(it.runtimeType));
    // Expected: Generic<String>, Generic<int>, Generic<Text>
    // Actual: Generic<Object>, Generic<Object>, Generic<Object>
}

Running with
Dart version 2.0.0-dev.41.0.flutter-2f68e82526

@matanlurey
Copy link
Contributor

Your list type is a List<Object>.

Dart doesn't have structural typing, so:

['a', 1, new Text('hello')]

...'s closest shared interface is Object - or WAI.

There is no way to currently say "this is a list of different known static types".

@matanlurey
Copy link
Contributor

That being said, to be clever, you could write a custom map function.

NOTE: This requires Dart2 semantics.

Iterable<Object> map3<A, B, C>(Iterable<Object> elements) sync* {
  for (final e in elements) {
    if (e is A) {
      yield new Generic(e);
    }
   if (e is B) {
      yield new Generic(e);
    }
   if (e is C) {
      yield new Generic(e);
    }
  }
}
main() {
  var list = ["a", 1, new Text("hello")];
  map3<String, int, Text>(list).forEach((it) => it.runtimeType);
}

... should work as you intended. Obviously it's not a great general solution.

@dgrove dgrove added the closed-duplicate Closed in favor of an existing report label Mar 30, 2018
@dgrove
Copy link
Contributor

dgrove commented Mar 30, 2018

This is currently WAI - we don't know if we'll implement union types (#4938) at some point.

@dgrove dgrove closed this as completed Mar 30, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-duplicate Closed in favor of an existing report
Projects
None yet
Development

No branches or pull requests

3 participants