Skip to content

Implement constant equality as primitive equality #51565

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
eernstg opened this issue Feb 28, 2023 · 7 comments
Closed

Implement constant equality as primitive equality #51565

eernstg opened this issue Feb 28, 2023 · 7 comments
Assignees
Labels
area-meta Cross-cutting, high-level issues (for tracking many other implementation issues, ...). implementation Track the implementation of a specific feature (use on area-meta issue, not issues for each tool)

Comments

@eernstg
Copy link
Member

eernstg commented Feb 28, 2023

Cf. dart-lang/language#1811.

'Having a primitive operator ==' has now been generalized to 'having primitive equality', cf. #51045. The implementation of this feature is ongoing as of Feb 2023 (and I think it has been completed in the analyzer).

As a further regularization of the treatment of equality in constant expressions, this issue is concerned with the implementation of constant equality as primitive equality.

In particular here is the current specification of constant expressions of the form e1 == e2:

An expression of the form \code{$e_1$\,==\,$e_2$} is potentially constant
if $e_1$ and $e_2$ are both potentially constant expressions.
It is further constant if both $e_1$ and $e_2$ are constant and
either $e_1$ evaluates to an object that is an instance of
\code{int}, \code{double}, \code{String}, \code{bool} or \code{Null},
or if $e_2$ evaluates to the null object (\ref{null}).

It will be modified to rely on primitive equality instead, approximately:

An expression of the form \code{$e_1$\,==\,$e_2$} is potentially constant
if $e_1$ and $e_2$ are both potentially constant expressions.
It is further constant if both $e_1$ and $e_2$ are constant, and
$e_1$ has a primitive equality
(\ref{theOperatorEqualsEquals}),
or $e_2$ evaluates to the null object (\ref{null}).

[Edit: To avoid a breaking change, the spec update will continue to admit double even though double does not have primitive equality; cf. dart-lang/language#2874.]

Note that this change implies that enum values can be used as operands to == in a constant expression, cf. dart-lang/language#312. This is a consequence of the fact that no enum declaration can declare or inherit an implementation of operator == or hashCode that overrides the declaration in Object.


Subtasks:

@scheglov
Copy link
Contributor

double does not have primitive equality, right?
So, now const v = 1.2 == 2.3; is an error?

@eernstg
Copy link
Member Author

eernstg commented Mar 1, 2023

Right, double does not have primitive equality and 1.2 == 2.3 is not a constant expression.

@scheglov
Copy link
Contributor

scheglov commented Mar 1, 2023

And 1.2 == 2.3 is not a constant expression only when patterns are enabled?

@eernstg
Copy link
Member Author

eernstg commented Mar 1, 2023

Oops, that's an unintended breaking change. We'll fix the spec update to avoid the breaking change in dart-lang/language#2874. Thanks for the heads up!

@eernstg
Copy link
Member Author

eernstg commented Mar 1, 2023

dart-lang/language#2874 has now landed, and the ability to have a double as the left operand of a constant == expression has been preserved as a special exception.

@bernaferrari
Copy link
Contributor

Out of curiosity, would "fixing" it be "that breaking"? For example, would any test fail? It seems small enough that could be fixed.

@eernstg
Copy link
Member Author

eernstg commented Mar 8, 2023

I'm not entirely sure what that means. If we change the rules such that someConstantVariableOfTypeDouble == 1.5 is suddenly not a constant expression then we might break any number of programs without helping anyone. OK, it's probably only very, very few cases, but it might still break a much larger number of lines of code, because any such expression could occur in a widely used library.

double was never considered to have primitive equality (previously known as "having a primitive operator ==") because equality for double is weird: double.nan != double.nan. So we'd have non-standard behaviors in collections where double.nan is used. E.g., const <double, String>{double.nan: "Not a number"} would return null when we try to look up double.nan.

So we did not want to give double primitive equality, and we did not want to break programs for basically no reason, and that's the reason why we did what we did.

In summary, I'm not 100% sure what 'fixing it' would mean. 😄

@johnniwinther johnniwinther self-assigned this Mar 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-meta Cross-cutting, high-level issues (for tracking many other implementation issues, ...). implementation Track the implementation of a specific feature (use on area-meta issue, not issues for each tool)
Projects
None yet
Development

No branches or pull requests

4 participants