On Sat, Aug 27, 2022 at 11:21 AM Михаил Найденов via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hello again,
I ended up writing a small proposal on this topic as I am quite bothered with the issue.
Attached is the draft

Hi Mikhail,
I looked at your paper. I think it needs to use the words "concept maps" somewhere in the paper: that's basically what you're proposing as a solution, but the paper doesn't show any evidence that you've dug into the previous proposals and why they failed.

Then, at a higher level, you have not convinced me that there's any problem here at all! Your original, "just programming," version of your function looks like this (quote):
void silly(string& s)
{
  using char_type = string::char_type;
  // ...
  if(s.starts_with("hello"))
     s.clear();
  // ...
}
I don't think that code is ordinary "just programming" at all! `std::string::char_type` (1) does not exist, and (2) even if it did exist, I assume it would be an unnecessarily verbose way of spelling "char". So let's eliminate that line. Then, we're left with nicely generic code, that looks just like classic Stepanov STL code. This function template (or "algorithm") can be compiled and works perfectly for any concrete type that implements the `starts_with` method (e.g. `string`, `string_view`) and the `clear` method (e.g. `string`, `vector`, `deque`, `map`, `set`...)

template<class T>
void silly(T& t) {
    if (t.starts_with("hello")) t.clear();
}

Of course in the actual STL there's only the one type (`string`) that supports both of those operations. But that's fine, because that's the only STL type that can actually be used with this template. If we intended to use it with both `string` and `string_view`, we could generalize it a little further like this:

template<class T>
void silly(T& t) {
    if (t.starts_with("hello")) t = T();
}

But nobody writes templates in a vacuum: there's always some actual business purpose behind writing the template. Usually it's to avoid code duplication: we have two or more known types that satisfy the same interface, and so we can write one ("statically polymorphic") version of our algorithm using a template like `silly`. The interface and the template algorithm generally will evolve cooperatively.  For example, the STL is designed to facilitate the writing of algorithms that work for any kind of STL container, so, all STL containers support the same vocabulary of methods: `insert`, `erase`, `begin`, `end`, `T::iterator`, `T::value_type`, and so on.

It seems to me that you're identifying the problem as "I can't write a template that works for all possible types, because (statically-)polymorphic code implies an interface, and not every possible type will implement the interface I require."  But that's not a real-world problem, because in the real world we don't write code to work with every possible type.  And then, you have an XY problem: you try to get around this artificial problem by crufting up your code, turning all your methods into free functions and adding a lot of `::`s, and then complain that this makes the code uglier. Yes — but that's the "Y" problem! Crufting up the code is ugly, but it isn't necessary to solve your "X" problem; and in fact, it's not even sufficient. In order to use polymorphism (either static polymorphism with templates, or classical runtime polymorphism with inheritance), your types must conform to some kind of interface. That's both unavoidable and beneficial-to-the-reader.

my $.02,
Arthur