On Mon, Jul 20, 2020 at 12:43 PM Richard Hodges via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Mon, 20 Jul 2020 at 18:03, codusnocturnus via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
This would be great - just remove the braces, and the .’s, and the struct.

At this point it becomes an argument over syntax [...]

I think it's common to think, "language X has a nice way of expressing Y - why don't we do that too?"
I can be guilty of that just like anyone else. 
But in the end, if a language gives you a way to express intent, one might wonder whether it's worth expending effort in making syntax nicer for niche use cases in favour of providing more utility or fixing design bugs.

Richard, apparently your notion of "express intent" doesn't match up with mine.
When I say that C++ gives the programmer a way to express his intent, what I mean is that C++ provides a specific syntax for that exact intent, which is intended to be used if and only if that's the programmer's intent. For example, when I see

    void foo(const std::string& x);

I know that the programmer's intent is that `x` should remain unchanged by a call to `foo`.  Now, physically, `foo` could still change `x`, because of `const_cast`; but in practice the `const` keyword gives me a hint that in general is really strongly correlated with the programmer's intent.

Similarly, if I see an overload set consisting of the signatures

    void foo(int x, int y);
    void foo(int x, int y, bool dx, bool dy);

that's a very strong indication that the programmer intends to permit the caller to call `foo` with either of these signatures, and no others.  I consider overloading a good example of "features that allow us to express intent."

On the other hand, if I see

    void foo(int x, int y, bool dx=false, bool dy=false);

that's much less of a hint about intent, because it indicates that either the programmer meant to permit a call like `foo(1, 2, true)` or else the programmer doesn't know what they're doing. (In my experience, it's usually the latter.)

To your specific example: If I see

    struct FooParams { int x, y; bool dx=false, dy=false; };
    void foo(FooParams params);

well, that's basically no hint at all as to what the programmer intends. Sure, it physically permits me to call `foo({1, 2, .dx=true})` or `foo({})` or `foo(FooParams(1, 2, false, true))` — but the code gives me practically zero indication of what the programmer intended me to do!

To me, "a feature that allows me to express intent" would be the exact opposite of "a stack of features that can be house-of-cardsed into something that physically resembles what I'm trying to do."

Also from C++20: The `concept` keyword doesn't add anything physically helpful(*) over and above the preexisting house-of-cards that was `inline constexpr bool fooable_v`; but it does permit programmers to express their intent better. (* — It adds subsumption, but I don't consider that to be helpful.)
Constraining a function template with a `requires` clause doesn't add anything physically helpful(*) over and above the preexisting `enable_if`/return-type-SFINAE tricks; but it does permit programmers to express their intent better. (* — It raises the template's overload-resolution priority, but I don't consider that to be helpful.)
Even C++20's `auto operator<=>(const Me&) = default;` could be considered to "express intent" better than what came before it.

I'm sympathetic to the idea that programming languages should permit the programmer to express intent.
I don't think this specific thread has suggested any specific ideas that would meet that bar w.r.t. named parameters, though. Named parameters are a very old idea that a lot of people have tried and failed to shoehorn into C++.

–Arthur