C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Paper on Interfaces (5 Pages)

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Sat, 25 Feb 2023 11:44:27 -0500
On Sat, Feb 25, 2023 at 6:48 AM Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> wrote:
>
> On Fri, Feb 24, 2023, Ville Voutilainen wrote:
> >
> > This paper should be burned, not sent to WG21 to spend time on.
>
>
> I admire your fervour; it's important to have passion in debate.
>
>
> > Okay then. The production of this paper is ignoring feedback,
> > especially including examples where the goal of this facility can just
> > be achieved with the existing language,
>
>
> I did read the email you sent on Thu, Feb 23, 2:08 PM (UTC+0) however
> since you didn't post any code, and since my imagination didn't
> spontaneously compose the code you were describing, I don't yet have a
> 'pure library' solution to the problem I posed.
> The burden of proof rests with the person making the assertion. *You*
> are the one saying that what I want can be achieved without editing
> the core language. Don't rely on my imagination, give me the proof. If
> you're not bothered writing code then don't expect me to be bothered
> wrangling your hypothesis.

Overall, this is my biggest problem with basically everything
surrounding your attitude towards your proposals.

The way you discuss your proposals suggests an attitude of thinking of
your proposals as things which ought to be accepted. Motivations?
Problems to be solved? Alternative ways to achieve the same effect?
You seem to treat all of that as sophistry, irrelevant to the topic at
hand. There is a change to the language that *should be made.* Since
it is a thing that ought to be done, any discussion of its merits is
off-topic; you only wish to discuss the shape of that change.

I don't know if you truly feel that way, but that is the general
attitude I get from the way you talk about your proposals: they are
right, they definitely should happen, and the only thing that matters
is what form they should take.

Let us ignore what this represents and instead focus on something more
practical:

You are not going to convince other people to do anything if you
approach the process in that fashion.

This perspective might work when you are in charge, when you have a
position of power over a group of people and can demand that they work
on this thing you want done. They can have input over its shape, but
that the change is going to happen is not something they get to opine
on.

That perspective does not work when those "other people" don't work
for you. It is not going to convince anybody to take *their* time to
change the language as you *dictate*.

What *does* convince them to take their time is to explain why it
needs to happen. You need to demonstrate that you yourself have taken
time to put together a well-considered idea. You need to demonstrate
that you have explored the space of possibilities for this change, and
you see a language change as the only viable solution to the problem.
You need to demonstrate that the problem exists and that your proposed
solution can have positive impacts on real C++ programmers.

In short, you should treat your proposal as an idea that needs to
justify *itself*.

What you're doing now is, at the very least, *unconvincing.* It is an
ineffective technique for getting people on your side.

My suggestion to you is to be more *effective.*

> - - - - - - Moving on to next author - - - - - - - -
>
>
> Jason McKesson wrote:
> > It makes a mockery of the type system and even if this were a
> > well-formed proposal, it should be abandoned on that basis.
>
>
> And what about a 'union'? Do think a union has the utmost reverence
> for the type system?

They do work within the object model. They are an object that has a
number of subobjects within it, but only one of them can be within its
lifetime at any one time. The basic idea of objects and lifetimes is
respected, even if it can be a bit odd that you can switch which
objects are within their lifetimes with seemingly innocuous
statements.

> Since /every/ C++ compiler can already do what I'm proposing, I'm
> really just asking for the Standard to explicitly allow something that
> every compiler is already doing anyway.

Yes, and that's the problem.

P0593 was an idea that was "just" asking the same thing: compilers
allow programmers to get away with X, so let's standardize X. But
rationalizing that out within the object model involved creating a
number of new concepts: implicit object creation,
pointer-to-a-suitably-created-object, etc. It was a substantial change
to the object model that involved months-to-years of back-and-forth to
work out all the details. It worked out in the end, and it's a good
feature. But it wasn't just two sentences in a proposal that said,
"compilers do this, so let's just make it legal".

Also, its argument wasn't "compilers already do this;" it was "*users*
already rely on this, so let's protect them." That is far more
convincing as a motivation for a change.

What you're proposing would likely require a similar level of change,
but it wouldn't have anywhere near the user-facing benefits of P0593.

