Properties being non-virtual

In the past I used to shadow properties extensively. Thanks to comments of Kem and Norman in a post started by Tim Jones called Shadowing Properties … Good or Bad? a few days ago I finally “got it” - at least I think I do so…

This is how I would summarize it (virtual methods vs. non-virtual properties):

  • When you call a method, the runtime type of the object is used to find out which implementation of the method to use.
  • When you call a property, the compile-time type of the object is used to find out which implementation of the property to use.

Translated into code it looks like that:

[code]// Class2 is a subclass of Class1
Dim obj11 As Class1 = New Class1()
Dim obj22 As Class2 = New Class2()
Dim obj12 As Class1 = New Class2()

obj11.Method() // Variable: Class1, Instance: Class1 -> Class1.Method
obj11.Prop = 0 // Variable: Class1, Instance: Class1 -> Class1.Prop

obj22. Method() // Variable: Class2, Instance: Class2 -> Class2.Method
obj22.Prop = 0 // Variable: Class2, Instance: Class2 -> Class2.Prop

obj12. Method() // Variable: Class1, Instance: Class2 -> Class2.Method -> virtual, Method of Class2 is invoked
obj12.Prop = 0 // Variable: Class1, Instance: Class2 -> Class1.Prop -> non-virtual, Prop of Class1 is invoked[/code]

I never had any problems with my shadowed properties, because I never used these classes in a way that the subtle bugs Kem and Norman were talking about could arise. But here is an example I can think of - now that I “got it”:

[code]Class MyCanvas
Property Enabled As Boolean // Shadows Enabled of the built-in super class Canvas

Sub Close() // Overrides Close of the built-in super class Canvas

End Class

// Now somewhere in a method of the window containing an instances of Canvas and MyCanvas
For i As Integer = 0 To ControlCount - 1
If Control(i) IsA Canvas Then
Dim cnv As Canvas = Canvas(Control(i))
cnv.Enabled = True // Enabled of Canvas will be invoked even if cnv is of type MyCanvas -> DANGEROUS
cnv.Close() // This will work and call Close of Canvas or MyCanvas depending on the type of cnv
End
Next[/code]

I started to replace all shadowed properties in my two large projects with a method pair for setting (with the help of the keyword “Assigns”) and getting the specific value, but I’m stuck when it comes to classes where I don’t have access to the source code: Windows, ContainerControls, and all built-in controls based on RectControl, but also classes from bought plugins. I didn’t find a way to satisfyingly solve this.

One way would be to introduce methods with a different name as the property’s name. For example like that:

[code]// CanvasExtensionsModule
Sub Enabled_OnlyUseThatOne(Extends cnv As Canvas, value As Boolean)
cnv.Enabled = value
End
Function Enabled_OnlyUseThatOne(Extends cnv As Canvas) As Boolean
Return cnv.Enabled
End

// MyCanvas
Sub Enabled_OnlyUseThatOne(value As Boolean)
Super.Enabled = value
// do my other stuff I need to do when the value of Enabled changes
End
Function Enabled_OnlyUseThatOne() As Boolean
Return Super.Enabled
End
[/code]
But now there will be two Enabled methods side by side for both Canvas and MyCanvas - and I can’t prevent that the wrong one will be chosen (Enabled in that case).

So how could a proper solution look like when:

  • the source code of a class A is not available
  • there is a need to add some code to the setter or getter of a property in a subclass of class A

The summary seems correct - which means that IF you use shadowing of any kind - you’re stuck because the declared type, not the runtime type, is whats important

This is true with Xojo framework code, plugin code etc.

The upshot is IF you really really think you need to reuse THAT specific property with that specific name & type then the ONLY way to do it is to make sure your code DOESN’T use the wrong declared type - otherwise you have the problems noted.

Or you use a lot of IsA checks to make sure you can do something like

if thing isA MyWindow then dim myWindowThing as myWindow = MyWindow(thing) // now access whatever shadowed property else if thing isA Window then dim myWindow as Window = Window(thing) // access the base class property end if

Or you just pick a different name

This is so ingrained in the language design that I doubt it’s likely to change - it could silently break a lot of code if it was changed to make properties virtual

Of course, I can understand that.

It’s just difficult to subclass built-in controls and capture changes on Enabled, Visible, etc. For some important properties like ListIndex on the listbox there is a Change event which fires, so you know that ListIndex has changed, but a lot of properties have no related change event.

Probably a heretical question: since properties with an argument like ColumnSortDirection(index As Integer) are in reality methods, why not implement all properties of the built-in controls as pairs of setter and getter methods? What is the actual advantage for developers that properties are indeed implemented as properties, and not as methods? Besides the disadvantage that they can not be overridden.

Oh, dreaming of the upcoming framework…

Speed?

Computed properties are methods (they even showed up until recently in introspection as methods, as Enabled.Get and Enabled.Set for example).

I’m not sure I understand your point. The advantage of implementing properties as actual properties (non-virtual) as opposed to methods (virtual) is that method calls incur overhead that straight property access does not.

I understood you answer wrongly, I thought you were referring to plain properties - sorry for that.

Yes, the address offset of the getter and the setter functions can be determined at compile time. But is that so much faster? Compared to loosing the ability to subclass a control properly (when you want to intercept a built-in computed property)? And, as an example - isn’t Cocoa based entirely on runtime evaluation method addresses? Blazingly fast…

I would like to be able to provide a clean API, but right now this is not possible. When using a subclassed control and you set or get a property value, you must know something about the subclass’s internals. Maybe the property is shadowed in the subclass, maybe it’s the one of the built-in control, etc. And I don’t like that, I like to narrow the possibilities of making mistakes.

Most OOP languages either allow overriding properties (VB .NET), setting them as virtual (C#), or you fake properties by implementing a setter/getter function pair which are virtual (C++, Java, Objective C - even with @property).

It certainly could be done that way and, as if I recall correctly, was done that way a long time ago.

From a conceptual view, properties are state and not actions, so having them actually be properties makes sense. It also helps with documentation, compiler error messages for things like assigning to a read-only property, and showing up in the debugger (as an aside, computed property getters really should be idempotent).

Not really. Making a computed property virtual would require an two extra adds, two extra dereferences, and an indirect call with the real cost being cache misses / branch prediction fails and not the actual instruction count. It’d also impair compile-time optimizations, but a sufficiently smart compiler can do devirtualization in most cases to eliminate all of that overhead.

I wouldn’t call it blazingly fast and Apple’s gone through some amazing hoops to get to the level it is now. However, for most things it’s tasked with doing, which at the very least is the UI layer of a program, it’s fine and worth the cost of the extra runtime flexibility.

I think the better question is “why do you want to do this” and “is there a better way of doing it”. Ever language feature or change starts out with -100 points and has to have a compelling reason to be done.