10

C++23 adds some "monadic-style" functionality regarding optionals, as methods of optional<T>:

optional<T>::and_then() (and ignoring qualifiers of this):

template<class F> constexpr auto and_then(F&& f); 

Returns the result of invocation of f on the contained value if it exists. Otherwise, returns an empty value of the return type.

optional<T>::transform() (and ignoring qualifiers of this):

template<class F> constexpr auto transform(F&& f);

Returns an std::optional that contains the result of invocation of f on the contained value if *this contains a value. Otherwise, returns an empty std::optional of such type.

So, aren't these two functions doing the same thing?

einpoklum
  • 118,144
  • 57
  • 340
  • 684

3 Answers3

13

Suppose you have an optional<T1> value.

  • transform() lets you pass your optional to functions like T2 foo(T1 x);
  • and_then() lets you pass your optional to functions like optional<T2> bar(T1 x);

... and get an optional<T2> at the end. So, transform() will "re-box" the function's output into an optional, while and_then() will expect the function to return a boxed value on its own.

See also this question.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • @StoryTeller-UnslanderMonica: You're right, but - then my answer doesn't really explain why this even makes sense. I mean, if we get an optional both with `and_then` and with `transform` - what's the use of having both of them? – einpoklum Nov 26 '22 at 10:11
  • Fluent API is enough reason for me personally. – StoryTeller - Unslander Monica Nov 26 '22 at 10:36
  • 6
    @einpoklum The point of monadic operations is to keep the object as an `optional`, and only unwrap them after you've finished all operations. `and_then` expects functions that were written for `optional`, where `transform` makes non-`optional` functions usable in `optional` context. – Ranoiaetep Nov 26 '22 at 10:43
  • 1
    In case anyone might come for the `std::expected` side, `and_then` is actually `and_then_when_valid`, `or_else` is actually `or_else_when_invalid` taking `expected fred(E1 x)`. In other words, `and_then` ***automatically*** passes through `E1` (`nullopt_t`) and `or_else` ***automatically*** passes through `T1`. Yes, `transform_error` and `or_else` are the `std::exptected`'s the counterpart of `transform` and `and_then` and their parameter function take a parameter of `E1` instead of `T1`. – sandthorn Jul 28 '23 at 03:11
1

and_then only takes functions of type T -> std::optional<U> (whereas transform is free to take functions returning any type).

If you just transform with such a function you will get a std::optional<std::optional<U>>.

and_then just then flattens the std::optional<std::optional<U>> into an std::optional<U>.

That's all monads are: transform composed with a type level flatten. Think range<range<U>> and future<future<U>>.

Tom Huntington
  • 2,260
  • 10
  • 20
0

and_then is monadic bind aka flatmap aka >>= and transform is functorial map.

One can express map in terms of bind generically, but not the other way around, because a functor is not necessarily a monad. Of course the particular monad of std::optional can be opened at any time, so both functions are expressible in terms of ordinary pre-C++23 std::optional API. Thus the question why the C++ standard defines both functions is no better than the question why it defines any of the two. Perhaps the Standard wishes to give the programmer a standard functorial interface and a standard monadic interface independently. Either interface is useful and important on its own right.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 4
    C++ programmers have different notions associated with the words "bind", "map" and "flatmap"; and the operator `>>=` does not exist in C++. Please explain all of this in your answer, or provide appropriate links. – einpoklum Nov 26 '22 at 19:43
  • 1
    @einpoklum I have considered this idea and decided against it. This answer is not, and doesn't want to be, an introduction to functional programming. – n. m. could be an AI Nov 26 '22 at 19:56
  • 5
    But the target audience of your answer does not understand what you are talking about. – einpoklum Nov 26 '22 at 20:05
  • 1
    @einpoklum I am of a somewhat different opinion about my target audience. If I'm wrong, anyone can write a better answer or edit this one. – n. m. could be an AI Nov 26 '22 at 20:09
  • @einpoklum Technically, C++ *does* have an operator called `>>=`, and I wouldn't be surprised if operator overloading were flexible enough to let you make it mean `and_then`. – Joseph Sible-Reinstate Monica Nov 27 '22 at 15:28
  • @JosephSible-ReinstateMonica: Indeed, C++ has a "left-shift-equals" operator. But that's not the operator `>>=` n.m. was referring to. However - that is an interesting idea. – einpoklum Nov 27 '22 at 18:33
  • 1
    This reply is only just more cryptic than the standard wording. It is not comprehensible for average C++ programers, even some of the elite. Nobody can edit such an answer propperly, except the author himself. – Red.Wave Dec 13 '22 at 17:16