Thread overview
Prevent self-comparison without taking the address
Jul 25
Dom DiSc
Jul 25
IchorDev
Jul 25
IchorDev
Jul 25
Dennis
Jul 25
IchorDev
Jul 25
Dom DiSc
Jul 25
IchorDev
Jul 26
Dom DiSc
July 25

I have copied some source from C++, where the following pattern is common (operator== already renamed):

@safe:
struct S
{
   bool opEquals(const ref S x) const
   {
      if(&x==&this) return true;
      ...
   }
}

Can I replace this pattern with (x is this) or are there some special cases where this doen't work?

July 25

On Thursday, 25 July 2024 at 10:50:04 UTC, Dom DiSc wrote:

>

Can I replace this pattern with (x is this) or are there some special cases where this doen't work?

When a parameter is ref it is treated as a value type (i.e. it has value semantics), even though it is a reference; therefore an identity expression of x is this will check whether the bits in x and this are identical: https://dlang.org/spec/expression.html#identity_expressions
Using the reference operator (&) on something that is ref returns its pointer form, which is what you want to compare.

TL;DR: No, is will compare the struct data not the pointers.

July 25

On Thursday, 25 July 2024 at 10:50:04 UTC, Dom DiSc wrote:

>
@safe:
struct S{

Also just so you know, placing @safe: there will not affect the contents of S. It has to be inside the struct declaration to affect its contents.

July 25

On Thursday, 25 July 2024 at 11:46:29 UTC, IchorDev wrote:

>

Also just so you know, placing @safe: there will not affect the contents of S. It has to be inside the struct declaration to affect its contents.

That's true for the other function attributes, but @safe: actually does penetrate scopes

July 25

On Thursday, 25 July 2024 at 13:01:53 UTC, Dennis wrote:

>

That's true for the other function attributes, but @safe: actually does penetrate scopes

The spec doesn’t mention this at all! Is this the case for any other AttributeSpecifier declarations?

July 25

On Thursday, 25 July 2024 at 13:20:59 UTC, IchorDev wrote:

>

On Thursday, 25 July 2024 at 13:01:53 UTC, Dennis wrote:

>

That's true for the other function attributes, but @safe: actually does penetrate scopes

The spec doesn’t mention this at all! Is this the case for any other AttributeSpecifier declarations?

As he said: no. It's only true for @safe:

But that doesn't answer my question.
You said it is not the same. But then: is there another way to translate the C++ pattern in a @safe way?

July 25

On Thursday, 25 July 2024 at 14:05:50 UTC, Dom DiSc wrote:

>

As he said: no. It's only true for @safe:

No they did not, they specifically said that my assertion holds true for all other function attributes. This does not tell me anything about other attributes like align, deprecated, @__future, linkage attributes, visibility attributes, mutability attributes, shared storage attributes, @system variables, or UDAs.

>

But that doesn't answer my question.

Your question was ‘Can I replace this pattern with (x is this)’. The answer is no.

>

You said it is not the same. But then: is there another way to translate the C++ pattern in a @safe way?

This is the first time you have mentioned this intention with words. I’m not a mind reader.
I think your function most likely has a safe interface, so it can be marked as @trusted as-per the spec. Let’s go through the checklist:

  • undefined behaviour? Nothing undefined about comparing two numbers.
  • creates unsafe values accessible by safe code? No it only returns a Boolean.
  • unsafe aliasing accessible by safe code? No aliasing whatsoever.
July 25

On Thursday, 25 July 2024 at 15:06:35 UTC, IchorDev wrote:

>

I think your function most likely has a safe interface, so it can be marked as @trusted as-per the spec.

Just to mention that with -dip1000, taking the address of variables is allowed, so the function would be @safe.

July 25
On Thursday, July 25, 2024 4:50:04 AM MDT Dom DiSc via Digitalmars-d-learn wrote:
> I have copied some source from C++, where the following pattern is common (operator== already renamed):
>
> ```d
> @safe:
> struct S
> {
>     bool opEquals(const ref S x) const
>     {
>        if(&x==&this) return true;
>        ...
>     }
> }
> ```
>
> Can I replace this pattern with ```(x is this)``` or are there some special cases where this doen't work?

If you want to do that, that's basically what you would need to do. However, I've never seen anyone do that with structs in D. They're usually put on the stack and passed around by value. They are of course sometimes passed by reference, but that's usually going to be to a variable on the stack, making comparing addresses kind of pointless, since you'd usually need to be doing something like x == x to end up comparing the same object against itself.

Pretty much the only time that something like this might make sense is when you're dealing with pointers to structs, which of course is done sometimes, but it's much less common than it would be in C++, since D separates classes and structs. And classes already do that check with ==, since it's lowered to a free function, opEquals, before calling the class' opEquals, and it does stuff like compare the address of the class reference and compare against null.

Either way, the fact that the this member for structs is a reference rather than a pointer means that if you want to compare addresses, you'll need to take the addresses - which won't be @safe without DIP 1000, because taking the address of a local variable is not @safe without the tracking that DIP 1000 adds via scope (since without the extra checks, you could easily take that address and pass it around, letting it escape the lifetime of the reference).

- Jonathan M Davis



July 26

On Thursday, 25 July 2024 at 15:40:29 UTC, Nick Treleaven wrote:

>

On Thursday, 25 July 2024 at 15:06:35 UTC, IchorDev wrote:

>

I think your function most likely has a safe interface, so it can be marked as @trusted as-per the spec.

Just to mention that with -dip1000, taking the address of variables is allowed, so the function would be @safe.

Thanks for all the good answers.
So the solution for me is -dip1000.

Marking something @trusted that the compiler should be able to check to be @safe is not so good, as it increases the review effort significantly and unneccessarily.