Lets say Thing has the following properties:
- IsVisible
- Mass
- CanMove
Lets say Tube has the following properties:
- PlayNote
And lets say that Cat has:
- Meow
Lets take the following contrived example for overriding:
Class Debugger {
void debug(Cat cat);
}
Class ThingDebugger : Debugger {
void debug(Thing thing);
}
Going "wider" to Thing works because Cats, Dogs, and Tuba all have the properties that a Thing has, because they are instances of Thing. Going "narrower" works for the same reason:
Class Wrangler {
Animal wrangle();
}
Class DogWrangler : Wrangler {
Dog wrangle();
}
A Dog can do anything an Animal can do because it is an Animal.
The type system is doing its best to save you from the following:
Class Janky {
void ThisIsOK();
Animal PrepareForCrash();
}
Class AlsoJanky : Janky {
void ThisIsOK();
Instrument PrepareForCrash();
}
Class StillJanky : Janky {
void ThisIsOK();
Thing PrepareForCrash();
}
In this case any mixing of PrepareForCrash will leave you with returned types that don't completely share an interface. If the compiler let you do that, you'd probably do this at some point start mixing the subtypes of Janky and calls to PrepareForCrash would return Tubas when you expect Cats and then all hell would break loose. Anyone who's used scripting languages should be familiar with something like this happening at one point or another.
first you can't call super() in that method without a downcast. how does that count as overriding the method?
it's a big problem if you have another subclass of Debugger that does not change the parameter type. you now have 2 subclassed of Debugger, one has a method debug(cat: Cat). the other has a method debug(cat: Thing). that accepts cats, dogs, and tubas. these subtypes of Debugger are not safely interchangeable.
this does not compile in scala, I'm surprised swift would allow it.
Thing -> Animal -> Dog Thing -> Animal -> Cat Thing -> Instrument -> Tuba
Lets say Thing has the following properties: - IsVisible - Mass - CanMove
Lets say Tube has the following properties: - PlayNote
And lets say that Cat has: - Meow
Lets take the following contrived example for overriding:
Going "wider" to Thing works because Cats, Dogs, and Tuba all have the properties that a Thing has, because they are instances of Thing. Going "narrower" works for the same reason: A Dog can do anything an Animal can do because it is an Animal.The type system is doing its best to save you from the following:
In this case any mixing of PrepareForCrash will leave you with returned types that don't completely share an interface. If the compiler let you do that, you'd probably do this at some point start mixing the subtypes of Janky and calls to PrepareForCrash would return Tubas when you expect Cats and then all hell would break loose. Anyone who's used scripting languages should be familiar with something like this happening at one point or another.