Hi Mihail,

 

if you want to just give directional guidance or you would like to have a directional vote, why not contribute to this customization point paper (if the author agrees)

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2279r0.html

https://github.com/cplusplus/papers/issues/972

 

instead of creating a new paper?

 

With a special focus, what is missing in

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2547r0.pdf

https://github.com/cplusplus/papers/issues/1208

which is finished up for shipping with C++26.

 

Best,

Sebastian


 

-----Ursprüngliche Nachricht-----
Von: Михаил Найденов via Std-Proposals <std-proposals@lists.isocpp.org>
Gesendet: Di 30.08.2022 17:51
Betreff: Re: [std-proposals] Generic code, not the API you are looking for
An: Arthur O‘Dwyer <arthur.j.odwyer@gmail.com>;
CC: Михаил Найденов <mihailnajdenov@gmail.com>; sotrdg sotrdg via Std-Proposals <std-proposals@lists.isocpp.org>;
 

On Mon, Aug 29, 2022 at 6:32 PM Arthur O'Dwyer <arthur.j.odwyer@gmail.com> wrote:
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.

Hello,
I am deliberately not providing, or investigating, a solution mainly because there is no simple one, much like you explained in Your previous post. What is the point discussing concept_maps when we don't have checked concepts, concept preservation, nominal conformance?
The proposal is a top-down view of what I believe is desirable by many - to have generic code that works on all/external types and does not require effectively a rewrite of the original algorithm and/or extensive planning just because it is generic. 
 
 
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.
 
I think I will change the example to not be a string or have standard operations. This was supposed to be some simple user code, a user class of whatever. 
 
 
 
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.

This is not fair. The problem is that we have two static polymorphisms right now:
 - One is the naive-but-simple "turn it into tparam"  
This one considers the interface as something natural to the type - a type having begin(), contains() is a container. Period. Conforming to that interface is "hard" - it has to come naturally, effectively be subclassing.
 - One is (very) advanced
This one, on the contrary, does not assume the type models the interface - it might, it might not, in any case the type must be able to model it... any type. Also, exactly because there are no assumptions, the interface needs nominal conformance. Conforming is "easy" in the sense it does not require subclassing. However all the burden is on the original developer of the genetic code. Not only a heavy burden, but code change requirement as well, a rewrite if not planned for.

Are we OK with that? Is this a natural separation or a language limitation? Or may be a natural evolution that highlights a limitation?
Is the solution polishing the second and still having two systems, or overhauling the first to the point it can serve the second as well? 
 
 
my $.02,
Arthur
-- 
 Std-Proposals mailing list
 Std-Proposals@lists.isocpp.org
 https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals