On Sat, Jan 7, 2023 at 2:00 PM Giuseppe D'Angelo via Std-Proposals <std-proposals@lists.isocpp.org> 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 `substr`!
    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));  // ??
    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 adaptors:
    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,
Arthur