Sdk: Dart const constructor does not allow using properties from a possibly const constructor argument

Created on 24 Aug 2020  路  3Comments  路  Source: dart-lang/sdk

Happens on DartPad, Dart SDK 2.9.1, Chrome.
The following code contains compilation errors.

main(){}
class EmailState {
  final String email;
  final bool emailVerified;

  const EmailState(this.email, this.emailVerified);

  const EmailState.from(EmailState emailState)
      : this(
          emailState?.email,
          emailState?.emailVerified,
        );
}

The compiler outputs the following:

Error compiling to JavaScript:
main.dart:10:11:
Error: Not a constant expression.
          emailState?.email,
          ^^^^^^^^^^
main.dart:11:11:
Error: Not a constant expression.
          emailState?.emailVerified,
          ^^^^^^^^^^
Error: Compilation failed.

Example: https://dartpad.dev/d315a7d07590ec6e97bf373fcb20d135
I believe the issue is for Common Front End (CFE) and kernel.

This is a request to allow this behavior; the producing of these errors is not intuitive, as such a const initialization could theoretically happen at compile time.

closed-as-intended

Most helpful comment

That's working as intended.

You can never read properties of an object in constant or potentially constant code (except String.length).
We have no way to mark a property as being "constant", so it is impossible to see from the interface whether the property is a user written getter or the implicit getter of a final field. Allowing fields to be read, but not getters, breaks the getter/field symmetry and makes it a breaking change to change a field into a getter. We do not want that to happen. If you could mark the field as constant deliberately, then we might allow reading it, because it would then count as a promise to not change it into a getter. We do not have that feature, though (and are not actively planning to make more expression usable as constants).

All 3 comments

That's working as intended.

You can never read properties of an object in constant or potentially constant code (except String.length).
We have no way to mark a property as being "constant", so it is impossible to see from the interface whether the property is a user written getter or the implicit getter of a final field. Allowing fields to be read, but not getters, breaks the getter/field symmetry and makes it a breaking change to change a field into a getter. We do not want that to happen. If you could mark the field as constant deliberately, then we might allow reading it, because it would then count as a promise to not change it into a getter. We do not have that feature, though (and are not actively planning to make more expression usable as constants).

@lrhn Thanks for the explanation. May I ask why String.length is the sole exception? What about other built-in types' getters, such as int.bitLength and int.isNegative?

I do not remember why String.length was accepted (I probably wasn't even there). My guess is that people wanted to write code without magical constants, so if they knew their string started with the string "Foo:", they preferred to write "Foo:".length instead of the magical constant 4 in the code which uses that value. Maybe it was used as a switch case value.
I'm guess is that there was some concrete use-case which convinced the language lead at the time that it was particularly worth including.
I probably wouldn't have included it if requested today. We still don't want to just allow any expression that can possibly be evaluated at compile-time. Simple expressions only.

Was this page helpful?
0 / 5 - 0 ratings