It'll de-const-ify your Dart code!
The only reason why you should ever run this tool is if you are as curious as I was about the difference using const makes in a Flutter app.
My findings from running this on a 200k LoC production app were as follows:
- Dart AOT snapshot size increased around 3.3%. This is relative to the entire code & data size, including 3rd party packages and the Flutter/Dart SDK code. The % increase on just the const-removed code would be larger.
- Dart Heap usage increased around 1-1.5%. Around 0.4% increase relative to the total allocated memory for the app.
- UI thread frame times were significantly worse (+58%) in specific scenarios. Generally an increase of 4-6% was observed. Well designed state management is still key to managing unnecessary rebuilds in your app, however using
constcan unlock free performance by pruning unnecessary rebuilds without much thought from the developer. It's possible additional performance is gained from reducing GC churn & generally executing less code (as constructors don't get called as often).
dart pub get
dart bin/const_remover.dart <path_to_project_root>The tool will recursively look for Dart source files in the given directory. It will only process source files if they reside within /lib. This is a basic safety check to avoid modifying files in .dart_tool/, test/ or other locations. This check is naive, and merely looks for the presence of the substring /lib/ within the full path of the file.
You can modify the filter in the _processDirectory method in bin/const_remover.dart.
This tool is not distributed through pub.dev, I don't wish to pollute the package repository with silliness like this. Of course, if you wish to fork it and publish it yourself, I can't stop you.
- The tool is, for the most part, LLM generated. I was actually quite surprised at how well the 1st iteration worked. A human touch was added in some places where Gemini got stuck on incorrect assumptions of the
analyzerAPI. - It will not cover all cases, and some manual fixup will be required. Don't worry, the Dart Analyzer will tell you where to look.
- For constructors, moving more than one argument with default value to the initializer list does apply correct delimiter, and will result in code that needs manual fixup.
- The tool skips de-
constifying literals for "simple" types, such asint,double,bool,String. A skim through Introduction to Dart VM has made me doubt whether this choice was correct.
// Code before running const_remover
class MyClass {
final MyChildClass a;
final MyChildClass b;
const MyClass({this.a = const MyChildClass.foo(), this.b = const MyChildClass.bar()});
}
// Incorrect code generated by const_remover
class MyClass {
final MyChildClass a;
final MyChildClass b;
MyClass() : a = MyChildClass.foo() : b = MyChildClass.bar();
}
// Fixed code, with comma separated initializer list
class MyClass {
final MyChildClass a;
final MyChildClass b;
MyClass() : a = MyChildClass.foo(), b = MyChildClass.bar();
}I've put this project in the wild without intent to evolve it further, as I don't believe it has practical significance, short of one-off experiments. Regardless, any contributions are welcome.