Boost logo

Boost :

From: Steve Downey (sdowney_at_[hidden])
Date: 2024-09-16 15:31:41


On Sun, Sep 15, 2024 at 1:55 PM Andrzej Krzemienski <akrzemi1_at_[hidden]>
wrote:

> Hi Steve,
> Thanks for weighing in.
>
> niedz., 15 wrz 2024 o 16:42 Steve Downey via Boost <boost_at_[hidden]>
> napisał(a):
>
>> The core motivation is not having yet another optional-like in the
>> standard
>> library.
>
>
> Understood. However, there is a trade-off here: additional optional-like
> type versus additional member functions in std::optional.
>
>
>> Ranges needs a 0-or-1 range as a primitive for where the filter
>> algorithm isn't quite the right answer, in particular for range
>> comprehension desugaring which comes up fairly often by hand.
>>
>
> I am not well familiar with ranges, so I must admit that upon reading the
> phrase "range comprehension desugaring" I bailed out. Is there a place that
> describes the term?
> However, I understood that in order to effectively compose ranges one
> needs the additional component, which can either be implemented as a stand
> alone ranges component or through adding member functions to `optional`.
>
>

Comprehensions are the expressions in other languages like [ (x,y) | x <-
[1, 2, 3], y <- [4, 5, 6], is_even(x+y)] based on set comprehension
notation. Python has it as [(x, y) for x in [1,2,3] for y in [3,1,4] if x !=
y]

The boolean constraint becomes an expression that is like if(cond) return
[val] else return [], either an empty list or a list of one element that is
the values under examination. We don't have that in C++, but it's an
important technique in writing range pipelines.

That's how you turn [(x, y, z) | z <- [1...], x <- [1...z+1], y <- [x ...
z+1], (x*x + y*y) == z*z] into something like
  auto triples = and_then(iota(1), [](int z) { return and_then(iota(1, z +
1), [=](int x) { return and_then(iota(x, z + 1), [=](int y) { return
yield_if(x * x + y * y == z * z, std::make_tuple(x, y, z)); }); }); });

Filter can be expressed as joining over yield_if, but not all expressions
using the idiom go the other way, at least not trivially.

> Having a range type like empty or single, without a bunch of the implicit
>> conversion operations from the underlying type, was my preference, however
>> adding the range ops to optional<T> was a reasonable fallback.
>>
>
> Indeed, I would also think that if this is only needed to compose ranges,
> it should be added as a <ranges>-component: view, adapter.
>
>
wg21.link/P1255R10

The criticism was "do we really need another optional?"

The main difference being that it did not allow direct assignment from the
underlying, because that's what introduces ambiguity, particularly for
references.

And optional not being a container was always a suspect position,
>> especially after the addition of other fixed size or limited size
>> containers. Making it a full Cpp17 Container is probably over the top, and
>> might have confused existing code, but adding the range interface is
>> minimal.
>>
>
> In retrospect, I think I agree with Tony Van Eerd's observation that it
> was a design mistake to combine two models in `boost::optional`, and by
> extension in `std::optional`:
> 1. That optional<T> is a T with an additional state. hence the conversions
> and comparisons with `T` and `none`/`nullopt`.
> 2. That optional<T> is a container holding zero or one element of `T`
> hence the interface for querying for being empty and for accessing the
> element.
>
> Those two are fine together. It's that it's also (sometimes) transparently
a T that causes the conceptual muddy-ness. But that's important for
modelling optional parameters,
void func(int a = optional<int>{});
func(5);

And making optional model a fancy pointer just made additional issues. .

But now that we have this confusion, I am not sure if extending one of
> these interfaces further is the right way to go.
>
> I can think of a couple of reasons why adding a range interface to
> optional is not desired.
> 1. A general design principle that a class should have a minimal interface
> required to manage its invariant. Anything else, if needed, should be free
> functions operating on the class interface. The Standard Library components
> do not necessarily follow it (std::string being the best (worst) example).
> 2. Given that we have standard concepts that detect the range interface,
> `std::ranges::range` it is reasonable to assume that programmers use it in
> their code, also for controlling the overload resolution. Suddenly adding
> the range interface to optional is likely to break their code. (While any
> change whatsoever could theoretically break code, the current problem is
> more likely, because we are talking about the standardized concept.)
> 3. Increasing (thus complicating) the class interface without motivating
> usages is a bad trade-off.
>
> The usages for the interop with ranges were given, but it looks like there
> are no other usages not involving ranges.
> The usage with the for-loop indeed seems like a hack rather than a
> technique that I would comfortably endorse.
>
> Regards,
> &rzej;
>
>
>> On the other hand, once we have std::optional<T&> and possibly
>> optional<T&&>, boost's optional should probably be avoided in codebases
>> using C++26 or later.
>>
>> On Sat, Sep 14, 2024 at 7:59 AM Thomas Fowlery via Boost <
>> boost_at_[hidden]> wrote:
>>
>> > Every feature should be well motivated by a real use case or a set of
>> use
>> > cases. I don't find any of the examples in this proposal motivating. In
>> > fact, this feature seems to encourage bad code, judging by the examples:
>> > - using transform(f) | join with an optional-returning function f,
>> instead
>> > of using a simple filter(predicate)
>> > - materializing optionals when not really necessary (incurs extra
>> > moves/copies)
>> > - abusing the range-for loop for unwrapping optionals
>> >
>> > Best regards,
>> > Thomas
>> >
>> > _______________________________________________
>> > Unsubscribe & other changes:
>> > http://lists.boost.org/mailman/listinfo.cgi/boost
>> >
>>
>> _______________________________________________
>> Unsubscribe & other changes:
>> http://lists.boost.org/mailman/listinfo.cgi/boost
>>
>


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk