On Thu, Dec 17, 2020 at 5:07 PM Jean-Baptiste Vallon Hoarau via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
> Recently i've been pondering on ADL, customization points and interface adaptation quite a bit.
> (TLDR there's a paper embedded in this email that try to address these problems, let me know what you think)

I've read your attached paper, "Type-namespace and symbols set control." I think:
(1) It's got way too many new features bundled together in one paper. Are they all needed, or are you sneaking in some "nice-to-haves" among the "must-haves"? Which are which?
(2) The features are poorly motivated. I mostly understand what each of them does, physically, but I don't understand why I as a C++ programmer would want to do those things. I recommend using "Tony Tables" to show (on the left) today's C++20 code that accomplishes some realistic task, and then (on the right) how the same task would be solved in a simpler or more robust way using your new features.  The important thing in a Tony Table is that the left-hand column must be real code that people are writing today. If your proposal simplifies the writing of only some pieces of code that people don't actually want to write, then your proposal doesn't help.
(3) I don't see a migration path from "C++20 ADL" to "your thing." IIUC, you are essentially proposing to take today's working code

    namespace N {
        struct A {};
        void swap(A&, A&);
    } // namespace N

    void test() {
        N::A a, b;
        using std::swap;
        swap(a, b);  // should call N::swap, not std::swap

and silently break it.  You write:
"In order for a function F to be implicitly included in the set of available functions for unqualified look-up, F must be available in the associated anonymous type-namespaces of the types of the arguments."
So, either you are proposing a rule by which N::swap becomes "available in the associated anonymous type-namespace" of N::A, or else you're proposing to break this existing code. I don't see the former; I suspect the latter, which is a non-starter for WG21.

Longer/nittier comments:

(4) Your moo(cow) example in section 1.1 is isomorphic to
No less a personage than Herb Sutter has also proposed breaking this code, in P0934R0 "A Modest Proposal: Fixing ADL."  But, if you're proposing to break it, you should clearly and explicitly say so, and show this example (or something like it). Your current example with names like `my_type` and `moo` is too contrived.

(5) Also in that example, you say "Under the current ADL rules..." but that's meaningless, as your example code uses syntax that is not C++20 syntax — `template<class T> namespace <my_type<T>>` and so on. So there's no way of telling what the "current" rules would make of it.

(6) You write: "An anonymous type-namespace can be extended, unless declared `final`."  This is meaningless. Namespaces can't be declared `final` today, and I don't see any grammar in your proposal that would make it possible in the future. For another thing, namespaces are open by definition; suppose I have two translation units, and in one I define `namespace A final { int foo(); }` and in the other I define `namespace A { int bar(); }`. Neither TU is aware of the other. Are you proposing that this should just be IFNDR?

(7) In section 1.2's example, I recommend getting rid of the functions' bodies. Just put their declarations:
    template <class T>
    virtual namespace plot_traits { 
        Point2D get_plot_point(T&, int);
        int get_num_points(T&);
    template <class T>
    namespace complex_plot final : override plot_traits<std::vector<std::complex<T>>> {
        Point2D get_plot_point(T&, int);
        // OK as plot_traits<...> inside a plot_traits override always refer to the primary namespace
        using plot_traits<std::vector<std::complex<T>>>::get_num_points;
Incidentally, I've moved the `final` keyword to a more appropriate place (I assume that's what you intended).

(8) Your code comment there is completely at odds with how templates work anywhere else in the language. Normally, when I have a template with some partial specializations, the partial specializations are there specifically to avoid instantiating the primary template for some problematic type. You seem to be proposing that when plot_traits<X> refers to plot_traits<X>, the compiler should take that as a sort of "super class reference," and go and instantiate the next most specialized specialization of the template. What happens if there are multiple partial specializations available, and it's not clear which one is the next most specialized?

(9) Finally, where did the identifier `complex_plot` spring from?  What is its purpose?  What is the relationship between this "specialization" of namespace plot_traits<T> and the actual namespace complex_plot?
    namespace complex_plot { int baz(); }

(10) The punchline of section 1.2 seems to be that after jumping through all of these hoops, we can then use plot_traits<T>::get_num_points(t) exactly as if plot_traits were defined as a plain old traits class, like `iterator_traits` or `regex_traits`:

    template<class T>
    struct plot_traits;

So what's the purpose of all this new syntax?  What does it buy us?  Certainly not simplicity!

(11) In section 1.3, you should read https://brevzin.github.io/c++/2019/04/13/ufcs-history/ and then eliminate section 1.3.

(12) Section 2.1, "not using", is interesting.
Do you understand the subtle difference between "using N::foo;" and "using namespace N;"?  (I owe a blog post on this subject, although honestly I don't understand the reason it was done this way to begin with. Asked on SO: https://stackoverflow.com/questions/65365681/why-does-cs-using-namespace-work-the-way-it-does )
What should the effect of "not using namespace N;" be, if namespace N hadn't been "using-ed" to begin with?

(13) Section 2.2 lacks motivation. Remember, "motivation" isn't "Without this feature, my sample code won't compile!" and it isn't "This keyword kind of looks like it might do X, so let's make it do that."  You should write a Tony Table, showing some real code from your codebase on the left, and then showing how you want to be able to write it, on the right. Make sure the snippet is long enough that it's "falsifiable." You want the reader to be able to say, "Ah, yes, I agree that that is the best possible way to write that code in C++20, and I could not do better myself; and furthermore, I agree that the right-hand snippet is better."  If your snippet is too short and contrived, the reader will simply disagree that the left-hand snippet is reasonable.

(14) Section 2.3, I don't understand how this `namespace(T)` relates back to your original idea of having an "anonymous associated namespace" named `namespace<T>`. Are `namespace(T)` and `namespace<T>` the same thing? If so, pick one name and stick to it. Don't make two names for the same notion.

(15) Section 2.4 lacks motivation, and also lacks rigor — what do you mean by "prioritization" in this context? (But first, write a Tony Table! If you can't do that, then there's no point trying to explain what you meant by "prioritization.")

(16) Section 2.4 also seems to be assuming some kind of UFCS. In C++ today, `t.blah()` never calls a free function.

(17) Section 2.5 lacks motivation.
See D&E section 17.4, where Stroustrup writes:
> ...the original design allowed for several member names to be mentioned in a single using-declaration:
>     using X::(f,g,h);
> This is syntactically ugly, and so were all the alternatives we considered. ... Having used namespaces
> a bit, I found far less need for such lists than I had expected. I also tended to overlook such lists when
> reading code because they resembled function declarations too much, so I fell into the habit of using
> repeated using-declarations instead:
>     using X::f;
>     using X::g;
>     using X::h;
> Consequently, there is no special form of a using-declaration that specifies a list of member names.

I buy Stroustrup's logic.

Bottom line: I'm glad you're aware that lookup in C++ is a big mess with no logic. But it seems like you're just throwing a grab-bag of additional widgets at the wall, without actually trying to solve any existing problem. And you're proposing silent code breakage with no migration path.