This is an archive of the discontinued LLVM Phabricator instance.

[ADT] Add has_value, value, value_or to llvm::Optional
AbandonedPublic

Authored by kazu on Jun 18 2022, 8:35 PM.

Details

Summary

This patch adds has_value, value, value_or to llvm::Optional so that
llvm::Optional looks more like std::optional.

I will keep the existing functions while migrating their callers and
then remove them later.

Diff Detail

Event Timeline

kazu created this revision.Jun 18 2022, 8:35 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 18 2022, 8:35 PM
kazu requested review of this revision.Jun 18 2022, 8:35 PM
Herald added a project: Restricted Project. · View Herald TranscriptJun 18 2022, 8:35 PM
dblaikie accepted this revision.Jun 18 2022, 9:06 PM

Sounds good. Though it might be worth migrating/normalising uses to op* (rather than value()) and bool testing (where it do any have to be explicit) instead of has_value() when migrating callers.

This revision is now accepted and ready to land.Jun 18 2022, 9:06 PM
This revision was landed with ongoing or failed builds.Jun 18 2022, 9:21 PM
This revision was automatically updated to reflect the committed changes.
jdoerfert reopened this revision.Jun 28 2022, 4:11 PM
jdoerfert added a subscriber: jdoerfert.

Sounds good. Though it might be worth migrating/normalising uses to op* (rather than value()) and bool testing (where it do any have to be explicit) instead of has_value() when migrating callers.

As mentioned here by @DaniilSuchkov, and here by me, this does not always make it easier to read the code. On the contrary, this can easily lead to confusion.

As far as I can tell, there is no guideline in our coding style for these changes, as @clementval pointed out. I'd suggest a discourse post or guideline patch so we can have the discussion if this is really helpful, especially as an automatically applied code change.

This revision is now accepted and ready to land.Jun 28 2022, 4:11 PM

Sounds good. Though it might be worth migrating/normalising uses to op* (rather than value()) and bool testing (where it do any have to be explicit) instead of has_value() when migrating callers.

As mentioned here by @DaniilSuchkov, and here by me, this does not always make it easier to read the code. On the contrary, this can easily lead to confusion.

As far as I can tell, there is no guideline in our coding style for these changes, as @clementval pointed out. I'd suggest a discourse post or guideline patch so we can have the discussion if this is really helpful, especially as an automatically applied code change.

I don't think all cleanups need style guide wording (see a lot of @kazu's other cleanups, such as migrating to range-based algorithms and other LLVM wrappers rather than iterator-pair based standard algorithms). But yeah, totally open to some discussion about this particular one.

Not sure if it needs to go on discourse, or we can have it here - I'd be OK with a more conservative cleanup of mapping "hasValue" to "has_value" and existing implicit bool checking remains the same. (& getValue -> value() and op* remains the same.

Though I personally find bool+* to be generally easier, because it's consistent with other things like pointers, so I don't have to think about which syntax to use for this optional-ish thing. (admittedly optional<bool> is particularly hairy) - but it's not worth a big discussion/trying to make that policy change, I don't think.

@kazu - sorry for the poor advice. Would it be especially hard to fixup the already refactored code to preserve the spelling-type used (eg: migrating hasValue -> has_value, etc)? (could probably do this without actually reverting all the cleanup upstream - revert it locally, then apply a modified refactoring that preserves spelling, then squash those commits and you should have a patch that only changes the places that need to be updated to the explicit spelling?)

Would that be sufficient/good @jdoerfert ?

Sounds good. Though it might be worth migrating/normalising uses to op* (rather than value()) and bool testing (where it do any have to be explicit) instead of has_value() when migrating callers.

As mentioned here by @DaniilSuchkov, and here by me, this does not always make it easier to read the code. On the contrary, this can easily lead to confusion.

As far as I can tell, there is no guideline in our coding style for these changes, as @clementval pointed out. I'd suggest a discourse post or guideline patch so we can have the discussion if this is really helpful, especially as an automatically applied code change.

