This is an archive of the discontinued LLVM Phabricator instance.

WIP: Support: Add Expected<T>::emplaceInto()
AbandonedPublic

Authored by dexonsmith on Oct 21 2021, 4:13 PM.

Details

Reviewers
lhames
dblaikie
Summary

Expected<T>::emplaceInto() takes as an out parameter any
Optional<OtherT>, with OtherT constructible from T&&. It either
calls Optional<OtherT>::emplace() with the stored value, or calls
Optional<OtherT>::reset() if none, before returning takeError().

emplaceInto() is similar to Expected<T>::moveInto() / https://reviews.llvm.org/D112278, but works with an
Optional that contains a construct-only type that T can be moved into.

Optional<ConstructOnly> P;
if (Error E = makeConstructOnly().emplaceInto(P))
  return E;

I'm not sure this is really useful enough -- construct-only types are a
real thing, but it's not often possible to move-construct them. It's
unlikely that an Expected would contain one. Perhaps this is too
specific a use case?

Also, would this be better as a free function? (It probably doesn't make
sense to add overloads to Expected<T> for arbitrary box types... but
as a free function you could easily extend without modifying Expected.)

Diff Detail

Event Timeline

dexonsmith requested review of this revision.Oct 21 2021, 4:13 PM
dexonsmith created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptOct 21 2021, 4:13 PM

BTW, I marked this as "WIP" because I'm not sure this really has legs... happy to abandon if no one thinks this is useful enough... or maybe there's a way to improve it?

I have hit places where Optional::operator=() fails but Optional::emplace() succeeds. Can't remember where off the top of my head though.

Yeah, similarly mixed feelings.

Might be at some point we would put up with using a small selection of macros (google's done something similar, begrudgingly, to handle absl::Status) to make it possible to actually create a local variable with initialization from an Expected result - I think that requires statement expressions or other shenanigans to make that work, though, which is also annoying, on top of the macros.

dexonsmith abandoned this revision.Oct 22 2021, 1:04 PM

Yeah, similarly mixed feelings.

Might be at some point we would put up with using a small selection of macros (google's done something similar, begrudgingly, to handle absl::Status) to make it possible to actually create a local variable with initialization from an Expected result - I think that requires statement expressions or other shenanigans to make that work, though, which is also annoying, on top of the macros.

A couple of other ideas that are implementable, but I'm not sure are really better than just doing the boilerplate:

struct ChallengingType {
  ChallengingType(std::string S, bool Flag, int I, ...);
};
Expected<std::string> makeString();
Expected<std::string> makeInt();

void f1(bool Flag) {
  Optional<ChallengingType> CT;

  // Filters arguments for `Expected<T>`, joining all errors.
  // Calls `emplace()` with moved values if there are none.
  if (Error E = CT.emplaceWithExpected(makeString(), Flag, makeInt(), ...))
    return E;

  // As above, but generalized to types other than Optional.
  // Returns Expected<X> if object returns X.
  if (Error E = emplaceWithExpected(CT, makeString(), Flag, makeInt(), ...))
    return E;

  // As above, but instead of filtering for Expected, filters for a temporary
  // lambda returned by `delayExpected()`.
  if (Error E = emplaceWithDelayedExpected(
          CT,
          delayExpected([&]() {return makeString();}),
          Flag,
          delayExpected([&]() {return makeInt();}),
          ...))
    return E;

  // As above, but call any function, not just emplace.
  if (Error E = callWithDelayedExpected(
          delayExpected([&]() {return makeString();}),
          Flag,
          delayExpected([&]() {return makeInt();}),
          ...,
          [&CT](std::string S, bool Flag, int I, ...) {
            CT.emplace(std::move(S), Flag, I, ...);
          }))
    return E;

  // ... other code ...
}

Anyway, I'll abandon this.