Skip to content

Conversation

@oldnewthing
Copy link
Member

@oldnewthing oldnewthing commented Jun 6, 2020

single_threaded_map()'s IMap::Remove did not throw hresult_out_of_range on attempts to remove a nonexistent key. Now it throws.

Note that this is a breaking change. Code that assumed nonexistent objects could be harmlessly removed will encounter exceptions when run against C++/WinRT implementations when they hadn't before this change. This was, however, a pre-existing bug, because implementations from other projections (C#, C++/CX, WRL) always throw under those conditions.

Added a TryRemove() method for people who want the nonthrowing version.

Note that fixing the ABI conformance is required in order for TryRemove to return the correct result, because TryRemove relies on the call to Remove failing if the key doesn't exist.

(JavaScript doesn't project objects as maps, so there is nothing to validate there.)

Tightened the behavior of TryLookup and TryRemove so they swallow only "key not found" and propagate other errors. The inability to remove the item could be due to the server being unavailable, or the app accessing the map from the wrong thread, and that's not the same as the item not existing in the collection. Previous code treated these errors the same as "The item doesn't exist", which is not true: The item could exist, we simply don't know since the call never got off the ground.

Failure to remove a nonexistent key no longer invalidates iterators, because nothing actually changed. This brings the map implementation in line with the implementations in C# and WRL. (C++/CX invalidates prematurely. JavaScript never invalidates iterators.)

`single_threaded_map()`'s IMap::Remove did not throw
`hresult_out_of_range` on attempts to remove a nonexistent
key. Now it throws.

Failure to remove a nonexistent key does not invalidate
iterators, because nothing actually changed. This brings
the map implementation in line with the implementations
in other projections.

Note that this is a breaking change. Code that assumed
nonexistent objects could be harmlessly removed will
encounter exceptions when run against C++/WinRT implementations.
This was, however, a pre-existing bug, because implementations
from other projections (C#, C++/CX) always threw under those
conditions.

Added a TryRemove() method for people who wanted the
nonthrowing version.

Note that fixing the ABI conformance is required in order
for TryRemove to work, because TryRemove relies on the
call to Remove failing if the key doesn't exist.

(JavaScript doesn't project objects as maps, so there
is nothing to validate there.)

Tightened the behavior of TryLookup and TryRemove so
they propagate RPC failures. Because the inability to
remove the item could be due to the server being unavailable,
and that's not the same as the item not existing in
the collection. Previous code treated loss of server
the same as "The item doesn't exist", which is not true:
The item could exist, we just were unable to contact
the server to find out.
auto found = container.find(static_cast<D const&>(*this).wrap_value(key));
if (found == container.end())
{
throw hresult_out_of_bounds();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why it's important that Remove throws when the key is not found, beyond consistency with other implementations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It prevents TryRemove from working correctly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but it sounds like a circular argument. TryRemove needs Remove to change. TryRemove is needed because Remove has changed. 😉

Copy link
Member Author

@oldnewthing oldnewthing Jun 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TryRemove is needed because if the map came from somebody other than C++/WinRT, it will throw. For example, if you want to "TryRemove" from CoreApplication.Properties, you cannot use "Remove" because that property set is implemented in WRL, not C++/WinRT, and it throws on key not found.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it - thanks.

@kennykerr
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

No pipelines are associated with this pull request.

oldnewthing and others added 2 commits June 8, 2020 08:21
because they can throw on other errors.

Added unit test to verify that errors other than "key not found" are
propagated.
@kennykerr
Copy link
Collaborator

/azp run

@azure-pipelines
Copy link

No pipelines are associated with this pull request.

@kennykerr kennykerr merged commit 87436b4 into microsoft:master Jun 8, 2020
@oldnewthing oldnewthing deleted the tryremove branch June 8, 2020 16:32
kennykerr added a commit that referenced this pull request Jun 8, 2020
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