dimitris papadimitriou
dimitris papadimitriou More than 12 years’ experience as full stack developer and Software Architect . Functional javascript with categories.

Pattern matching - Inheritance

 Pattern matching  - Inheritance

Pattern matching - Inheritance

Let us say now that you we have a simple hierarchy of shapes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 class Shape { } 

class Rectangle extends Shape {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

class Circle extends Shape {
  constructor(radius) {
    this.radius = radius;
  }
}

and we can assign in a Shape variable either a rectangle or a circle. Here i will go with the rectangle:

1
Shape s = new Rectangle(2, 3);

How can you find out during runtime what kind of shape did i put in ? How can we distinguish them.

Well, using Polymorphism is the usual OOP idea. This means you must add another method for every case that you want to implement. For example you should implement a polymorphic area() in each class to get the area and one toString() to get a String representation and so on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Shape { area() { throw `base class method` } }

class Rectangle extends Shape {
  constructor(height, width) {
    super();
    this.height = height;
    this.width = width;
  }
  area() { return this.width * this.height; }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }
  area() { return Math.PI * this.radius * this.radius; }
}

console.log(new Rectangle(10, 20).area());
console.log(new Circle(10).area()) 

Run this

Instead we can define a generic match method that .match() that allow us to define any other polymorphic method without modify the sub-classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 class Shape { }

class Rectangle extends Shape {
 ...
  match(pattern) {
    return pattern.rectangle(this.height, this.width);
  }
}

class Circle extends Shape {
...
  match(pattern) {
    return pattern.circle(this.radius);
  }
}

We can use this method to define an area function externally, without modifying the sub-classes:

1
2
3
4
5
6
7
8
9
10
11
 import { Rectangle,Circle } from "./Shape.js"

//define the area using .match()

var area = shape => shape.match({
  rectangle: (width, height) => width * height,
  circle: radius => Math.PI * radius * radius
});

console.log(area(new Rectangle(10, 20)));
console.log(area(new Circle(10)))

Run this

using the match we can now define any polymorphic method. For example a conversion to string function would look like the following:

1
2
3
4
5
6
7
8
9
10
 import { Rectangle,Circle } from "./Shape.js"


var toString = shape => shape.match({
  rectangle: (width, height) => `rectangle: ${width} , ${height}`,
  circle: radius => `circle: ${radius}`
});

console.log(toString(new Rectangle(10, 20)));
console.log(toString(new Circle(10)))

Run this

We are going to use the pattern matching for inheritance hierarchies extensively thought this course.

comments powered by Disqus