Tuesday, 3 April 2007

Shadowing and Overriding in Java and Python Inheritance.

This morning I was trying to do something in Java which would tidy up the code in some custom JSP tags I was writing. The idea was to have an abstract superclass for the tags which declared a method "getLog()". This method was to return the LOG object defined in the concrete subclass (I wanted to do some logging to the subclasses 'personal' log from a method within the superclass).

Something was nagging at me that this wasn't going to work, as I recalled that there was something different about overriding methods and variables in subclasses. I did a bit of research, and in fact you can't override variables, only methods. Variables are merely "shadowed".

What this means in practice is that subclasses may call superclass variables as if they were their own, unless they have shadowed them with their own copy of the variable (in which case you have to do "super.variable" to get the superclass version).

In Python on the other hand, you can override superclass variables in subclasses. In my opinion this behaviour is more intuitive and consistent than the Java behaviour. Here are some examples illustrating the difference between the languages:

Java example

// In file A.java
public class A {
  String x = "In class A";

String getX(){ return x; }

public static void main(String[] args){ B b = new B(); System.out.println(b.getX()); } }

class B extends A { String x = "In class B"; }

Compiling and running this example will print "In class A" to the console.

Python example

# In A.py
class A(object):
  def __init__(self):
      self.x = "In class A"
  def getX(self):
      return self.x

class B(A): def __init__(self): self.x = "In class B"

b = B() print b.getX()

Running this example will print "In class B".

It's not a huge deal, more of an irritation. If I want to do the sort of dependency inversion that I wanted, then I will just have to make all subclasses override a getLog() method in the superclass rather than using the LOG variable.

No comments: