Calling method on Super calling Self method instead

I’ve distilled this down to the simplest project I can. This is a weird one.

I have a DesktopPopupMenu subclass that has an overridden AddRow method. In a computed property, I call Super.AddRow because I don’t want my overridden version used. Instead, it’s doing Self.AddRow.

All you need to do is run the project, I have a break statement added to show that it’s definitely calling the wrong version of AddRow. In fact, it’s calling Self.AddRow(Item As String) when I have passed a DesktopMenuItem. That’s possibly a clue. And yet calling Super.AddRow from inside the overridden method doesn’t cause recursion.

I feel like this is some sort of casting / Operator_Convert nonsense because I can create a custom class that does the exact same thing technique, just isn’t a popup menu, and the correct methods are called as expected.

Super Bug.xojo_binary_project.zip (5.2 KB)

My working theory is that DesktopPopupMenu.AddRow(Item As DesktopMenuItem) is implemented like this:

Self.AddRow(Item.Text)
Self.RowTagAt(Self.LastAddedRowIndex) = Item.Tag

So Super.AddRow ends up calling my implementation of AddRow(Item As String) anyway, and the framework parts of the stack trace are hidden from me.

I’ve never had super.Function inside a subclass work in API 2.0 IDEs. I always have to cast it like

DesktopPopupMenu(self).AddRow(Item.Text)

Edit: Hrrm, maybe I’m thinking of properties.


Update: This post exists for posterity but is facutally incorrect.

This does not compile:

dim s as string
dim nm as DesktopMenuItem

nm=New DesktopMenuItem(DesktopMenuItem.TextSeparator)

s=nm

which suggests that Operator_Convert isn’t involved.

Really? It works all the time. The language wouldn’t really work without it. Try this project. Just run it, the break in ChildClass will hit, and when you continue, the break in ParentClass will hit.

Super Test.xojo_binary_project.zip (3.8 KB)

The only exception to this is properties. Those you can’t reach using Super. I think it’s dumb, but that’s the way it is. In which case your trick is the only way.

I think this is what I was getting confused about. I left my post up for posterity, but I was confused.

Yep, I’m right. Calling AddRow with a DesktopMenuItem just calls AddRow with a string and RowTagAt. I just added an override for RowTagAt to confirm, and sure enough it gets called immediately after AddRow.

1 Like

Since you’re using DesktopPopupMenu with MenuItem entries, you might be interested in signing onto this ticket I created for clarity:
#79184 - DesktopPopupMenu.AddRow accepts a MenuItem, but does not use any of the features besides Text and Tag

1 Like

Sure, though I don’t expect it’ll go anywhere. PopupMenu is just not featured enough for that. You can’t even use separators on Windows.

I came the same conclusion, and I can even prove it. Drop this into your AddRow(string) code:

try
    raise new NilObjectException
catch e
    dim s() as StackFrame

    s=e.StackFrames

    break
end

At the break, you can inspect s and see that indeed the call chain goes from DesktopMenuItem.Addrow back down to TestMenu.AddRow. The Exception.StackFrames data is more comprehensive than what you see in the debugger - it’s the equivalent of crashing the app on the Mac and getting the Wall of Text stack trace from the kernel.

Ha! And you can cause a stack overflow like this:

AddRow(string)

    Super.AddRow(new DesktopMenuItem(item))

End