www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Prevent self-comparison without taking the address

reply Dom DiSc <dominikus scherkl.de> writes:
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?
Jul 25
next sibling parent IchorDev <zxinsworld gmail.com> writes:
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.
Jul 25
prev sibling next sibling parent reply IchorDev <zxinsworld gmail.com> writes:
On Thursday, 25 July 2024 at 10:50:04 UTC, Dom DiSc wrote:
 ```d
  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.
Jul 25
parent reply Dennis <dkorpel gmail.com> writes:
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
Jul 25
parent reply IchorDev <zxinsworld gmail.com> writes:
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?
Jul 25
parent reply Dom DiSc <dominikus scherkl.de> writes:
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?
Jul 25
parent reply IchorDev <zxinsworld gmail.com> writes:
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](https://dlang.org/spec/attribute.html#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](https://dlang.org/spec/function.html#safe-interfaces). 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.
Jul 25
parent reply Nick Treleaven <nick geany.org> writes:
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](https://dlang.org/spec/function.html#safe-interfaces).
Just to mention that with -dip1000, taking the address of variables is allowed, so the function would be safe.
Jul 25
parent Dom DiSc <dominikus scherkl.de> writes:
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](https://dlang.org/spec/function.html#safe-interfaces).
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.
Jul 26
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
Jul 25