I don't think all cleanups need style guide wording (see a lot of @kazu's other cleanups, such as migrating to range-based algorithms and other LLVM wrappers rather than iterator-pair based standard algorithms). But yeah, totally open to some discussion about this particular one.

There is two problems with this approach (no style guide wording and no "announcement"):

  1. People might have reasonable arguments against and no chance to bring them up.
  2. People do not realize what happened and will continue to introduce the "old" style which somewhat defeats the purpose. Playing devils advocate, people might just undo the style changes with the same argument they were introduced (no need for discussion or style guide changes).

Not sure if it needs to go on discourse, or we can have it here - I'd be OK with a more conservative cleanup of mapping "hasValue" to "has_value" and existing implicit bool checking remains the same. (& getValue -> value() and op* remains the same.

I'm totally fine with hasValue -> has_value (and similar) to phase out llvm::Optional (if that is the actual plan). We can also "encourage people" to use these by deprecating the old ones.

Though I personally find bool+* to be generally easier, because it's consistent with other things like pointers, so I don't have to think about which syntax to use for this optional-ish thing. (admittedly optional<bool> is particularly hairy) - but it's not worth a big discussion/trying to make that policy change, I don't think.

It's not only optional<bool>, int, ptr, can also be confusing.
The example I flagged in on of the patches changed:

`if (... && Size1.hasValue() && ...)` to `if (... && Size1 && ...)`.

I am very certain most people will read the former as "Size1 has a value" and the latter as "Size1 is not null". Which is arguably not an improvement.

@kazu - sorry for the poor advice. Would it be especially hard to fixup the already refactored code to preserve the spelling-type used (eg: migrating hasValue -> has_value, etc)? (could probably do this without actually reverting all the cleanup upstream - revert it locally, then apply a modified refactoring that preserves spelling, then squash those commits and you should have a patch that only changes the places that need to be updated to the explicit spelling?)

Would that be sufficient/good @jdoerfert ?

I don't think we should revert everything, that is causing churn. We should read through and flag the few problematic situations though which we move to std::Optional spelling. Also deprecating the old spelling methods seems reasonable, or just adding a comment.

@kazu - sorry for the poor advice. Would it be especially hard to fixup the already refactored code to preserve the spelling-type used (eg: migrating hasValue -> has_value, etc)? (could probably do this without actually reverting all the cleanup upstream - revert it locally, then apply a modified refactoring that preserves spelling, then squash those commits and you should have a patch that only changes the places that need to be updated to the explicit spelling?)

Would that be sufficient/good @jdoerfert ?

I don't think we should revert everything, that is causing churn. We should read through and flag the few problematic situations though which we move to std::Optional spelling.

sorry, what I was suggesting was a /local/ revert (not upstreamed), then apply the more nuanced transformation (that preserves explicit test/access where it's written originally) on top of that, then merge those two commits and the result should be one commit that touches only the places that need to be corrected that lost the explicit access/testing.

Also deprecating the old spelling methods seems reasonable, or just adding a comment.

I think that probably won't be necessary - I assume @kazu plans to complete this migration and remove the old methods entirely once all the uses are cleaned up. But might be necessary to use deprecation attributes for a while to help out-of-tree folks migrate off.

kazu abandoned this revision.Aug 9 2022, 10:34 AM
MaskRay added inline comments.
llvm/include/llvm/ADT/Optional.h
208

std::optional::value has undesired exception checking semantics: https://en.cppreference.com/w/cpp/utility/optional/value
llvm-project defaults to not use exceptions so this is wasteful.

And see _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS in libcxx/ which has __attribute__((availability(macos,strict,introduced=10.13)))/etc. It seems that Apple contributors no longer test such an old SDK (we haven't heard of complaints about unavailablity of value, but Chrome toolchain folks do target 10.12).

value likely needs a LLVM_DEPRECATED. See https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716/19?u=maskray