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 inconsistent indexing between LeftValues and RightValues #8

Merged
merged 2 commits into from
Sep 7, 2024

Conversation

ladvoc
Copy link
Owner

@ladvoc ladvoc commented Sep 6, 2024

I noticed something I overlooked when I first implemented LeftValues and RightValues. In a standard Dictionary, Keys and Values share the same indices. That is, as long as the dictionary is not mutated and the indices remain stable, index $i$ corresponds to the same element regardless if accessed from keys or values:

var dict = [
    "a": 1,
    "b": 2,
    "c": 3
]

print(dict.keys[dict.startIndex])  // prints "b"
print(dict.values[dict.startIndex])  // prints "2"

dict["d"] = 4  // mutation invalidates indices

print(dict.keys[dict.startIndex]) // prints "a"
print(dict.values[dict.startIndex]) // prints "1"

This is the expected behavior for index-based access in a Dictionary. However, BijectiveDictionary's current implementation has a bug. The reason the docs mention that order is not guaranteed for leftValues and rightValues is because LeftValues uses _ltr and RightValues uses _rtl. However, since _rtl is a separate dictionary, it has different indices. This means index $i$ refers to a different element in leftValues and rightValues. This behavior is unexpected and is not consistent with Dictionary.

Taking another look at this, there is no reason RightValues can’t also use _ltr; this pull request modifies RightValues accordingly.

@DandyLyons
Copy link
Collaborator

In a standard Dictionary, Keys and Values share the same indices. That is, as long as the dictionary is not mutated and the indices remain stable, index i corresponds to the same element regardless if accessed from keys or values

I'm not certain that this statement is true. See this from the docs:

The order of key-value pairs in a dictionary is stable between mutations but is otherwise unpredictable.

A dictionary’s indices stay valid across additions to the dictionary as long as the dictionary has enough capacity to store the added values without allocating more buffer. When a dictionary outgrows its buffer, existing indices may be invalidated without any notification.
https://developer.apple.com/documentation/swift/dictionary#Iterating-Over-the-Contents-of-a-Dictionary

In any case, perhaps it does make sense to use _ltr for RightValues. If so, that would mean that we don't have to worry about RightValues and LeftValues being out of sync or having mismatched order pairs.

However, I'm not sure if that could have any negative performance implications for certain use cases. But all current tests are passing with this PR.

This is probably good to go, but I think we should add more test coverage.

@DandyLyons
Copy link
Collaborator

I added some test coverage. For this. It looks like I don't have permission to push my test coverage changes directly to this PR. I can PR my added tests after we merge this PR. This PR looks good to go.

👍🏼

@ladvoc
Copy link
Owner Author

ladvoc commented Sep 7, 2024

You are right, my explanation implies that the indices get invalidated on each mutation which doesn’t always happen. But in any case, while the indices are valid, a given index should refer to the same left-right pair.

I will go ahead and merge this now. I also agree more testing is needed—especially performance testing; I will revise issue #4 to track this.

@ladvoc ladvoc merged commit 233a2f6 into main Sep 7, 2024
2 checks passed
@ladvoc ladvoc deleted the rvalues-fix branch September 7, 2024 00:29
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.

2 participants