Skip to content

Can't use static const of class in other static const #1868

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

Closed
ltOgt opened this issue Sep 22, 2021 · 9 comments
Closed

Can't use static const of class in other static const #1868

ltOgt opened this issue Sep 22, 2021 · 9 comments
Labels
enhanced-const Requests or proposals about enhanced constant expressions request Requests to resolve a particular developer problem

Comments

@ltOgt
Copy link

ltOgt commented Sep 22, 2021

Take the following:

class ClassA {
  final String strA;

  const ClassA(this.strA);

  static const ClassA defaults = ClassA("default");
}

class ClassB {
  final String strB;

  const ClassB(this.strB);

  static const ClassB defaults = ClassB(ClassA.defaults.strA);
  // -----------------------------------"""""""""""""""""""""
}

which shows the problem

Const variables must be initialized with a constant value.
Try changing the initializer to be a constant expression.
dart(const_initialized_with_non_constant_value)

Arguments of a constant creation must be constant expressions.
Try making the argument a valid constant, or use 'new' to call the constructor.
dart(const_with_non_constant_argument)

A value of type 'Null' can't be assigned to a parameter of type 'String' in a const constructor.
Try using a subtype, or removing the keyword 'const'.
dart(const_constructor_param_type_mismatch)

is this by design or should this be possible?

@ltOgt ltOgt added the request Requests to resolve a particular developer problem label Sep 22, 2021
@mateusfccp
Copy link
Contributor

You are trying to use a non-constant to make a constant. ClassA.defaults.strA is not constant, although ClassA.defaults is.

@Levi-Lesches
Copy link

@ltOgt, you can't access members on any object, only classes. ClassA.defaults is const because it's accessing defaults on ClassA, but ClassA.defaults.strA isn't const because you're trying to access strA on ClassA.defaults, an object.

@ltOgt
Copy link
Author

ltOgt commented Sep 23, 2021

Thanks @mateusfccp + @Levi-Lesches
i assumed that the instance along with its fields would become a constant.

@lrhn
Copy link
Member

lrhn commented Sep 23, 2021

Field accesses are not constant. One of the reasons is that something being "a field" is not part of a class's API. From the outside, it's a getter, which is what allows you to freely change a field to a getter and vice-versa.
We can't allow constant access to getters, they can potentially run arbitrary user code, which we don't allow during const evaluation. We also don't want to allow accessing getters-which-are-really-fields because that would then make it a breaking change to later change that field to a getter.
That means no instance member access at const evaluation time except for a set of hand-picked methods on platform types (mainly operators like int.+).

If you could declare an instance const variable, like you can `static const x = ...;, then we might make be able to allow accessing that variable in a const evaluation. It would also be an obvious breaking change to make that variable non-constant, and therefore it can't be a getter. We do not currently have that feature.

@eernstg eernstg added the enhanced-const Requests or proposals about enhanced constant expressions label Dec 1, 2021
@ltOgt
Copy link
Author

ltOgt commented Dec 2, 2021

@lrhn I think I still don't fully understand this.
If I create an instance of a class with const, are the values of that instance not constant?
Or is the issue only that we can't access those values during evaluation to circumvent getter execution?

I.e. is ClassA.defaults.strA still a compile time constant and only illegal to use inside other const expressions?

@eernstg
Copy link
Member

eernstg commented Dec 2, 2021

It is not guaranteed that any getter invocation on an object is "constant", even when that object was obtained as the value of a constant expression:

class A {
  final bool b;
  const A(this.b);
}

bool _b = true;

class B implements A {
  bool get b => _b = !_b;
  const B();
}

void main() {
  const A = B();
  print('${A.b} != ${A.b}'); // Prints 'false != true'.
}

The point is that there's nothing stopping "a constant object" from running arbitrary code.

@eernstg
Copy link
Member

eernstg commented Dec 2, 2021

The proposal about stable/final getters is aimed at this exact property, that is, adding true semantic immutability to Dart. The trade-off is that if you declare that a specific getter is stable or final then it becomes a compile-time error to override it the way it's done in the class B in the example I gave above.

@ltOgt
Copy link
Author

ltOgt commented Dec 2, 2021

Thank you for the example, the override in B made the issue clear.

@Levi-Lesches
Copy link

If your question's been answered, you can close this issue to help clear up the list of open issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhanced-const Requests or proposals about enhanced constant expressions request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

6 participants