JS++ | Subtype Polymorphism
Last Updated :
30 Aug, 2018
Subtyping describes type relationships, and subtype polymorphism enables operations defined for supertypes to be safely substituted with subtypes. Concretely, imagine the relation between a 'Cat' class and an 'Animal' class. (Remember: classes create data types in JS++.) In this case, within the context of type relationships, 'Cat' is the subtype of 'Animal' and 'Animal' is the supertype of 'Cat'. In simpler terms, 'Cat' "is a" 'Animal', but 'Animal' is not a 'Cat'. In theory, this means that all operations that apply to the 'Animal' data type should accept operating on data of type 'Cat'; however, the reverse is not true: operations defined for the data type 'Cat' would not safely be able to operate on data of type 'Animal'.
If you remember the code from the previous section, cats and dogs are domesticated animals with names. However, not all animals should be named so our 'Animal' class did not take a name parameter. Thus, while we could have defined and called a 'name' getter on an instance of 'Cat', we could not safely substitute the 'Cat' instance with an 'Animal' instance. In JS++, if you even try to do this, you will get an error.
Subtype polymorphism allows us to write code in a more abstract manner. For example, within the context of primitive types, a 'byte' represents numbers in the range of 0 to 255. Meanwhile, an 'int' represents numbers within a much larger range: -2, 147, 483, 648 to 2, 147, 483, 647. Therefore, we can substitute numbers of type 'byte' where numbers of type 'int' are expected:
int add(int a, int b) {
return a + b;
}
byte a = 1;
byte b = 1;
add(a, b);
Thus, we are able to express algorithms and functions more "generally" because we can accept a wider variety of data (categorized by data types) for any given algorithm or function.
It's important not to confuse subtyping with inheritance even though the concepts are closely related within object-oriented programming. Subtyping describes type relationships, whereas inheritance is concerned with implementations (such as extending the implementation of a base class with a derived class). Subtyping can apply to interfaces while "inheritance" cannot. This concept will become clearer in later sections when we cover interfaces.
As a starting point to practically understand subtyping, we can change main.jspp so that the data type of all of our variables becomes 'Animal' but we keep the instantiation of classes as the subtypes:
import Animals;
Animal cat1 = new Cat("Kitty");
cat1.render();
Animal cat2 = new Cat("Kat");
cat2.render();
Animal dog = new Dog("Fido");
dog.render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();
Compile your code. It should compile successfully because, during instantiation, all data that is a subtype of 'Animal' can be assigned to a variable of type 'Animal'. In this case, 'Cat', 'Dog', 'Panda', and 'Rhino' data can all be safely assigned to 'Animal' variables.
However, there's a small "gotcha." Open index.html. You'll see all the animals rendered again, but, if you hover your mouse over any of the animal icons, you won't see any names! To understand why this occurs, we must understand static versus dynamic polymorphism, which will be explained in the next section. (In short, we actually specified we wanted "static" or compile-time polymorphism by using the 'overwrite' keyword on the 'render' method. Thus, we got the specified behavior.)
Similar Reads
JS++ | Static vs. Dynamic Polymorphism Static polymorphism is polymorphism that occurs at compile time, and dynamic polymorphism is polymorphism that occurs at runtime (during application execution). An aspect of static polymorphism is early binding. In early binding, the specific method to call is resolved at compile time. (JS++ also su
4 min read
JS++ | Access Modifiers and 'super' Access modifiers allow us to change the "visibility" and "access privileges" of a class (or module) member. These are best understood by example. JS++ has three access modifiers: private, protected, and public. A private member is the least permissive. If a member is declared as 'private' it can onl
15 min read
JS++ | Types in JavaScript In this chapter, we're going to explore JavaScript programming styles and how developers worked with types in JavaScript (rather than JS++). This chapter will help you understand the next chapters which explain the JS++ type system in detail. In this tutorial, we will be using the Google Chrome web
10 min read
JS++ | Virtual Methods As we mentioned in the previous section, if we want runtime polymorphism, using casts can lead to unclean code. By way of example, let's change our main.jspp code so that all our animals are inside an array. From there, we will loop over the array to render the animal. Open main.jspp and change the
3 min read
JS++ | Classes, OOP, and User-defined Types Up until now, we've been declaring variables, looping over data, and writing 'if' and other conditional statements. These operations comprise the "imperative programming" paradigm where we describe "how" a program operates step by step (or, more specifically, statement by statement). Oftentimes, in
6 min read