> > The text of this proposal treats an "interface" as a thing that is a
> > type. It is not presented as a new kind of entity; it is a type. This
> > is why you have to explicitly forbid things like virtual functions,
> > member variables and the like, because the proposal treats an
> > "interface" as just a new way to write a type. The "interface"
> > inherits from a type and therefore inherits everything in the "base"
> > type.
> >
> > That is not acceptable.
>
>
> Yes, every interface is a type, in fact you can even typedef an
> interface, for example:
>
> interface lockable_binary_semaphore : std::binary_semaphore { /*
> Stuff goes here */ };
>
> typedef lockable_binary_semaphore monkey;
>
> You have closed out your paragraph with the one-liner "That is not
> acceptable" without saying why. As I tole Ville above, I'd prefer you
> didn't rely on my imagination.

If you propose a medical procedure, and someone points out that this
procedure requires breaking every bone in the patient's body and says
"that is not acceptable," one doesn't need very much imagination to
understand why this is the case. Nor does one need to understand why
it's the person proposing such a procedure who needs to explain why
such a thing is medically necessary.

> > The reason why "casting" a class to a derived class that it definitely
> > is not is UB is because it breaks the strict aliasing rule. There is
> > no derived class object instance there, so pretending that there is
> > one is nonsense. That this "works" on various compilers is completely
> > irrelevant to this fact. It is UB behavior because it makes no sense
> > in terms of the object model.
>
>
> There's a page in my paper dedicated to aliasing but maybe you didn't
> read it. Here you're talking about UB but my paper explicitly says
> that the behaviour is well-defined.

Declaring that it shall be well-defined does not cause your idea to
actually *make any kind of sense* in terms of the object model. Your
text speaks entirely in terms of what "the compiler" does. The
standard doesn't care about what "the compiler" does. This is about
the object model and the implementations thereof.

Consider this:

```
derived_class some_derived_object = ...;
base_class &b = some_derived_object;
b.func();
```

Why does this work? `some_derived_object` is not in fact a
`base_class` object. So one might expect that this should fail, since
you're accessing a reference to the wrong type.

It works because the conversion from a derived class object to one of
its base class subobjects results in a pointer to that object. That
is, there is an object of type `base_class` living inside of every
`derived_class`, and this conversion gets a reference to it.

Consider this:

```
class_type my_obj = ...;
int &val = *(static_cast<int*>(&my_obj));
val = 20;
```

Does that work? Well, that depends: is there an `int` within
`class_type` which is pointer-interconvertible with `class_type`? If
so, then `val` is a reference to that subobject of `my_obj` and this
code is valid.

It's important to understand that in both cases, there is an actual
object of that type within its lifetime present when the conversion
happens. The conversion simply gives you access to it. It is that fact
which allows accessing the reference to work in accord with the strict
aliasing rule.

Now consider what you want:

```
class_type my_obj = ...;
interface_type &val = my_obj;
val.func();
```

`val` is a reference to an `interface_type`. But it is unclear what
that *means*. Does `val` refer to an object of type `interface_type`?
If so... where did that object come from? It didn't exist before;
`class_type` doesn't have one. What rule do you propose to cause it to
manifest into being? What things will cause it to exist, and what
operations make it go away? How does that lifetime interact with other
objects (perhaps other interface objects) at that same address?

If there is no object of that type there, then why does `val.func()`
work? What rule do you propose to make to allow this to work, and what
does "work" here even mean? What does it mean to call a non-static
member function on an object that *does not exist*?

Like, this *might* make sense if you require all of these member
functions to be declared as explicit object parameter member
functions, where the object parameter *must* be of a base class type
(or in the case of template deduction, will be deduced as such):

```
interface interface_type : public class_type
{
  void func(this class_type &self) {}
};
```

This would make it clear that nobody ever attempts to access a
non-existing object. `func` only ever gets a `class_type` object and
`interface_type` is a fiction. However, this would make it difficult
for `func` to call other functions within `interface_type`.

The overall problem here is that you're not considering the object
model at all. You're just looking at compiler behavior and saying "the
standard should make that legal". You don't care that the object model
has a rationale to it or that your change breaks any semblance of
logic to that rationale. You just want the change.

> > Trying to hack the type system for this is just not acceptable as an approach.
>
>
> Your use of the word 'hack' here is where I would use the word 'change'.

A hack is a change someone makes by thoughtlessly driving a bulldozer
through whatever code stands in the way of making that change. That's
basically what you're proposing here. Your language change is nothing
more than "whatever it has to be to make what I want work; someone
else gets to work out the details."

Again, not an effective strategy for convincing others.

Received on 2023-02-25 16:45:20