-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
The analyzer does not understand unmodifiable list
#48551
Comments
It could be useful to track the type of a list literal in such a way that the constant variable in this example is known to be an unmodifiable list. However, we do specify in the section 'List Literal Inference' that every list literal has a type of the form
@lrhn, do you plan to introduce system classes that describe the behavior of an unmodifiable list, set, and map? Presumably, they would be superinterfaces of the current However, this does look like a topic that has been raised a number of times in the past, and it is not obvious how we'd do it, without causing hugely breaking changes... |
We have no plan to introduce an interface for the "non-modifying Not a The We made that decision a long time ago to not have a "read-only" interface for our collections, and haven't changed it since. We could reconsider, but that would be a big change to the libraries, and would potentially require a large non-trivial migration. The usual argument against "read only" interfaces is that it makes code authors have to choose which interface to use in their APIs. Do you accept a (let's call it) We double the complexity of the core Dart collections API for everybody. The advantages of having those interfaces would be that you won't get run-time errors when passing a fixed-length or unmodifiable list into something which does an All in all, the cost doesn't seem to match the benefit. If the analyzer wants to detect that you're calling modifying methods on a constant list created by a constant list literal, they should have all the information needed. |
Thought so. ;-)
This was the part that I was worried about: Noting that we won't make 'unmodifiable' for collections a property of the static type itself, the analyzer would need to add some "unofficial extras" to |
However far the benefits outweigh the costs. If it brings benefit to users, and the benefit is worth the cost (and opportunity cost) of implementing and maintaining it, I see no reason to not make our tools provide special-cased warnings about specific misuses of API. Calling |
It is easy to know that the
however, it really gets out of track when you have some lines between the |
@lrhn wrote:
Sure, lints and hints can do whatever they want, and 'warnings' might be treated similarly at some point. However, I made the distinction between properties that rely on specified information (in particular, static types), and properties that rely on non-specified information. The fact that both kinds of information must be propagated between program locations implies that any "extra" information will make common objects consume more memory (e.g., a Perhaps this is not a problem at all, but I thought it was at least a thing to keep in mind, which is the reason why I pushed a bit on the (impossible) idea that it could be maintained as a proper part of the static types. In any case, we're just looking at this from the outside. @stereotype441, @scheglov, WDYT? |
Writing a lint that can see the flaw in @adnanjpg's example would definitely be possible, and not too difficult. But most real-world examples of this sort of problem require synthesizing information from multiple functions across the program. Consider this example: import 'dart:math';
class C {
void foo() {
var listOfInts = const [1, 2, 3];
bar(listOfInts);
}
void bar(List<int> values) {
print('$values');
}
}
mixin M {
void bar(List<int> values) {
values.shuffle(Random());
}
}
class D extends C with M {}
main() {
D().foo();
} This example has the same flaw, but in order to see that the flaw exists, you can't look at individual functions in isolation. You have to see that Automating this sort of analysis is definitely possible, but it's tricky. I don't think we have any definitive plans to add this sort of functionality to the linter or the analyzer, though we have talked about things like this before. IIRC I've discussed ideas like this with @pq and @bwilkerson in the past. So they might want to weigh in with their thoughts. |
I think that sums it up fairly well. The ability to detect at analysis time where runtime exceptions will occur is hugely valuable, but in this case the percentage of places where we could do so, given the performance constraints, is small enough that it probably isn't worth it. We have discussed adding some kind of whole-program analysis (@srawlins), and this is a good example of what we'd be able to do with it, but there are no concrete plans at the moment for adding such a tool. |
@adnanjpg big +1 on this one. The basic problem with immutable lists and Dart is that we don't see any problems at compile time. There are two ways that Dart could deal with the problem:
Meantime, check out this package: fixed_collections It just deprecates the mutation members, so you get a warning when you try to use this. You can use |
It does not look to me that import 'package:fixed_collections/fixed_collections.dart';
main() {
const items = [0, 1, 2];
f(FixedList(items));
}
void f(List<int> items) {
items.add(42);
} |
@scheglov, you have to use the |
This tracker is for issues related to:
In your issue, please include:
Dart SDK version: 2.16.1 (stable) (Tue Feb 8 12:02:33 2022 +0100) on "macos_x64"
let's go over an example:
here, as clearly it is that
foo
cannot be modified as it is constant, the analyzer does not understand that and does not warn, so this bug is only catchable on runtime.the output:
The text was updated successfully, but these errors were encountered: