Skip to content

Shadowing: You can’t always get what you want (or expect)

Shadowing is when a subclass defines a constant, property or enumeration (almost anything that is not an event or a method) that has the same name as a constant, property or enumeration (but not an event or a method) in the superclass. Generally the best rule is avoid using the same names for constants, properties and enumerations that the superclass has already used.

For code in the subclass things will work as you expect since scope resolution will figwill ure out it should use the one defined in the subclass. But, for code outside the subclass things get more difficult because you don’t always get what you expect.

Suppose you have a class like:

Class Foo
   const kDelta = 6
end class
Class Bar inherits Foo
   const kDelta = 66
end class

And somewhere else in you app you have code like:

dim c as Foo
c = new Bar
dim i as integer = c.delta

What would YOU expect the value of i to be?

Many would answer that it should be 66 since the Bar class Delta says 66. Many would be unpleasantly surprised to find that it is not. Constants, properties and many other items like enumerations, cannot be overridden like methods can because they are not virtual. Doing this is known as shadowing. This means that what is important is not the type of the instance you create using NEW but the type that is DECLARED – in the code above this is the type on the line dim C as Foo.

If you change that to say DIM C AS BAR you WILL get the result you expect, but doing that everywhere causes problems in your code becuase you can’t have polymorphic behavior.

So how to deal with this in your own code?

Don’t create code where you need shadowing to work. Shadowing will not always get you want you want or expect. If you expect properties, constants, etc. to be virtual, set your code up to make it so they are virtual using methods. A really nice aspect of Xojo is that code can’t tell if you’re accessing a property or constant or method.

Here’s what I’d suggest- it’s more work, but it’s also far safer at runtime and your code will work as you expect:

Interface Component

  function Delta() as Integer
  end function

... I have no idea what else you'd want ...
end interface

Class Foo implements Component
     private sub Constructor()
     end sub

     function Delta() as Integer
       // return whatever the "generic delta" is
       return kGenericDelta
     end function

     private const kGenericDelta = 6
end class

Class Bar inherits Foo

     function Delta() as Integer
       return kMyDelta
     end function

     private const kMyDelta = 66
end class

With this code, inheritance works as expected without the issues that shadowing brings to the table. Each subclass is a component so you can treat them all the same but they can all specialize in whatever way you need becuase they are all subclasses and using any properties of them gives you the properties of the instance not the declared type.

Still have questions about Shadowing? Ask them here or on the Xojo Forums!