Why is `opequals` for objects not `@safe` by default?
Liam McGillivray
yoshi.pit.link.mario at gmail.com
Sun Apr 7 21:05:14 UTC 2024
On Sunday, 7 April 2024 at 09:59:56 UTC, Jonathan M Davis wrote:
> No, we really don't want to force @safe on opEquals, because
> that means that you can't write one that's @system, meaning
> that you're potentially forced to use @trusted on code that
> really shouldn't be treated as @safe.
Well, I already ended up putting `@trusted` in a function I
didn't want to put it in because `opEquals` was `@system`. Point
taken though.
> ```
> class C
> {
> bool opEquals(C rhs) @safe
> {
> ...
> }
>
> override bool opEquals(Object rhs) @safe
> {
> ...
> }
> }
> ```
> then the first overload will be called when comparing class
> references of type C - or class references derived from C,
> whereas if you're comparing class references of type Object (or
> class references which aren't C or derived from C), then
> they'll be compared as Object, and the base class opEquals will
> be called, resulting in your second overload being called
> thanks to polymorphism, but because the base class version is
> @system, == will still be treated as @system in that case. E.G.
Oh! Is this how the `opEquals` function used can be made to
depend on the reference type, rather than the type of the object
contained in the reference?
>> Anyway, I discovered that `==` can be replaced with `is`, and
>> it seems to do the same thing while working within a `@safe`
>> function.
>
> The is operator and == are _not_ the same. When you use is on
> class references, it's true if and only if the two references
> point to the same object. It's basically doing a pointer
> comparison. In contrast, == calls the free function, opEquals,
> which will call opEquals on the class references to compare
> them if they're not null and they're not pointing to the same
> object.
Right. I was just saying that `is` will in most cases give the
same results as the default `opEquals` function. The existence of
`is` means I no longer think `opEquals` should be `@safe` by
default. The only place where they would differ is when the first
reference is null, right?
Ultimately, not knowing to use `is` is what lead me to making
this topic.
Actually, I just looked in [the base object
definition](https://github.com/dlang/dmd/blob/master/druntime/src/object.d), and I found this:
```
bool opEquals(Object o)
{
return this is o;
}
```
It looks like it really would be the same whenever the first
reference is a valid object. I figure it would segfault if the
first reference is null, while `is` would simply return `false`.
> You already need to do an override to get opEquals unless you
> want it to just compare the references, which is borderline
> useless. All that opEquals on Object does is compare the
> addresses of the references with the is operator, and that's
> almost never what you want when doing an equality check.
Well, it's exactly what I wanted, but I'm new to the language,
and hadn't yet been taught to use `is` in such cases. For the
function I was writing, see `Weapon.getOptions` or look for `if
(user.currentWeapon == this)` in [this
module](https://github.com/LiamM32/Open_Emblem/blob/master/source/item.d).
Now knowing about the proper uses of `==` and `is`, I think the
only worthy idea I have for a new addition to the language is a
new function in `std.algorithm.searching`; a `@safe bool`
function called `contains`. It would return whether the first
argument (an array of the second argument's type) contains the
second argument. It would be equivalent to `canFind` for some
argument types, but for objects it would do an `is` comparison.
Perhaps I can try to implement this myself. Given my
inexperience, chances are someone else would make some edits to
it before getting merged into Phobos.
More information about the Digitalmars-d
mailing list