In this lesson, we begin our introduction to subtype polymorphism. Imagine a feature that checks if there are comments on an article or a topic (questions from Hexlet users under tutorials and projects). In the code, we represent:
- Articles as objects with the class Article
- Topics as objects with the class Topic
const hasComments = (commentable) => {
// If this is an article
if (commentable instanceof Article) {
return commentable.getArticleComments().length > 0;
// If this is a topic
} else if (commentable instanceof Topic) {
return commentable.getTopicComments().length > 0;
}
}
class Article {
// Some code
getArticleComments() {
return this.comments;
}
}
class Topic
{
// some code
getTopicsComments()
{
return this.comments;
}
}
// Article.first() is the method that returns the first article from the database
const article = Article.first();
console.log(hasComments(article));
We have encountered this kind of code before. Each new type will make us add code to this conditional construct. We can use dispatching by key instead, but it is not the best option. We already have the defined behavior within classes, but we still have to define the behavior of each class manually.
But there is something even better you can do. We can align the interface of all types and agree that the method for retrieving comments will have the name getComments()
. Then the code will be like this:
const hasComments = (commentable) => commentable.getComments().length > 0;
const article = Article.first();
console.log(hasComments(article));
const topic = Topic.first();
console.log(hasComments(topic));
Now we can call the hasComments(commentable)
function with any object, having a getComments()
method with the necessary signature. This function will not change even if you add a new class containing the same method.
Here we see subtype polymorphism — the ability of a function to handle objects of different types in the same way. The function itself is called a polymorphic function.
As you can see from the code above, you do not need inheritance and interfaces in JavaScript to implement this kind of polymorphism. This approach is called duck typing. If something walks like a duck and quacks like a duck, it is a duck.
Technically, the most straightforward thing that subtype polymorphism does for client code is the removal of conditional constructs. We can replace any conditional construct with polymorphism, and use if
instead of any polymorphic function.
In other words, subtype polymorphism is not an integral part of development. We can write code can be written without it. On the other hand, sometimes there are situations in which it helps a lot, but it doesn't happen all the time.
What is the difference between parametric polymorphism and subtype polymorphism?
In the first case, we implement a generic algorithm for a container that contains a value or values of type T. This algorithm is independent of T and is executed identically for any T.
In the second case, we page the object itself and use its methods. In subtype polymorphism, the polymorphic function works only with objects which have the necessary methods to implement the algorithm.
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.