Extending a Method on a Base Class

By Deane Barker on May 22, 2008

Here’s something I’d like to see in any object-oriented programming language. This might be a crappy idea, which is why I’m posting it here before I call Steve Balmer up and ask him to implement it.

Say I have a base class Foo, which is extended by Bar (below notation is in C#, because that’s what I was using when I wanted this):

public class Foo
{
}

public class Bar : Foo
{
}

Foo (the base class) has a method called DoSomething. I also write a DoSomething method in Bar (the child class), thus overriding the method in Foo.

public class Foo
{
  public void DoSomething()
  {
     //This method won't run from Bar...
  }
}

public class Bar : Foo
{
  public void DoSomething()
  {
    //...because this method this hides Foo's method.
  }
}

At this point, the Foo version of DoSomething is hidden — Bar has overridden it. In most cases, this is what I want. But sometimes it’s not.

Sometimes (today, for example), I really wanted the Bar version of DoSomething to add to the Foo version. So I wanted Bar to run the base implementation of the method (the one on Foo), then run its own implementation.

Something like this:

public class Foo
{
  public void DoSomething()
  {
    //When DoSomething is called from Bar, this code will run first...
  }
}

public class Bar : Foo
{
  public void DoSomething()
  {
    //...then this code will run.
  }
}

Now, I know what you’re saying. Do this in Bar.

public void DoSomething()
{
  base.DoSomething();
  [more code here]
}

But, this requires explicit code in Bar, and it’s optional — the guy writing Bar could just choose not to do it. What if I wanted to force this from Foo?

What I want to do is write a method in Foo and somehow designate that to say:

You can add to this method all you want in child classes, but this code right here is still going to run first no matter what you do.

This is both a convenience thing — I don’t have to remember to call the base method from Bar — but I can also envision situations where it’s a security issue. There could be times when the code in Foo has to run for security reasons or to set up some situation or structure for Bar’s method implementation to run correctly.

Does what I want exist in any language you know of? Is it a stupid idea? Why?

Gadgetopia

Comments

  1. Although there’s a bit more code, you can explicitly achieve what you need with something like this:

    class Foo
    {
      protected void DoThisFirst()
      {
        Console.Out.WriteLine("Always do this first.");
      }
    
      protected virtual void DoThisNext()
      {
        Console.Out.WriteLine("Default next bit to do.");
      }
    
      public void DoSomething()
      {
        DoThisFirst();
        DoThisNext();
      }
    }
    
    class Bar : Foo
    {
      protected override void DoThisNext()
      {
         Console.Out.WriteLine("Bar version of doing the next bit.");
      }
    }
    

    The DoSomething method specifies what methods are to be called and in what order. Sub-classes can override the called methods as required.

  2. That doesn’t actually force it though. There’s nothing stopping

    class Bar : Foo
    {
      public new void DoSomething()
      {
        System.Console.WriteLine("Oops, I just bypassed DoThisFirst().");
      }
    }
    

    By simply adding the new keyword I was able to completely bypass DoThisFirst(). If the subclass author only overrides DoThisNext(), it works as desired, but it’s still possible for them to completely ignore that wish and skip that method altogether.

  3. well this will accomplish what you want, if you did not want the FooSomething in the chain you could remove it. This is pretty much the only way that I can think of to simulate what you want.

    class Program
    {
        public class Foo
        {
            public Foo()
            {
                DoEverything += new DoSomething(FooSomething);
            }
    
            public delegate void DoSomething();
            public event DoSomething DoEverything;
    
            public void FooSomething()
            {
                Console.WriteLine("FooSomething");
            }
    
            public void DoIt()
            {
                DoEverything();
            }
        }
    
        public class Bar : Foo
        {
            public Bar()
            {
                DoEverything += new Foo.DoSomething(BarSomething);
            }
            public void BarSomething()
            {
                Console.WriteLine("BarSomething");
            }
        }
        static void Main(string[] args)
        {
            Bar b = new Bar();
            b.DoIt();
        }
    }
    

    }

  4. It’s possible to do in C#, and it’s not a stupid thing to do at all.

    For instance, I’ve created an abstract Task class that runs tasks via a BackgroundWorker. The BackgroundWorker itself is a static member of the abstract base class, so the only thing that can call its methods is code in the base class. The base class exposes a virtual method (called Method) that subclasses can override. But Method is protected, so programs that create an instance of a Task subclass can only call its Execute method, which does the whole elaborate dance of calling RunWorkerAsync and handling exceptions that were thrown by the background thread.

    The person implementing the subclass doesn’t have to worry about any of that. He just has to write Method. And then it just works, except for all of the other ways that you can screw yourself up with multithreaded code.

    Here’s a simple prototype:

    public abstract class Foo
    {
       public void Bar()
       {
          MethodBeforeBaz();
          Baz()
          MethodAfterBaz()
       }
    
       protected virtual void Baz();
    
       private void MethodBeforeBaz() { ... }
       private void MethodAfterBaz() { ... }
    }
    

    When you implement a subclass of Foo, the only method you can override is Baz. Since Bar is the class’s only public method, nothing that creates an instance of Foo can call anything but Bar. Since Baz is protected, the only thing that can call Baz is an instance of Foo.

Comments are closed. If you have something you really want to say, email editors@gadgetopia.com and we‘ll get it added for you.