C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Generic code, not the API you are looking for

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sun, 21 Aug 2022 13:39:58 -0400
On Sat, Aug 20, 2022 at 6:52 PM Zhihao Yuan via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Saturday, August 20th, 2022 at 6:27 AM, Jason McKesson via
> Std-Proposals <std-proposals_at_[hidden]> wrote:
> > > In the protocols/generics model "the concept" is an entity by itself,
> much like Zhihao said. Inside func, the code will actually ask String
> itself for methods, not directly the class that it is instantiated with.
> >
> > That ship sailed when C++20 standardized a concept model that was
> > fundamentally incapable of definition checking. C++20 concepts are
> > exactly and only a way to constrain a template declaration, nothing
> > more. And there's no simple way to turn them into something more.
>
> I don't know why "concept model" is brought
> up here. [...]


Well, as I understand it, Jason was interpreting your suggested "protocol"
paradigm as a tweak to the existing C++20 Concepts paradigm (which it
definitely can't be); it seems more likely to me that you intended it as
Yet Another Paradigm in the multi-paradigm language that is C++. So if we
allowed "protocols," then we'd have at least three competing/coexisting
paradigms for polymorphic programming:
- classical inheritance-based polymorphism
- templates (i.e. unconstrained or constrained, but in either case *not*
C++0x "concept maps")
- "protocols" (i.e. Go interfaces, type erasure) <— this new thing

Jason wrote:
> what happens if/when I need a "generic" based on a concept that takes
more than a single type parameter?

Type erasure is based on unary interfaces by definition. It simply cannot
handle STL-style webs of interrelationships between T, T::value_type,
T::iterator, T::const_iterator, and so on. It doesn't work for that stuff.
So "protocols" wouldn't be attempting to replace STL-style templates;
"protocols" would just be yet another paradigm that programmers could
*choose* to use or not.
(Now, I think having too many paradigms is a bad thing; but I recognize
that that argument holds little water, because the "having too many
paradigms" ship sailed in C++ sometime in the mid-1990s. ;))

It does occur to me that if all you want is "concept maps," you can get
that today via basically the same mechanism that gave us std::string_view:
write an adaptor that takes in a "suitably string-like" type and spits out
an actually string-like type. It's very fiddly today, though, I admit.
https://godbolt.org/z/Kb1dnPaGn

    std::string_view StringLikeOf(const std::vector<char>& v) {
      return std::string_view(v.data(), v.size());
    }
    template<StringLike S>
    const S& StringLikeOf(const S& s) { return s; }

    template<StringLike S>
    void function(const S& sx) {
      decltype(auto) s = StringLikeOf(sx);
      [...use (s) instead of (sx)...]
    }

For the difficulties that would be caused by any attempt to "half-do"
concept maps, the background reading I know of includes

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0782r2.html
(One problem is basically that
    protocol String {
        bool startswith(std::string s) const;
    }
now *forces* `myString.startswith("hello")` to construct a `std::string`
argument object, even when the original type would have known how to do the
operation on a `const char*` more efficiently. Flattening overload sets in
that way is usually *not* beneficial to performance. It has other
advantages; but performance is not one of them.)

and
https://quuxplusone.github.io/blog/2021/02/13/blog-roundup/#i-also-learned-a-bit-about-auftr

my $.02,
Arthur

Received on 2022-08-21 17:40:11