Date: Fri, 7 Apr 2023 21:37:35 +0200
No, I don't have a working implementation, but here is an example that
demonstrates the benefits:
https://www.godbolt.org/z/Ejn9KK57x
When the polymorphic class is already de-virtualized, then returning
Base& breaks the de-virtualization in the second and third call. With
a "this" return type, we would have the guarantee that the dynamic
type stays the same, so we can keep making direct calls.
The only exception to this is when a virtual function ends and begins
the lifetime of "this" before returning, though I'm not sure if this
is really allowed by the standard, and could also be declared UB for
this return types, if need be.
On Fri, Apr 7, 2023 at 8:50 PM Jens Maurer <jens.maurer_at_[hidden]> wrote:
>
>
> On 07/04/2023 19.14, Jan Schultke via Std-Proposals wrote:
> > For many operator overloads like assignment or pre-increment, as well
> > as builder pattern functions, you tend to write:
> > return *this;
> >
> > What if we could write the following:
> > struct T {
> > int i;
> > this operator++() { ++i; }
> > };
> >
> > A return type of `this` would result in an implicit return T by
> > reference, with qualifiers taken from the function (e.g.
> > const-qualified member functions return const T&). This saves one line
> > of boilerplate in many places, saves developers from forgetting to
> > return *this, and can improve performance.
>
> I can see this is technically feasible, but it adds a little more
> special-casing to the language without significantly increasing
> the expressiveness (but see below). At this point, I'm not convinced
> the effort-vs.-reward ratio is good enough. A potential future
> paper should discuss these concerns:
>
> Compilers are pretty good giving a warning when you fall off the end of
> a value-returning function.
>
> "this" has pointer type, but the syntax actually wants to describe
> by-reference return (i.e. "return *this"). There is a disconnect
> in the syntax here.
>
> > Namely it improves performance because it can help with devirtualization:
> > x.fun1().fun2().fun3()
> >
> > If three virtual member functions return T&, that T& may not be a
> > self-reference, so it requires a vtable lookup each time. If the
> > member functions return "this", then the dynamic type must stay the
> > same and the second and third call can use the same vtable pointer.
>
> I can see that argument (note the redundant vtable loads):
>
> https://www.godbolt.org/z/9516f5PY3
>
> However, using "this return" in this case would introduce
> covariant return types, which come with their own thunk
> mechanism for pointer adjustments, which may or may not be
> desirable.
>
> Also, I note that the "operator++" use case is one where virtual
> functions are discouraged in the code bases I've seen.
>
> Do you have a sample implementation that can demonstrate
> actual performance improvements for the generated code?
> I wouldn't expect virtual functions to be used pervasively
> in hot code paths.
>
> Jens
demonstrates the benefits:
https://www.godbolt.org/z/Ejn9KK57x
When the polymorphic class is already de-virtualized, then returning
Base& breaks the de-virtualization in the second and third call. With
a "this" return type, we would have the guarantee that the dynamic
type stays the same, so we can keep making direct calls.
The only exception to this is when a virtual function ends and begins
the lifetime of "this" before returning, though I'm not sure if this
is really allowed by the standard, and could also be declared UB for
this return types, if need be.
On Fri, Apr 7, 2023 at 8:50 PM Jens Maurer <jens.maurer_at_[hidden]> wrote:
>
>
> On 07/04/2023 19.14, Jan Schultke via Std-Proposals wrote:
> > For many operator overloads like assignment or pre-increment, as well
> > as builder pattern functions, you tend to write:
> > return *this;
> >
> > What if we could write the following:
> > struct T {
> > int i;
> > this operator++() { ++i; }
> > };
> >
> > A return type of `this` would result in an implicit return T by
> > reference, with qualifiers taken from the function (e.g.
> > const-qualified member functions return const T&). This saves one line
> > of boilerplate in many places, saves developers from forgetting to
> > return *this, and can improve performance.
>
> I can see this is technically feasible, but it adds a little more
> special-casing to the language without significantly increasing
> the expressiveness (but see below). At this point, I'm not convinced
> the effort-vs.-reward ratio is good enough. A potential future
> paper should discuss these concerns:
>
> Compilers are pretty good giving a warning when you fall off the end of
> a value-returning function.
>
> "this" has pointer type, but the syntax actually wants to describe
> by-reference return (i.e. "return *this"). There is a disconnect
> in the syntax here.
>
> > Namely it improves performance because it can help with devirtualization:
> > x.fun1().fun2().fun3()
> >
> > If three virtual member functions return T&, that T& may not be a
> > self-reference, so it requires a vtable lookup each time. If the
> > member functions return "this", then the dynamic type must stay the
> > same and the second and third call can use the same vtable pointer.
>
> I can see that argument (note the redundant vtable loads):
>
> https://www.godbolt.org/z/9516f5PY3
>
> However, using "this return" in this case would introduce
> covariant return types, which come with their own thunk
> mechanism for pointer adjustments, which may or may not be
> desirable.
>
> Also, I note that the "operator++" use case is one where virtual
> functions are discouraged in the code bases I've seen.
>
> Do you have a sample implementation that can demonstrate
> actual performance improvements for the generated code?
> I wouldn't expect virtual functions to be used pervasively
> in hot code paths.
>
> Jens
Received on 2023-04-07 19:37:48