Two problems:
- Build systems automatically pass flags to dart2js to make it easy for developers to get the best of dart2js production capabilities out of the box without any configuration: this may include compiling with
--minify
and--omit-implicit-checks
today. Our flags will change, and we want that change to be transparent and not a breaking change for build systems. - We want users to be aware of how safe/unsafe certain flags are. Documentation is not enough for this.
Ideas
--production
flag:
To improve the build system integration and prevent having to change tools downstream on every change to our compiler, we were planning to add a new set of flags that will evolve in time. Because the main goal build systems have is to have a flag to build apps at production level, we could focus on a single flag for that, e.g. --production
. The means of a production compile may vary as we implement more features. For example, once we implement our optimizations for Dart2, we can deprecate the behavior of omit-implicit-checks
, but may introduce a new option to allow unsafe casts in certain framework’s code.
So initially --production
would be equivalent to --minify --omit-implicit-checks
, but later it will be equivalent to --minify --allow-unsafe-cast-operator
or something else.
--unsafe-optimizations
flag:
One suggestion to address the second problem is to purposely use a naming convention of flags that makes it easier for users to see how safe or unsafe the flag is. For example: it has been proposed to add --unsafe-optimizations
and --safe-optimizations
flags that take as arguments an optional list of optimizations.
- Accepted unsafe optimizations:
default, all, none, allow-unsafe-cast-operator, lax-runtime-type, omit-parameter-checks, omit-implicit-downcasts, trust-primitives
- Accepted safe optimizations:
default, all, none, minify, inlining, type-inference, rti, runtime-type
(and in the future some SSA optimizer steps can be listed here). - The
default
safe optimizations are all butminify
- The
default
unsafe optimizations may only includeallow-unsafe-cast-operator
initially.
Revised --production=value
flag:
Another suggestion: allow values to --production
:
--production=safe
(like--safe-optimizations=all
)--production=almost-safe
(unsafe-cast-operator, lax-runtime-type-to-string)--production=unsafe
(omit-implicit-checks)--production=really-unsafe
(trust-primitives)
and have --production
(with no args) default to --production=safe
or --production=almost-safe
.
The idea is that we could also provide a warning if an underlying flag is used without using the production flag. For example:
dart2js --production=unsafe # produces no warnings
dart2js --omit-implicit-checks # produces a warning about how you should test your app.
I’m starting to like this last approach. Thoughts?
@vsm had an interesting suggestion on wording:
O2 for us is about TypeError, O3 includes ArgumentError, NoSuchMethodError on null, and RangeError produced from the corelibs.
I believe so, yes. Today only a handful of teams use the latter. Externally, we were inclined to enable omit-implicit-checks by default on package:build, but not trust-primitives.
Thinking more about this, the reason I’m so hesitant on grouping implicit-checks and trust-primitives in the same bucket is that the latter is more susceptible to invalid user input. So when I think of testing for omit-implicit-checks, normally DDC unit tests, plus some integration tests for the RPC layer tends to be enough to ensure that the app will be fine. With trust-primitives, I believe developers need to be more cautious about how different user inputs may affect their code and think more about off-by-one errors and such.
At the same time – once we implement #34003, I feel more comfortable grouping them together because it will be less likely for users to need to use omit-implicit-checks altogether.
Trying to put together all suggestions thus far, here is an updated proposal: