Method overriding/shadowing question

Solarion

Honorary Master
Joined
Nov 14, 2012
Messages
28,051
Reaction score
17,804
I'm looking at the following, specifically the JewelThief.ReturnContents (safe, owner) method. I was expecting the jewelThief's ReturnContents method to shadow the LockSmith's ReturnContents method because it has the same name, however it is not. I specifically have to override and virtual on JewelThief and Locksmith methods respectively.

For example, I created a PrintDate() test method in both LockSmith and JewelThief and yes, that method shadowed the LockSmith's PrintDate method. Here I did not have to specify override and virtual.

What is the difference? Why does it work for one and not the other aka why does a child method hide a base class method sometimes but then at other times it does not?

PHP:
    class Jewels
    {
        public string Sparkle()
        {
            return "Sparkle, sparkle!";
        }
    }

PHP:
    class Safe
    {
        private Jewels contents = new Jewels();
        private string safeCombination = "12345";
        public Jewels Open(string combination)
        {
            if (combination == safeCombination)
                return contents;
            else
                return null;
        }
        public void PickLock(Locksmith lockpicker)
        {
            lockpicker.WriteDownCombination(safeCombination);
        }
    }

PHP:
    class Owner
    {
      
        private Jewels returnedContents;
        public void ReceiveContents(Jewels safeContents)
        {
            returnedContents = safeContents;
            Console.WriteLine("Thank you for returning my jewels! " + safeContents.Sparkle());
        }
    }

PHP:
    class Locksmith
    {
        public void OpenSafe(Safe safe, Owner owner)
        {
            safe.PickLock(this);
            Jewels safeContents = safe.Open(writtenDownCombination);
            ReturnContents(safeContents, owner);
        }
        private string writtenDownCombination = null;
        public void WriteDownCombination(string combination)
        {
            writtenDownCombination = combination;
        }

        public void ReturnContents(Jewels safeContents, Owner owner)
        {
            owner.ReceiveContents(safeContents);
        }
    }

PHP:
    class JewelThief : Locksmith
    {
        private Jewels stolenJewels = null;
        public void ReturnContents(Jewels safeContents, Owner owner)
        {
            stolenJewels = safeContents;
            Console.WriteLine("I'm stealing the contents! " + stolenJewels.Sparkle());
        }
    }

PHP:
    class Program
    {
        static void Main(string[] args)
        {
            Owner owner = new Owner();
            Safe safe = new Safe();
            JewelThief jewelThief = new JewelThief();
            jewelThief.OpenSafe(safe, owner);
            Console.ReadKey();
        }
    }
 
Although the following is not the same example, the principle still applies

PHP:
class Thing
    {
        public void greet()
        {
            Console.WriteLine("Hello from Thing");
        }
    }
    
    class AnotherThing: Thing
    {
        public void greet()
        {
            Console.WriteLine("Hello from AnotherThing");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var thing = new Thing();
            thing.greet(); //Hello from Thing
            
            Thing anotherThing = new AnotherThing();
            anotherThing.greet(); //Hello from Thing
            
            var anotherThing2 = new AnotherThing();
            anotherThing2.greet(); //Hello from AnotherThing
            
        }
    }

vs

PHP:
class VirtualThing
    {
        public virtual void greet()
        {
            Console.WriteLine("Hello from Thing");
        }
    }
    
    class AnotherThing: VirtualThing
    {
        public override void greet()
        {
            Console.WriteLine("Hello from AnotherThing");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var thing = new VirtualThing();
            thing.greet(); //Hello from Thing
            
            VirtualThing anotherThing = new AnotherThing();
            anotherThing.greet(); //Hello from AnotherThing
            
            var anotherThing2 = new AnotherThing();
            anotherThing2.greet(); //Hello from AnotherThing
            
        }
    }
 
Last edited:
Last edited:
I'll be blatantly honest here in several years of coding I've not had to upcast any derived classes, either because I have simply just used the derived class or because I've not needed to or because hence the reason for me doing a refresher diploma now...... I have been doing it wrong! :cry:

I'm hoping one of you could please give me a real world example of where type casting is used in this way. I understand what is going but I don't understand why it is needed aka why one would need to upcast a derived class into a base class object.

PHP:
    public class Employee
    {
        public virtual void PrintFullName()
        {
            Console.Write("I am a base class print method");
        }
    }

PHP:
    public class TemporaryEmployee : Employee
    {
        public override void PrintFullName() 
        {
            Console.Write("I am a derived class print method");
        }
    }

PHP:
    class Program
    {
        static void Main(string[] args)
        {
            Employee temp = new TemporaryEmployee();
            temp.PrintFullName();
            Console.ReadKey();
        }
    }

I found this answer from Stackoverflow, however I am unable to find an actual example of what he is talking about here.

I think you might be a bit confused about what the upcast does. The upcast does not disable the functionality of the derived object, nor does it create a new Base object. Rather, it just takes a more limited view of the object you upcasted. Through the base class reference, you can access only those methods declared in Base, but if any of those methods are overridden in the derived class, invoking them through the base reference will still call the derived version.

As for when you'd want to do this, it's uncommon to see people upcast for no particular reason. After all, that limits what you can do to the object. However, as other posters have pointed out, it's common to implicitly upcast when passing an object into a function or returning an object from a function. In those cases, the upcast allows function authors to either take in a parameter with the weakest set of requirements necessary to get the job done, or to return an object from a function that exhibits some set of behaviors without necessarily revealing the full type of the object.

Link
 
I'll be blatantly honest here in several years of coding I've not had to upcast any derived classes, either because I have simply just used the derived class or because I've not needed to or because hence the reason for me doing a refresher diploma now...... I have been doing it wrong! :cry:

I'm hoping one of you could please give me a real world example of where type casting is used in this way. I understand what is going but I don't understand why it is needed aka why one would need to upcast a derived class into a base class object.

Imagine that you had a function that took an Employee as a parameter, and called printFullName on it. Or perhaps, you have a list of Employee's, and want to add both TemporaryEmployee and PermanentEmployees to it.
 
You probably heard the phrase "favor composition over inheritance", which means this style of OOP design should not be the first grab bag; however due to limitations with C# interfaces there are still some scenarios where there's simply no other choice.

Problem is C# has been lagging behind in terms of things like default implementation for interface methods which would all but make this style of coding obsolete, but that's only coming in C# 8 -- for now you either go the typical abstract base class route or use an interface extension method workaround as a temporary filler, or a combination of both! that is until the real thing hopefully arrives more fully fledged in C# 8.

The ultimate benefit btw of what default method implementations on interfaces could offer will depend largely on how they tie it in with generics, generalized existentialis, type / element constraints, etc. In the Swift code it has had a big impact, for example it's possible to use Interface (Swift calls these protocols) default implementation methods to add a a single generic method implementation to a base interface like Sequence and have all the structures that implement this receive a working implementation for free. I.e. Array, Linked List, Dictionary, Set, ... Oh and this doesn't require any type erasure tricks and casting tricks to get it to work.

Biggest first win in a codebase is cutting back on a lot of boilerplate, but in the long run it should open up a whole new way to tackle design. Apple FYI referred to its Swift implementation of this as Protocol Oriented Programming (POP); in the C# sense that should translate to Interface Oriented Programming -- how this will ultimately match up, will require more detail on not only C# 8 objectives, but also the planning to extend this going forward.

Where to after that is obvious; higher kinded polymorphism is a big ticket win, but I'd imagine the C# compiler team is keeping that on the back burner much like Rust and Swift teams are. The only languages that support that level of polymorphism today is Haskell, Purescript and Scala to some degree.
 
Last edited:
I'm curious: what possible benefit is there in adding default implementations to interfaces if an abstract class implementing an interface already does that? I've never seen the benefit of it in Java. To me it looks like more language fluff but maybe I'm missing something.
 
I'm curious: what possible benefit is there in adding default implementations to interfaces if an abstract class implementing an interface already does that? I've never seen the benefit of it in Java. To me it looks like more language fluff but maybe I'm missing something.
Quite the contrary re fluff; limitation with Java's default methods stems from its inherently poor support of parametric polymorphism, existentialis and type constraints. Missing those parts is the Eason why Java's default method implementations are very limited in versatility.

In contrast, we can use both generics and type constraints to target the type that implements a particular interface (in Swift it's called a protocol),

Swift code examples:
PHP:
// Here we constrain the default method implementation for sort to Sequence types
// where the Element type conforms to the Equatable protocol (interface)
// a single sort implementation for all these types
extension Sequence where Element: Equatable {
  func sort(_ predicate: (Element, Element) -> Bool) -> [Element] {
    ....
  }
}

// here we extend the Sequence protocol (interface) that is inherited by all sequence types
// Array, Dictionary, Set, Linked List, ...
// this single default method implementation add the count higher order method to all sequence types.
extension Sequence {
    func count(where predicate: (Element) throws -> Bool) rethrows -> Int {
        var count = 0
        for element in self {
            if try predicate(element) {
                count += 1
            }
        }
        return count
    }
}
These are simple examples, the flexibility of type constraints and element generics allows for far more versatile implementations that achieve a lot with very little amount code; bonus is that we avoid the a lot of boilerplate and/or use of code generators.

The ability to extend the type system in Swift doesn't stop at Interfaces, it extends to almost all aspects of the type system; While C# has extension methods it versatility is equally limited re limited support for parametric polymorphism and type constraints.

Btw in the above code you might have noticed that the sort function example would always return an Array [Element], irrespective of the sequence type involved e.g. Sorting a linkedList would return a sorted array; this limit in the type system is linked with higher kinded polymorphism, which only a language like Haskell has a type system that can currently express this level of polymorphic abstraction together with a single default method implementation.
 
Last edited:
So "default methods" as in methods attached to the type like in Go instead of a method for each instance? Is that the "for Dummies" explanation?
 
So "default methods" as in methods attached to the type like in Go instead of a method for each instance? Is that the "for Dummies" explanation?
It's not attached to a single type as in Go but rather a group of types that are associated by their conformance to an interface (protocol). Whereas Higher Kinded polymorphism takes this to the next extent: Container Generics together with Parameter / Element Generics.

Keep in mind that interfaces aren't limited by the inheritance model I.e. We can have a type that conforms to multiple interfaces I.e. It could get many different default method implementations based solely on its conformances.

The biggest difference it makes to a codebase is cutting back on code; a lot of duplication can be abstracted away with this. Also should explain why Haskell code is far more terse than most other languages because it has the full scale of parametric based generics. What it doesn't support is inheritance because as we know now that provides a very inflexible model for polymorphism.
 
Last edited:
[)roi(];21923291 said:
You probably heard the phrase "favor composition over inheritance", which means this style of OOP design should not be the first grab bag; however due to limitations with C# interfaces there are still some scenarios where there's simply no other choice.

I remember in the distant past with C++ I used to code all these deep inheritance hierarchies. Worked well at the time but it creates dependencies. Very rarely use it now.
 
I remember in the distant past with C++ I used to code all these deep inheritance hierarchies. Worked well at the time but it creates dependencies. Very rarely use it now.
For those that didn't know C++ was on of the only language I know that at a point actively promoted multiple inheritance, but as you confirmed there are concrete reasons why no language has pursued it since then. Plus it's quite apparent that no language specialists are chasing after that inheritance "utopia" anymore; the new languages that still incorporate it, do so arguably purely for historical code compatibility.
 
Last edited:
Imagine that you had a function that took an Employee as a parameter, and called printFullName on it. Or perhaps, you have a list of Employee's, and want to add both TemporaryEmployee and PermanentEmployees to it.

This expands quite on what you are saying. It's in C++ but the idea is there.

In the student example given in the previous notes set, we may end up with many sub-categories of Students, which translates into many derived classes with different information in each. This also means that we will probably have many different types of Grade Reports. It would really be nice to be able to store one big list of Students, and then quickly print out ALL grade reports with a loop, like this:

PHP:
  Student list[30000]; 
  .... 
  for (int i = 0; i < size; i++) 
     list[i].GradeReport();


However, this code is problematic, for two reasons:

The items in the array above are Student objects, and Student is the base class. These base class objects don't have the full range of information about the sub-types. Furthermore, we can't store all these different subtypes (like Grads and Undergrads) physically in an array, because everything in an array must be the same type (and more importantly, the same size)!

The GradeReport function being called is the Student class version of it, since we are calling through objects declared as type Student. This is also not the desired call. If the Student is a Grad, we want to call Grad's version.

If the Student is an Undergrad, we want to call Undergrad's version.
One solution, of course, would be to create a separate array for each subtype. While this is reasonable with very small examples, it is not realistic when there are many subtypes. Real world situations are always larger and more complex than small textbook examples!

http://www.cs.fsu.edu/~jestes/cop3330/notes/inher2.html
 
Last edited:
I am interested in how interfaces would solve that problem, when the object sizes are different?

In C++, I would just keep an array of base class pointers, and allocate the objects on the heap. If performance was a bit of a concern, I would allocate the objects continuously using placement new. If performance was a big concern, I would keep arrays of derives classes so that I didn’t need to do dynamic method resolution.
 
I am interested in how interfaces would solve that problem, when the object sizes are different?

In C++, I would just keep an array of base class pointers, and allocate the objects on the heap. If performance was a bit of a concern, I would allocate the objects continuously using placement new. If performance was a big concern, I would keep arrays of derives classes so that I didn’t need to do dynamic method resolution.
You can think of Interfaces as a set of conformance rules that work a bit like a (void *), for example: what properties (getter/setter) and methods must the conforming objects implement:
PHP:
  interface IStudentReport
  {
    void GradeReport();
  }

  sealed class StudentType1 : IStudentReport
  {
    // ... add all the properties and methods unique to this type 
    int mathScore = 80;


    // Here's our conformance to IStudentReport
    public void GradeReport()
    {
      // the internal computation of this can differ for each conforming type, 
      // only the method signature is important
      Console.WriteLine("StudentType1's math score is {0}", this.mathScore);
    }
  }

  sealed class StudentType2 : IStudentReport
  {
    // ... add all the properties and methods unique to this StudentType2
    // This can be completely different to StudentType2 
    int scienceScore = 45;

    // Here's our conformance to IStudentReport
    public void GradeReport()
    {
      // the internal computation of this can differ for each conforming type, 
      // only the method signature is important
      Console.WriteLine("StudentType2's science score is {0}", this.scienceScore);
    }
  }


// Next we'll create instances of for each of our Student types, for example:
var student1 = new StudentType1();
var student2 = new StudentType2();

// Now let's throw this all into 1 array
// We can't make the array type either StudentType1 or StudentType2 because
// internally they could be very different, but they both conform to the
// IStudentReport interface
IStudentReport[] students = { student1, student2 };

// Finally let's iterate over these dissimilar types that share a common Interface conformance
foreach (IStudentReport student in students) {
   student.GradeReport();
}

// output from this is:
// StudentType1's math score is 80
// StudentType2's science score is 45
Naturally if you needed more similarities between the 2 types you can either extend the current interface or you could make them conform to another interface, and if you need a shared implementation and structure you could also link them to a common abstract base class, plus Interfaces can also tie in generic placeholders variables, for example:

PHP:
  interface Addable<T> {
    T Plus(T value1, T value2);
  }
This is an interface that would just fine for any type that could be added together, int, double, string, ...

Further to this, we can also add extension methods to the Interface, which will be available to all the objects that conform to that interface (which is btw how LINQ is implemented in C#).

In C# 8, goal is to take this a step further by permitting the implementation for GradeReport to be done as part of the Interface i.e. so instead of two separate implementations in the confirming objects, we would end up with just 1 in the interface, and every other new type that conforms to that interface would get that implementation by default. Naturally you can mix this all up; some stuff locally implemented, some stuff in extension methods and some stuff in default implementation.

[table="width: 80%, class: outer_border, align: center"]
[tr]
[td]Interfaces in C# don't support fields; but it does support methods; which means that by requiring getters and setters for these fields we can directly stipulate which inputs we need to perform a particular computation in our default methods.

Benefits of Interfaces over class inheritance is two fold:
  • The interface conformance relationship is loosely coupled in comparison to class inheritance.
  • There is no limit to how many Interfaces an object can conform to, whereas C# limits class inheritance to 1.
[/td]
[/tr]
[/table]

Keep in mind the C# 8 stuff re default implementations is still not ratified, so the ultimate flexibility of that is still unknown. In Java it's not all that flexible, yet it still adds a lot of value; whereas in Swift, Kotlin, Rust and other its much more flexible and cuts out a lot of duplication (or at least has the potential for that).
 
Last edited:
[)roi(];21926185 said:
Interfaces are a solution to this.

Exactly. Where in C++ i would have created class hierarchies for common behaviour, I now use interfaces to define the behavioural contract and then delegate common behaviour out to another class by using composition. This completely decouples code from ‘frameworks’ and makes a codebase far more extensible.
 
Exactly. Where in C++ i would have created class hierarchies for common behaviour, I now use interfaces to define the behavioural contract and then delegate common behaviour out to another class by using composition. This completely decouples code from ‘frameworks’ and makes a codebase far more extensible.
Sure and the closest thing to C# interfaces in C++ is an abstract class with virtual functions.
 
Top
Sign up to the MyBroadband newsletter
X