Operator_Compare bug or my error?

Create a module (I named my Extensions) with this method (global scope):

Function Operator_Compare(this As Point, other As Point) As Integer
  If other = Nil Then Return -1

  If this.X = other.X And this.Y = other.Y Then
    Return 0
  Else
    Return -1
  End If
End Function

Then put this in the Opening() event of the window:

Var p1 As Point = New Point(1, 2)
Var p2 As Point = New Point(1, 2)

If p1 = p2 Then
  Break
Else
  Break
End If

If you put a break point in the Operator_Compare() method, it never gets called. Am I doing something fundamentally wrong here or can I not extend the built-in type?

Operator_XX methods need to be added to the class itself. (See docs)

In this case, you would need to use it like this, which is just a regular method call.

Var p1 As Point = New Point(1, 2)
Var p2 As Point = New Point(1, 2)

If Operator_Compare(p1, p2) = 0 Then
  Break
Else
  Break
End If

Ah that’s a shame.

I was hoping to use Points as the keys in a Dictionary. I figured if I could override the comparison operator I could then use Dictionary.HasKey() to check for the presence of a particular Point (different instance, same properties).

You could make a Point subclass and add your own operator methods in the subclasses.

Var p1 As Point = New myPoint(1, 2)
Var p2 As Point = New myPoint(1, 2)

If p1 = p2 Then //Operator_Compare would be called here
  Break
Else
  Break
End If

EDIT:

I believe Dictionary.HasKey uses a hash table. Each class instance would have its own different hash. What you are trying to achieve would not work as expected.

1 Like

You can use extends with the Operator_Compare method inside a module:

Public Function Operator_Compare(extends this As Point, other As Point) As Integer
  If other = Nil Then Return -1
  
  If this.X = other.X And this.Y = other.Y Then
    Return 0
  Else
    Return -1
  End If
End Function

Edit: Nevermind. I could’ve sworn this used to work, but it doesn’t appear to now that I’m testing it.

I’m fairly sure I’ve used something like this in projects before:

Public Function Operator_Subtract(extends this as Point, other as Point) As Point
  if other = nil then Return nil
  
  return new Point( this.x - other.x, this.y - other.y )
End Function

But it fails now, so I don’t know. Sorry for the noise.

Case

1 Like

I thought it worked too @Anthony_G_Cyphers - I guess we’re both wrong! I added a thumbs up to that case however, for what it’s worth.

Yeah, a bit more experimenting and you’re correct. Other languages (like Java, etc) offer effectively a Hashable interface that lets you implement this sort of behaviour but I don’t think it’s possible with Xojo.

Maybe worth a feature request? There is precedence after all with the Iterable interface I guess.

1 Like

I was about to suggest using a Structure as a key since the hashes of those seem to be based on value, but it turns out there is a bug there. I’m going to file a report now.

2 Likes

The Issue is here, FWIW:

https://tracker.xojo.com/xojoinc/xojo/-/issues/75063

If they fix this, it will be a nice option in cases like this.

1 Like

I wanted to do this for a module to generate placeholder images. I ended up just making a string version and using that as the key. Worked well enough.

var sSize as String = sz.Width + "x" + sz.Height
if dictCache.HasKey(sSize) then
 // Get the cached placeholder
  return dictCache.Value(sSize)

end

Since images were going to be whole numbers like that, it was easy and efficient.

1 Like

I believe the reason this doesn’t work is that the compiler already has a function to satisfy the equals operator: it checks to see if the two objects are the same object. Operator_Compare can only be used to add comparison functionality, not override it.

Best I can suggest is to add a function to your class:

Function ValuesEqual(extends pA as Point, pB as Point) as Boolean

…used thusly:

If pointA.ValuesEqual(pointB) then...

Operator_Compare works for = as well.

1 Like

Are you sure?

https://tracker.xojo.com/xojoinc/xojo/-/issues/3316

That has nothing to do with my statement. If you implement Operator_Compare on a class like it’s intended to be, checking for equality can be determined. You’re just incorrectly assuming that the equality operator would be used for the hashing mechanism used for dictionary keys.

Making a class and defining the Operator_Compare method does allow you to do something like this in code:

Dim c1 as New MyClass
Dim c2 as New MyClass

If c1 = c2 then

End if

Operator_Compare is there so you can do custom non-object-based comparisons, so if you had two objects with and underlying pointer for instance, you could return 0 if the two pointers were the same even if the objects themselves are different.

1 Like

Also be careful with If other = Nil Then Return -1 because the = may trigger another Operator_Compare. It would be safer to use If other Is Nil Then Return -1 in such a case.

7 Likes

I wonder, should using Operator_Compare as a method name, when not either in a class definition or Module using Extends, be considered a compile error?

1 Like

Based on a hunch, I threw together a quick sample project and verified that you can’t use Operator_Compare with Extends, at least in 2020r1.2, and probably the other Operator_* methods as well. This was confirmed by Norman Palardy 9 years ago in a random comment in this forum and was itching in my memory all day.

There’s no obvious reason that I can see why it couldn’t work if Xojo wanted it to, but perhaps there’s a deeper reasoning at play here.

Edit: and of course this was documented in the issue link I posted earlier, I must not have read it carefully. I gotta stop spending so many hours at work…

Edit II: The issue was opened 15 years ago (!) and last updated 9 years ago. If your’e not going to change the functionality, could we at least get a compiler warning…?

1 Like

Indeed, it turns out https://tracker.xojo.com/xojoinc/xojo/-/issues/3316 was the bug I submitted 15 years ago, but apparently I forgot about it. :joy:

2 Likes