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
casting json result to List<List<String>> #48686
Comments
Dart maintains a representation of the actual type arguments of any given instance of a generic class at run time. This is needed in order to maintain soundness in various situations, including the situation where we execute things like This means that a If you perform a type cast (like So in order to allow the list-of-lists to be typed as var json = <dynamic>[
<dynamic>['Hello'],
];
void main() {
var typedJson = <List<String>>[
for (List innerList in json) List<String>.from(innerList)
];
print(typedJson.runtimeType);
} If you do not wish to copy the entire structure of the given nested list then you can also work on the objects that you actually have, which means that every element of a list has type |
To be precise, I think that when you say that you cast to As @eernstg says, those member accesses do throw because the members are var typedJson = [...json.map((list) => list.cast<String>())]; // aka json.map((list) => list.cast<String>()).toList()
var typedJson = [for (var list in json) <String>[...list]]; // relies on implicit downcast from dynamic.
var typedJson = json..asMap().forEach((i, v) => json[i] = v.cast<String>()).cast<List<String>>(); |
I understand what has been said. I also have no problem producing code which produces what I want. What bothers me is that Something like Then I can say The "breaking the language problem" is a concern for the error message, but perhaps there could be some way to at least turn on a warning for the unclear typing |
@drpond1, I'm not 100% sure about the intended rules around type arguments like void main() {
List<dynamic> xs = [1, true];
List<cast.int> ys = xs; // This would be OK, but implies dynamic checks later on.
for (int i in ys) {
print(i); // Prints '1', then throws because `true` isn't an `int`.
}
} We could have a language mechanism like this, but we do already have a library feature which is very similar: void main() {
List<dynamic> xs = [1, true];
List<int> ys = xs.cast<int>(); // Create a wrapper around `xs` that checks each element type at run time.
for (int i in ys) {
print(i); // Prints '1', then throws because `true` isn't an `int`.
}
} |
The When you do Now, if we had a feature like You can't assign a In that way, it's more reminiscent of a view. It's a static behavior put on top of a |
No disagreements with either reply. This is not an issue of the static typing... that works exactly how I expect. The problem is that the runtime ends up treating the items in the list as So either:
The possible language enhancement if needed is
If you think I am wrong about this, there should be an example where |
It's not just treating them as
Doing So, var o = <Object>[<String>[], <String>["foo"]];
var s = o.cast<List<String>>(); // Correct use of `cast`
var l1 = s[0]; // l1 has type List<String> and the read succeeds. is a valid use of The thing that makes
We don't want |
|
@drpond1, thanks for your very constructive approach to discussions like this one! I'll close this issue, we'd just create new ones as needed. One thing to note is that there is a proposed language feature known as 'views', and that feature offers support for establishing type safe access to dynamic object structures without creating any wrapper objects (view methods are similar to extension methods in that they are resolved statically). Again, the assumption is that the dynamic object structure satisfies some constraints, and there will be run-time errors if the given object structure actually violates those constraints. JSON decoding is a typical example where this can be a reasonable assumption: We might very well receive a Here's how we can safely navigate an object structure with that schema, using a couple of views to model the schema. I'm using 'lls' to abbreviate List of List of String in names, and 'ls' to abbreviate List of String, with the usual CamelCasing, indicating that an 'lls' is a // Using the proposed feature 'views'. Minimal example, just providing `[]`.
view LlsView on List<dynamic> {
LsView operator[](int index) => this[index]!;
}
view LsView on List<dynamic> {
String operator[](int index) => this[index]!;
}
var json = <dynamic>[<dynamic>[' Hello!']];
void main() {
LlsView lls = json;
LsView ls = lls[0];
print(ls[0].trimLeft());
} The assignment of So this means that we've keeping track of the underlying structure as declared in the JSON schema (and encoded in But on the other hand, the view methods are technically just like top-level functions: There is no wrapper object corresponding to the In this kind of situation, I would expect that we would use code generation based on an actual document specifying a JSON schema of sorts, such that we'd get all the different kinds of expectations in a given object structure correct without a lot of manual work. |
Using IntelliJ CE for a web app I have the following concern. debugging with Dart 2.16
I decode an object with json and then cast it to a
List<List<String>> meta
Later, I try
for (List<String> list in meta) {...
This compiles but produces a runtime error of
List<dynamic>
is not aList<String>
The type in the debugger is cast._new (I think) and the item
looks like a
List<String>
.It seems to me that this is not a great behavior. I think the runtime
ought to know that this is ok, but that further runtime checks will
need to be done when the list in the for loop is read.
If this is not going to be allowed at runtime, then I think the type of meta should be
a compile time syntax error.
Some way of specifying
List<List<cast.String>>
might be an alternative, althoughList<List<dynamic>>
is ok.If needed, I can produce and test a simple example to duplicate the behavior.
The text was updated successfully, but these errors were encountered: