C++ Logo


Advanced search

Re: [std-proposals] Return type of string_view::remove_suffix

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Sat, 07 Jan 2023 23:31:29 +0000
On 7 January 2023 23:13:33 GMT, Arthur O'Dwyer via Std-Proposals <std-proposals_at_[hidden]> wrote:
>On Sat, Jan 7, 2023 at 2:00 PM Giuseppe D'Angelo via Std-Proposals <
>std-proposals_at_[hidden]> wrote:
>> On 06/01/2023 17:28, Jason McKesson via Std-Proposals wrote:
>> >> so that we can do stuff like:
>> >>
>> >> string str("monkey5");
>> >> Func( string_view(str).remove_suffix(1u).remove_prefix(2u) );
>> > You could just do this:
>> >
>> > Func(string_view(str.begin()+1, str.end() - 2));
>> >
>> > This requires C++20 for the contiguous iterator support, but it does
>> > work. Note that the remove_* functions exhibit UB if you try to remove
>> > more characters than exist. So the fact that this too will exhibit UB
>> > in those situations is fine.
>> It's completely anti-ergonomic to have to do math like that.
>> Compare with something like Qt, where string classes have functions that
>> mutate in place and functions that return the mutated version:
>> view.chop(N); // mutates in-place, returns void
>> view.chopped(N); // does not mutate, returns a new view
>I agree with all three guidelines stated so far:
>(1) Math is un-ergonomic.
>(2) Active-verb and past-tense/adjectival-form (sort/sorted, chop/chopped,
>strip/stripped, trim/trimmed) are the Right Solution.
>(3) Having a method that *both* mutates *and* returns reference-to-*this is
>just asking for misuse, and should be avoided at all costs.
>But this particular operation has two unusual problems: we have to think
>about consistency with the methods that already exist (problem for (2)),
>and the operation itself is not simple (problem for (1)).
>After all, `string_view` already has a substring method — it's called
> Func(str.substr(1, str.size() - 3));
>This is shorter than Jason's
> Func(std::string_view(str.begin()+1, str.end()-2)); // ...or...
> Func(std::string_view(str.data()+1, str.size()-3));
>but it is equally as mathy and un-ergonomic.
>The Best Solution, which C++ will probably never get, is for negative
>indices to be treated Python-style, so we could write something like
> Func(str.fromto(1, -2));
>But that's still got trouble because "the operation is not simple." Is that
>second argument a *position* or a *length*? I tried to indicate "position"
>by naming the method `fromto`... but `fromto` is a *terrible* name a-priori.
>Basically, no small tweak seems appropriate here. You can't even apply
>guideline (2), because what even is the past tense of "remove_prefix"?
> Func(str.removed_prefix(1).removed_suffix(2)); // ??
> Func(str.remove_prefixed(1).remove_suffixed(2)); // ??

What about "without_prefix" and "without_suffix"? When used, it reads almost like a proper English phrase. `some_str.without_prefix(some_other_str)`.

> Func(str.after_removing_prefix(1).after_removing_suffix(2)); // ??
>The mutators have such unwieldy names that the non-mutators are constrained
>(by consistency) to also have unwieldy names and thus probably go unused.
>Finally, I note that in C++20 Ranges the `views::take` and `views::drop`
>adaptors special-case `string_view`, so all you need is to wait for
>`drop_last`. Circa C++26-ish you might be able to finally write
> Func(str | std::views::drop(1) | std::views::drop_last(2));
>And then it's relatively easy to write your own "un-piping wrapper" that
>would let you use nice object-method syntax with all the standard view
> Func(+UnPipe(str).drop(1).drop_last(2));
>In fact, someone's probably done a library like that already, right? If
>not, somebody has a niche to fill! :)
>my $.02,

Received on 2023-01-07 23:31:36