Skip to content

reimplement MapEntry as a record #61071

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
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

RohitSaily
Copy link
Contributor

@RohitSaily RohitSaily commented Jul 7, 2025

As stated by its documentation, MapEntry has been planned to be changed to a value type. This change achieves that by making it a Record (K, V). Backwards compatibility is mostly achieved by preserving the original API through an extension type and ensuring it implements Object. See #61071 (comment) for what would not be backwards compatible

asPair is added to the API to allow direct usage as a record, it was required anyways since it is the backing field

Copy link

Thank you for your contribution! This project uses Gerrit for code reviews. Your pull request has automatically been converted into a code review at:

https://dart-review.googlesource.com/c/sdk/+/439100

Please wait for a developer to review your code review at the above link; you can speed up the review if you sign into Gerrit and manually add a reviewer that has recently worked on the relevant code. See CONTRIBUTING.md to learn how to upload changes to Gerrit directly.

Additional commits pushed to this PR will update both the PR and the corresponding Gerrit CL. After the review is complete on the CL, your reviewer will merge the CL (automatically closing this PR).

@RohitSaily
Copy link
Contributor Author

Now the record constructor is accessible and named fromPair

Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

1 similar comment
Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

@RohitSaily
Copy link
Contributor Author

cc @bwilkerson @keertip

@mraleph
Copy link
Member

mraleph commented Jul 7, 2025

See also discussions on #54965

This is technically a breaking change so it requires breaking change process, and even before that it requires @lrhn to pre-approve the design.

Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

1 similar comment
Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

@RohitSaily
Copy link
Contributor Author

RohitSaily commented Jul 7, 2025

@mraleph thanks for linking that and tagging @lrhn. This change uses an extension type and includes the original API as a subset of its API* and therefore should not be breaking

* the _ constructor is removed but that is internal and was not used anywhere, so I simply omitted it since it was not needed

@mraleph
Copy link
Member

mraleph commented Jul 7, 2025

It is breaking because it changes runtime semantics: the difference between old and new version is observable via is / as checks as well as through equality and identity of MapEntry (original class did not override ==).

That being said the breakage is probably very limited - MapEntry should only really occur as temporary objects.

@RohitSaily
Copy link
Contributor Author

RohitSaily commented Jul 7, 2025

It is breaking because it changes runtime semantics: the difference between old and new version is observable via is / as checks as well as through equality and identity of MapEntry (original class did not override ==).

That being said the breakage is probably very limited - MapEntry should only really occur as temporary objects.

Good points, I did not consider those things. The original class-based MapEntry is replaced in this change so any MapEntry is/as behaviour should still be preserved for MapEntry but if (K, V) or Record happens to be checked or casted it would now work differently, as you have said eg

(1, 'hello') is MapEntry<int, String> // used to be false, now true
(1, 'hello') as MapEntry<int, String> // used to throw Error, now it works

f (MapEntry<int, String> e) {
  e is Record  // used to be false, now true
  e is (int, String)  // used to be false, now true
}

Also agree this changes == to the record defined behaviour from the original identity based one

Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

1 similar comment
Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

keep it backwards compatible by preserving member names and
implementing `Object`

introduce `asPair` to allow direct usage as a record and
`fromPair` to allow direct construction from a record
Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

2 similar comments
Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

Copy link

https://dart-review.googlesource.com/c/sdk/+/439100 has been updated with the latest commits from this pull request.

@lrhn
Copy link
Member

lrhn commented Jul 12, 2025

It's not the time, yet.

The Dart 3.0 language changes to the platform libraries, including adding final to MapEntry, were made conditional on the language version of the client library.

That means that pre-3.0 language version libraries can extend MapEntry, and changing the class to an extension type will break that.
So it's a breaking change as long as the SDK supports language version 2.19.

Other than that, I don't mind MapEntry having equality. In fact, I thought I did that already.

I wouldn't expose asPair.
I would consider using a ({K key, V value}) as representation record, so that dynamic access would keep working.

But not yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants