I've run into an odd case where a base class is calling a private method in a subclass that isn't defined as an override.
It's a bit contrived, but demonstrates the issue:
public virtual with sharing class Dog {
public void speak() {
bark();
}
// No virtual modifier, so it can't be overridden.
// Private as well. Not Public or Protected
private void bark() {
System.debug('The dog says woof');
}
}
Inherit the base class and provide a new definition of bark()
public with sharing class DogTerrier extends Dog {
// No override and base method is not virtual or protected/public
private void bark() {
System.debug('The terrier says yap');
}
}
Test it with anonymous Apex in the developer console. All API version are 37.0:
Dog d = new Dog();
d.speak();
DogTerrier t = new DogTerrier();
t.speak();
Dog td = new DogTerrier();
td.speak();
Debug log output:
10:50:44.15 (20036624)|USER_DEBUG|[8]|DEBUG|The dog says woof
10:50:44.15 (20694360)|USER_DEBUG|[4]|DEBUG|The terrier says yap
10:50:44.15 (21226199)|USER_DEBUG|[4]|DEBUG|The terrier says yap
Apex is calling the private method defined in the child class even though the base class isn't virtual and the child classes method isn't doing an override.
For comparison, I did the same test in C#.
public class Dog
{
public void speak()
{
bark();
}
private void bark()
{
Console.WriteLine("The dog says woof");
}
}
public class DogTerrier : Dog
{
private void bark()
{
Console.WriteLine("The terrier says yap");
}
}
And then tested it with a simple console app:
static void Main(string[] args)
{
Dog d = new Dog();
d.speak();
DogTerrier t = new DogTerrier();
t.speak();
Console.ReadLine();
}
Console output:
The dog says woof
The dog says woof
For good measure I also tried Java via https://www.compilejava.net/
public class HelloWorld
{
public static void main(String[] args)
{
Dog d = new Dog();
d.speak();
DogTerrier t = new DogTerrier();
t.speak();
}
}
public class Dog
{
public void speak()
{
bark();
}
private void bark()
{
System.out.println("The dog says woof");
}
}
public class DogTerrier extends Dog
{
private void bark()
{
System.out.println("The terrier says yap");
}
}
The dog says woof
The dog says woof
The Apex behavior seems like a bug to me. It is giving unintended method polymorphism for something that isn't:
virtual
- The method in the base/super class isn't a candidate for polymorphism.
protected
/public
- The base/super class shouldn't be able to see a private method in the child class.
Raised as Case # 14163020