Skip to content

Allow a const record entry to be assignable to a const #3004

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

Open
rubenferreira97 opened this issue Apr 17, 2023 · 5 comments
Open

Allow a const record entry to be assignable to a const #3004

rubenferreira97 opened this issue Apr 17, 2023 · 5 comments
Labels
enhanced-const Requests or proposals about enhanced constant expressions request Requests to resolve a particular developer problem

Comments

@rubenferreira97
Copy link

rubenferreira97 commented Apr 17, 2023

import 'package:flutter/material.dart';

class MyColors {
  static const Color primary = Color(0xFF007AFF);
  static const Color secondary = Color(0xFF6C757D);
}

const primaryClass = MyColors.primary;

const myColors = (
  primary: Color(0xFF007AFF),
  secondary: Color(0xFF6C757D),
);

const myColors2 = myColors; // works https://github.com/dart-lang/language/issues/2337
const primaryRecord = myColors.primary; // Error: Const variables must be initialized with a constant value.

If a record is const, and its entries must be const, could we get a way to assign it to a constant? Unfortunately I think a const return (const Color get primary) would need to be present on the getter method. Could we under the hood create a const instance and replace it inline? This may break some things.

The previous code would generate something like this:

const myColors = (
  primary: const Color(0xFF007AFF);
);

const primaryRecord = const Color(0xFF007AFF); // myColors.primary -> const Color(0xFF007AFF);
@rubenferreira97 rubenferreira97 added the request Requests to resolve a particular developer problem label Apr 17, 2023
@rubenferreira97 rubenferreira97 changed the title Allow a const record entry to be assignable to a const variable Allow a const record entry to be assignable to a const Apr 17, 2023
@munificent
Copy link
Member

In principle, yes, this is a thing we could do. Since records can't be implemented or inherited from, we know that every record field access is effectively non-virtual. If we know that the record the field is being accessed on is constant, then we can know that the field access is itself constant too.

@eernstg eernstg added the enhanced-const Requests or proposals about enhanced constant expressions label Apr 18, 2023
@eernstg
Copy link
Member

eernstg commented Apr 18, 2023

Note the overlap with #2219 (comment).

@ds84182
Copy link

ds84182 commented Jun 19, 2023

I really wish this was shipped with 3.0. I wanted to write an inline class with a const constructor that accepts records and turns them into a bitflag:

const RelativeBoxConstraints({required Dim2D<bool> flexible}) : _flags = (flexible.width ? 1 : 0) | (flexible.height ? 2 : 0);

Of course the workaround here is to use separate named parameters for width and height but that simply isn't as clean.

As a workaround, I can use operator ==. But that's a horrible solution to this problem.

@lrhn
Copy link
Member

lrhn commented Jun 19, 2023

There is a number of member accesses we can allow at compile-time.

  • Record field access is a clear candidate.
  • Constant list and map lookup (but only when applied to lists and maps that are created by literals), plus, maybe length, first, last, isEmpty.
  • A large number of int operations, possibly all of them (int.sign, int.abs(), int.isEven, etc.).
  • A large number of String operations (substring(int,int), isEmpty, isNotEmpty).

I'm pretty sure we have a request for "more const expressions" somewhere, I just can't find it. (Damn you, Github search!)

(Before someone says "final fields", then no, a final field is not a promise to not make it a getter in a later version of the same code. Allowing accessing fields, but not getters, would make it one. #299)

@mmcdon20
Copy link

This does seem like an obvious fit for const expressions.

const r = (x: 1, y: 2);
const x = r.x, y = r.y;

It might even be possible to allow a const destructuring, but I see this as less essential.

const r = (x: 1, y: 2);
const (:x, :y) = r;

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