Date: Thu, 24 Sep 2020 01:58:39 +0300
On Thu, 24 Sep 2020 at 01:05, Eric Lengyel <lengyel_at_[hidden]> wrote:
>
> 1) What are the use cases for having a disjoint this pointer?
>
> The first example that comes to mind is a *= operator for a matrix class. If it's declared like this:
>
> Matrix& operator *=(const Matrix& m) disjoint;
>
> then the compiler can assume that m is not the same matrix as pointed to by the this pointer, and it would be free to store results immediately instead of putting them in temporaries until all reads through m are completed.
>
> A symmetric declaration like this:
>
> Matrix& operator *=(const disjoint Matrix& m);
>
> would have the same effect.
Right. Note that if you have
template <class T>
Matrix& operator*=(const T& m)
{
if (this == &m)
return *this;
/* the rest of it */
}
this now has the curious property that if called with a
reference-to-distinct, the compiler knows that
the self-assignment check can be axed.
But, well. Putting it into the type system means that template
specializations for Foo* and disjoint Foo* are separate.
Furthermore, allowing it as a member function cvd-qualifier means that
library wrappers that wrap member functions
need to (again) bifurcate their set of known signatures they can wrap.
> 2) If I have a Foo::operator=(disjoint Foo&&) disjoint;, that's presumably a move assignment operator, so it's considered a special member function. Curiously enough, that seems to be a flavor of a move assignment operator that knows that self-move is not possible. Even more curiously, that doesn't mean that the disjointness necessarily leads into a compiler optimizing away self-move checks, because since this is a separate function, it could just be written not to do such checks.
>
> I see your point, and I agree that this is an area full of redundant coding and tediousness. What would be nice is a way to have some kind of qualifier template parameters so you could write the code once and let the compiler generate different versions of the function for different qualifiers on the argument or on this:
>
> template <qualifier X, qualifier Y> operator =(X Foo&&) Y;
That doesn't change the template specialization duplication and member
function wrapper code bifurcation mentioned
above, though.
> 6) Consider
> disjoint Foo a;
> disjoint Foo* b = &a; // #1
> disjoint Foo* c = nullptr;
> c = b; // #2
> Is this well-formed?
>
> Yes.
>
> > How is a pointer disjoint if it can be assigned from another disjoint pointer?
>
> Disjoint is not a property of the pointer but of the storage pointed to. It's up to the programmer not to misuse the tool.
Right, my terminology mistake. I find it interesting that you first
say that it's up to the programmer not to misuse
the tool, and later say it's a safety-enforcing tool. I get the drift,
it increases safety but doesn't provide complete safety.
However.. see below.
> 7) All this stuff seems very complex compared to being able to mark function parameters as disjoint from each other.
> But that leads to the safety and stability problems addressed in the proposal, and it doesn't allow for overloading.
Why.. do I care that it doesn't allow for overloading? I could
entertain (but not necessarily advocate, too unbaked)
exploring an attribute solution where you just annotate variables and
parameters, and a compiler can diagnose
mismatches. That wouldn't be as deep-impact language change, but sure,
it wouldn't allow overloading either.
And as far as safety goes, well.. it's trivially easy to make copies
of a pointer-to-disjoint, and pass multiple copies
around wherever, and later end up calling a function that wants
multiple pointers-to-disjoint that aren't. I could
entertain the thought that pointer-to-disjoint would only convert from
an xvalue pointer-to-disjoint. But I'm not sure
whether that would help either.
There is a previous proposal for restrict-like semantics for C++,
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3988.pdf
I wonder what the people who worked on that think about baking the
disjointness into language semantics instead.
Rephrasing my main concern: the cost/benefit ratio of this looks
awkward. Needing to tell an optimizer that two pointers
are disjoint should be rare. But making it a new cvd-qualifier and
baking it into the type system puts it on everybody's face.
That seems like the tail wagging the dog to me.
>
> 1) What are the use cases for having a disjoint this pointer?
>
> The first example that comes to mind is a *= operator for a matrix class. If it's declared like this:
>
> Matrix& operator *=(const Matrix& m) disjoint;
>
> then the compiler can assume that m is not the same matrix as pointed to by the this pointer, and it would be free to store results immediately instead of putting them in temporaries until all reads through m are completed.
>
> A symmetric declaration like this:
>
> Matrix& operator *=(const disjoint Matrix& m);
>
> would have the same effect.
Right. Note that if you have
template <class T>
Matrix& operator*=(const T& m)
{
if (this == &m)
return *this;
/* the rest of it */
}
this now has the curious property that if called with a
reference-to-distinct, the compiler knows that
the self-assignment check can be axed.
But, well. Putting it into the type system means that template
specializations for Foo* and disjoint Foo* are separate.
Furthermore, allowing it as a member function cvd-qualifier means that
library wrappers that wrap member functions
need to (again) bifurcate their set of known signatures they can wrap.
> 2) If I have a Foo::operator=(disjoint Foo&&) disjoint;, that's presumably a move assignment operator, so it's considered a special member function. Curiously enough, that seems to be a flavor of a move assignment operator that knows that self-move is not possible. Even more curiously, that doesn't mean that the disjointness necessarily leads into a compiler optimizing away self-move checks, because since this is a separate function, it could just be written not to do such checks.
>
> I see your point, and I agree that this is an area full of redundant coding and tediousness. What would be nice is a way to have some kind of qualifier template parameters so you could write the code once and let the compiler generate different versions of the function for different qualifiers on the argument or on this:
>
> template <qualifier X, qualifier Y> operator =(X Foo&&) Y;
That doesn't change the template specialization duplication and member
function wrapper code bifurcation mentioned
above, though.
> 6) Consider
> disjoint Foo a;
> disjoint Foo* b = &a; // #1
> disjoint Foo* c = nullptr;
> c = b; // #2
> Is this well-formed?
>
> Yes.
>
> > How is a pointer disjoint if it can be assigned from another disjoint pointer?
>
> Disjoint is not a property of the pointer but of the storage pointed to. It's up to the programmer not to misuse the tool.
Right, my terminology mistake. I find it interesting that you first
say that it's up to the programmer not to misuse
the tool, and later say it's a safety-enforcing tool. I get the drift,
it increases safety but doesn't provide complete safety.
However.. see below.
> 7) All this stuff seems very complex compared to being able to mark function parameters as disjoint from each other.
> But that leads to the safety and stability problems addressed in the proposal, and it doesn't allow for overloading.
Why.. do I care that it doesn't allow for overloading? I could
entertain (but not necessarily advocate, too unbaked)
exploring an attribute solution where you just annotate variables and
parameters, and a compiler can diagnose
mismatches. That wouldn't be as deep-impact language change, but sure,
it wouldn't allow overloading either.
And as far as safety goes, well.. it's trivially easy to make copies
of a pointer-to-disjoint, and pass multiple copies
around wherever, and later end up calling a function that wants
multiple pointers-to-disjoint that aren't. I could
entertain the thought that pointer-to-disjoint would only convert from
an xvalue pointer-to-disjoint. But I'm not sure
whether that would help either.
There is a previous proposal for restrict-like semantics for C++,
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3988.pdf
I wonder what the people who worked on that think about baking the
disjointness into language semantics instead.
Rephrasing my main concern: the cost/benefit ratio of this looks
awkward. Needing to tell an optimizer that two pointers
are disjoint should be rare. But making it a new cvd-qualifier and
baking it into the type system puts it on everybody's face.
That seems like the tail wagging the dog to me.
Received on 2020-09-23 17:58:55