C++ Logo


Advanced search

Re: The unnecessary confusion of the C++23 proposal P0847R6

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Mon, 2 Aug 2021 10:14:12 -0400
On Sun, Aug 1, 2021 at 7:51 PM Hani Deek via Std-Discussion
<std-discussion_at_[hidden]> wrote:
> > While I agree in principle that we do not want unnecessary complexities,
> > the proposal does solve immediate problems (code duplication is bad,
> > right?) without too much learning overhead. So it looks good to me (from a
> > user point of view).
> All the benefits listed in the paper, including the avoidance of code duplication, can be obtained simply by adopting the new syntax to define non-static member functions, without changing or adding anything else to the standard.

I fail to see how *this* doesn't add similar "complexity" to the language.

Let's say we do what you say. We define that these functions are
non-static in every way. So... what is the type of this:

struct foo
  void ex_mem(this foo self);

That is, what is the type of `&foo::ex_mem`?

If this function must in all ways be a regular non-static member
function, then that `self` parameter needs to go away. After all,
member pointer syntax is of the form
`ReturnType(ClassName::*)(Parameters) Qualifiers`. The implicit `this`
parameter is defined by the `Qualifiers`, not the `Parameters`.

So now a user needs to stick the first parameter in the `Qualifiers`
section. Personally, I would find this to be *incredibly* confusing.
The parameters of a function declaration should match the parameters
in a member pointer. You shouldn't have to shuffle them around for no

Note that the current proposed behavior doesn't have this problem. The
parameters in the declaration are always the same when used as a
function pointer.

The other issue is that the current set of `Qualifier`s are inadequate
for representing "all the benefits listed in the paper". In the
example above, `ex_mem` takes its parameter by value. There is
currently no `Qualifier` that means "value". Similarly, the current
proposal allows for an explicit parameter to have a type that is not
the same as `ClassName`. So you'd have to create some new `Qualifier`
syntax that could express the full range of possibilities.

Or just make it act like a static member when you get its address.
That's *much* simpler than adding a bunch of new trailing qualifier
syntax. All of the parameters are spelled out exactly as listed, and
you don't have to add more stuff to the language.

That means *less* complexity, not more.

> Unfortunately, however, the paper is not satisfied with that simple fix. They want to add the following complexity to the language.
> Quote from the paper: "The status quo is that all member functions are either static member functions or non-static member functions. A member function with an explicit object parameter [...] is a third kind of member function that’s sort of halfway in between those two. They’re like semi-static member functions. We’ll call them explicit object member functions due to them having an explicit object parameter. You can think of regular non-static member functions as being implicit object member functions. The high level overview of the design is that from the outside, an explicit object member function looks and behaves as much like a non-static member function as possible [...] But from the inside, an explicit object member function behaves exactly like a static member function." --end of quote.

You keep saying that it is "complexity" but you never explain *why*
this is "complexity". Consider the above: I went into detail as to
exactly where your proposal would add complexity. I've yet to see you
give a similarly detailed account of the increase in complexity. All
you say is that "it's a third kind of member function, and that's

Indeed, I would argue that this *simplifies* classes. Why? Because
pointer-to-member-function syntax and trailing qualifiers are
*complicated*. They have their own special rules and so forth that
don't work at all like regular functions. Having no reference
qualifiers doesn't mean it takes `this` by value the way it does
everywhere else. Member pointer syntax is exceedingly ugly, as is the
tortured syntax for *calling* them. And this is ugly by C++ standards.

You may have gotten used to these rules, but not having to know about
them makes the language simpler.

By contrast, explicit `this` makes all parameters behave the same. The
kind of function pointers you get out of them work exactly like any
other function pointers; no special `->*` or whatever syntax is
needed. And indeed, it makes explicit members and static members
behave the same.

The only odd-man out here are implicit member functions. And the
*only* reason to still use them (besides legacy/cross-version code) is
for `virtual` functions. Which makes sense, as they are indirect
callable functions that are inherently dependent on their class types
to do dispatch. So having to use specialized syntax on them, like
`->*`, makes sense. They're a weird kind of function with its own
weird properties.

Give me an example of some code using this feature that would be too
complicated for a user to learn. Not merely that would be momentarily
surprising for a user to see their code fail to compile, but that
would make code using it needlessly complex.

> It seems they are adding this new type of member functions only because they want to be able to pass the object argument by value, which is a trivial thing and hardly can be called a benefit.

That is not *the* motivation for the syntax. It's merely a thing it does.

> Let's wait and see what the final adopted text will look like. I still doubt that the proposal in its current form will make it to the standard.

Do you have a basis for saying that? CWG and EWG both seem to like it
a whole lot: https://github.com/cplusplus/papers/issues/115

> In recent years the trend has been to remove unnecessary complexities from the language.

Received on 2021-08-02 09:14:26