Boost logo

Boost :

From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2024-12-28 11:21:27


sob., 21 gru 2024 o 13:54 Neil Groves via Boost <boost_at_[hidden]>
napisał(a):

> On Sat, 21 Dec 2024 at 12:11, Peter Dimov via Boost <boost_at_[hidden]
> >
> wrote:
>
> > Christian Mazakas wrote:
> > > I'm with Andrey, I think the iterator API *is* the useful API.
> > Typically, when I
> > > find something in a map, I'll either erase or do something else where
> > reusing
> > > the iterator is a key part of everything.
> > >
> > > My whole thing was about what users actually wanted vs all the costs of
> > > everything else.
> >
> > What this user has always wanted is to not have to write this:
> >
>
> > auto it = map.find( key );
> > if( it != map.end() )
> > {
> > // do something with it->second
> > }
> >
> > That's why I'm always defining a helper function `lookup` that returns a
> > pointer, which allows me to write this instead:
> >
> > if( auto p = lookup( map, key ) )
> > {
> > // do something with *p
> > }
> >
> > If there's a built-in way to obtain an optional<mapped_type&> instead
> > of an iterator, I can use that instead of `lookup`, without changing the
> > syntax.
> >
>
> What I tried to do was provide that with map.equal_range(key) |
> mapped_value | invoke(fn). And then tidy the syntax, but I accept that
> wasn't an outstanding success! I collapsed the map.equal_range and
> mapped_value into one step and then we had map | mapped_values(key) |
> invoke([](...) {})
>
> In the end what I had for you paraphrasing you snippet above would be:
>
> map | mapped_values(key) | invoke([&](auto&& p) {
> // do something with p
> };
>
> Obviously here I've pulled the "if" into the boilerplate code and
> eliminated the need for p to be optional. I like eliminating the
> possibility of a dereference of nullopt and I like not having to include
> either implementation of optional. If we need to have work in the "else"
> path then this is less awesome and projection to optional is one approach
> to tackle this. Where we would like to pick a replacement default value
> when missing that could probably also use syntactic sugar to replace the
> invoke. The composition possibilities looked interesting to me, and I
> thought that the common cases could appear approximately as the expressed
> desired syntax of other approaches with a little syntactic sugar.
>
> I was always open to name changing, so mapped_values could be "lookup" if
> you wanted. Of course I could go a step further and collapse those two
> adapters. We also discussed what would be returned, and of course it would
> be possible to return an optional single element where appropriate. I like
> the generality of passing the range of values back, especially since that
> works for multi containers. The optional, to me, looks to be an inferior
> alternative for an empty or not range, for many of the cases. Perhaps more
> real world examples would change my mind. Nonetheless I could give the
> projection to optional no trouble at all. Hence, in the end, I thought I'd
> pretty much got every issue I'd heard addressed. I realize though that
> small details to me may be much more important to others. I don't typically
> confuse my opinion with fact. I'm definitely not young enough to know
> everything.
>
> I liked not having the explicit if, but totally accept that before it
> becomes familiar it may look odd. It also takes away the possibility of
> incorrectly dereferencing a nullopt, while apparently providing a very
> similar solution to the expressed problem. One of the posted suggestions
> used the optional map function to get the same advantage.
>
> Thus I went on this journey to see if we could just keep the ranges we
> already had and get the syntax close to the original expressions. It looked
> pretty close to me, but it didn't appeal, which is totally fine. It would
> be boring if we all agreed all the time.
>
> I thus don't have anything concrete to merge that addresses the original
> poster's request, which is disappointing but totally okay from my
> perspective.
>

Hi Neil,
I think you may be drawing the wrong conclusions from this thread.
Your observations in this thread are very valuable. The positive outcome
may be not necessarily the specific changes in the libraries, but generally
raising the awareness of the design tradeoffs, things like pizza operator,
unified function call syntax, and ranges in general. There are a lot of
people that read this thread but do not talk, like myself (until now).
I believe you mentioned adding things to Boost.Ranges. I think it would be
beneficial, even if there still exist people that choose not to use them.
If Boost.Ranges are to be compared to other solutions we need Boost.Ranges
to be as good as possible.

Thanks,
&rzej;

>
>
> >
> > Although it strikes me that it should probably be named `try_at` instead
> >
>
> Totally with you on "try_at" versus "try_find", but if we use 0..1 ranges
> it is just equal_range, that's mapped_value adapted.
>
>
>
> > of `try_find`. `find` is already a try-ing member function, because it
> > doesn't
> > fail, whereas `at` both returns the correct reference type, and can fail.
> >
> > Of course `try_at` by convention ought to return boost::system::result
> > or std::expected instead of an optional, but that's another story.
> >
> > Interestingly, and maybe relevant for this discussion, `at` was added to
> > associative containers even though it could have been made a free
> > function instead.
> >
>
> I've looked at the recent standard changes and to me it looks like we are
> semi-randomly preferring member and non-member functions in an
> inconsistnent and arbitrary manner. We also added std::erase_if as a
> non-member for std::vector and other containers. I would estimate that you
> are probably aware of many more of these changes than I am. They've gone in
> both directions. To me it seems we can't use recent history to inform us. I
> accept that it may appear arbitrary and inconsistent because I have failed
> to comprehend the rules that drive the final decisions.
>
> Apologies if by asserting that I've achieved nothing this seems to be an
> emotional reaction. It isn't. While I'm disappointed I couldn't help with
> the original problem. I consider this eventuality to be part of the
> acceptable, expected set of outcomes from the effort. If it weren't then
> I'm not taking enough risk.
>
> My perception is that my suggestion doesn't have broad appeal and hence I'm
> not pushing to make it happen. Other solutions can be explored, or we can
> leave it as it is. I never intended my experimentation to block progress
> for other approaches. I also never intended to make any demands about how
> anyone approached the problem.
>
> I'm happy to continue to help, if I am actually doing so, but equally happy
> to get out of the way and let others come up with something else.
>
> Regards,
>
> Neil Groves
>
> _______________________________________________
> 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