Skip to content
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

Fix recent regression on storing Maps #5182

Merged
merged 1 commit into from Feb 4, 2023
Merged

Conversation

2colours
Copy link
Contributor

@2colours 2colours commented Feb 4, 2023

The commit that was meant to fix storage of "hash objects" into Hashes had a serious thinko: after checking for Maps, it invoked a method defined on Hashes only. This meant that after the changes

my %problem is Map = :foo;
(%problem,).hash

was failing, unable to find the PUSH_FROM_MAP method on Maps. (Ironically, even the name suggested that it should be defined on Maps.)

This commit addresses this problem by indeed moving the PUSH_FROM_MAP method to Map. For clarity, I added a type constraint to the parameter - the pushing always happens to a Hash, that was the dedicated purpose of the method all along.

The commit that was meant to fix storage of "hash objects" into Hashes
had a serious thinko: after checking for Maps, it invoked a method
defined on Hashes only. This meant that after the changes

my %problem is Map = :foo;
(%problem,).hash

was failing, unable to find the PUSH_FROM_MAP method on Maps. (Ironically,
even the name suggested that it should be defined on Maps.)

This commit addresses this problem by indeed moving the PUSH_FROM_MAP method
to Map. For clarity, I added a type constraint to the parameter - the pushing
always happens *to* a Hash, that was the dedicated purpose of the method all
along.
@2colours
Copy link
Contributor Author

2colours commented Feb 4, 2023

While running the tests and spectests at least, I'd like to add a few notes.

First, I'm not sure about the format but I think the spectest should be more exhaustive. There is Map, Hash and Hash::Object (a role mixed in to Hash) as three different implementations to consider at storing. All can be the source and the target of storing; that means all nine scenarios should be tested. It could be done with three tests: storing a List of all three into 1. a Map 2. a Hash 3. a Hash::Object.

Second, other than the testing, I think the overall condition of these behavior is not great:

  • I noticed that Map reasons about all types but then Hash overrides its behavior in a way that didn't take all of them into account anymore. A lot of logic is being duplicated. This will be hard to keep in sync should anything change.
  • the reason I like the solution I'm pushing for is that it allows separation of implementations. We have loads of concrete types and often inherit from them. To make it worse, we are trying to push every specific overridden implementation into one "god class" that can take all of them into account, simply because it's hardwired to do so.

For these reasons, I would like to rewrite these workings in the somewhat recent future. Then all the testing and benchmarking could be done. I can imagine that relying on actual method dispatch could be slower than a handwritten typecheck in NQP, however I'd hope that the cost would be rather negligible because the affected type checks happen at rather high point in the structure - once per Map(/Hash/Hash::Object) instance. Other than the organizing of the methods and the calls, I don't think much change would be required but it's good to be precautious.

@2colours 2colours marked this pull request as ready for review February 4, 2023 00:22
@lizmat lizmat merged commit 5ed14bc into rakudo:main Feb 4, 2023
@lizmat
Copy link
Contributor

lizmat commented Feb 4, 2023

Good catch!

@2colours 2colours deleted the map-store-refix branch February 4, 2023 10:54
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.

None yet

2 participants