Coder Social home page Coder Social logo

List.toList() Type problem about sdk HOT 5 CLOSED

feduke-nukem avatar feduke-nukem commented on July 21, 2024 1
List.toList() Type problem

from sdk.

Comments (5)

lrhn avatar lrhn commented on July 21, 2024 1

It's expected and specified behavior.

The analyzer doesn't warn, because it's perfectly valid code.

The inherent unsoundness in covariant generics is so deep in the language that it's impossible to warn about it, because that would make almost all uses of (for example, but not limited to) List.add give a warning.

It might be possible to locally deduce that you are casting a List<int> to List<Object>, and shortly after doing .add(x) on it with something that's not an int. But it's also incredibly easy to do that without the analyzer having any chance of recognizing it.

from sdk.

lrhn avatar lrhn commented on July 21, 2024

Because your code is not type safe. And nor is List.

It's the same error you'll get from

List<Object?> list = <C>[];
list.add(B()); // Type error, B is not a C

The function test takes a Holder, aka Holder<Object?>.
That contains some List<Content<T>>, deleted you haven't shown the type. I'm assuming it's a List<Content<C>>, but from where your code is looking, it has static type List<Content<Object?>>

If you try to add a Content<B> to that, it fails, as it should.

If you do .toList() on it, you get another List<Content<C>> with static type List<Content<Object?>>, and adding still fails.

If you do var list = List.of(...);, you create a new List<Content<Object?>> with the same elements. That's safe, and you can safely add to it. That is, the static element type becomes the runtime element type of the newly created list.
That's why it works.

from sdk.

feduke-nukem avatar feduke-nukem commented on July 21, 2024

Because your code is not type safe. And nor is List.

It's the same error you'll get from

List<Object?> list = <C>[];
list.add(B()); // Type error, B is not a C

The function test takes a Holder, aka Holder<Object?>. That contains some List<Content<T>>, deleted you haven't shown the type. I'm assuming it's a List<Content<C>>, but from where your code is looking, it has static type List<Content<Object?>>

If you try to add a Content<B> to that, it fails, as it should.

If you do .toList() on it, you get another List<Content<C>> with static type List<Content<Object?>>, and adding still fails.

If you do var list = List.of(...);, you create a new List<Content<Object?>> with the same elements. That's safe, and you can safely add to it. That is, the static element type becomes the runtime element type of the newly created list. That's why it works.

Thanks for answer but I still don't get it. toList() is a shortcut for List.of() (basically the same operation) then why behaviour differs?

from sdk.

lrhn avatar lrhn commented on July 21, 2024

If list is an instance of List<E>, then list.toList() works like List<E>.of(list), no matter what the static type of list is.

Doing List.of(list) infers the type of the created list from the static type of list, because the compiler infers the missing type argument to List. This is List<T>.of(list) for some T, which is inferred because you didn't write it.

Which means:

List<Object> list = <int>[1]; // Valid, up-cast.
var list2 = list.toList(); // Same as `List<int>.of(list);`, called by list itself, which knows it's an `int` list.
var list3 = List.of(list); // Same as `List<Object>.of(list);`, inferred from static type.

Those two calls are not the same.

from sdk.

feduke-nukem avatar feduke-nukem commented on July 21, 2024

If list is an instance of List<E>, then list.toList() works like List<E>.of(list), no matter what the static type of list is.

Doing List.of(list) infers the type of the created list from the static type of list, because the compiler infers the missing type argument to List. This is List<T>.of(list) for some T, which is inferred because you didn't write it.

Which means:

List<Object> list = <int>[1]; // Valid, up-cast.
var list2 = list.toList(); // Same as `List<int>.of(list);`, called by list itself, which knows it's an `int` list.
var list3 = List.of(list); // Same as `List<Object>.of(list);`, inferred from static type.

Those two calls are not the same.

So is that an expected behaviour?

Why doesn't an analyzer warn about it or something?

from sdk.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.