JavaScript OOP Course 4: Prototypical Inheritance: Difference between revisions
m Стадий: 6 [Фаза:Утвърждаване, Статус:Утвърден]; Категория:JavaScript |
m Text replacement - "mlw-continue" to "code-continue" |
||
Line 6: | Line 6: | ||
==Creating Your Own Prototypical Inheritance== | ==Creating Your Own Prototypical Inheritance== | ||
<syntaxhighlight lang="javascript" class=" | <syntaxhighlight lang="javascript" class="code-continue"> | ||
function Shape(color) { | function Shape(color) { | ||
this.color = color; | this.color = color; | ||
Line 15: | Line 15: | ||
const shape = new Shape('red'); | const shape = new Shape('red'); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
Object.getPrototypeOf(shape); | Object.getPrototypeOf(shape); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
{duplicate: ƒ, constructor: ƒ} | {duplicate: ƒ, constructor: ƒ} | ||
duplicate: ƒ () | duplicate: ƒ () | ||
constructor: ƒ Shape(color) | constructor: ƒ Shape(color) | ||
[[Prototype]]: Object | [[Prototype]]: Object | ||
</syntaxhighlight>Now we want to inherit the <code>duplicate()</code> method by another type of objects, like Circle and Square.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Now we want to inherit the <code>duplicate()</code> method by another type of objects, like Circle and Square.<syntaxhighlight lang="javascript" class="code-continue"> | ||
function Circle(radius) { | function Circle(radius) { | ||
this.radius = radius; | this.radius = radius; | ||
Line 31: | Line 31: | ||
const circle1 = new Circle(1); | const circle1 = new Circle(1); | ||
</syntaxhighlight>Note the Constructor here is <code>''ƒ Circle(radius)''</code>.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Note the Constructor here is <code>''ƒ Circle(radius)''</code>.<syntaxhighlight lang="javascript" class="code-continue"> | ||
Object.getPrototypeOf(circle1); | Object.getPrototypeOf(circle1); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
{draw: ƒ, constructor: ƒ} | {draw: ƒ, constructor: ƒ} | ||
draw: ƒ () | draw: ƒ () | ||
constructor: ƒ Circle(radius) | constructor: ƒ Circle(radius) | ||
[[Prototype]]: Object | [[Prototype]]: Object | ||
</syntaxhighlight>Change the Prototype of the Constructor and create a new Object at this Base.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Change the Prototype of the Constructor and create a new Object at this Base.<syntaxhighlight lang="javascript" class="code-continue"> | ||
Circle.prototype = Object.create(Shape.prototype); | Circle.prototype = Object.create(Shape.prototype); | ||
const circle2 = new Circle(2); | const circle2 = new Circle(2); | ||
</syntaxhighlight>Note now the Constructor is <code>''ƒ Shape(color)''</code>.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Note now the Constructor is <code>''ƒ Shape(color)''</code>.<syntaxhighlight lang="javascript" class="code-continue"> | ||
Object.getPrototypeOf(circle2); | Object.getPrototypeOf(circle2); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
Shape {} | Shape {} | ||
[[Prototype]]: Object | [[Prototype]]: Object | ||
Line 49: | Line 49: | ||
constructor: ƒ Shape(color) | constructor: ƒ Shape(color) | ||
[[Prototype]]: Object | [[Prototype]]: Object | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
circle2.duplicate(); | circle2.duplicate(); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
duplicate | duplicate | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 57: | Line 57: | ||
== Resetting the Constructor == | == Resetting the Constructor == | ||
As best practice when we reset the Prototype make sure you reset the constructor as well. Let's continue by the last example, where we saw when the Prototype was changed to <code>Shape</code> also the Constructor was changed to <code>Shape</code>, here is how to set it back to <code>Circle</code>''.''<syntaxhighlight lang="javascript" class=" | As best practice when we reset the Prototype make sure you reset the constructor as well. Let's continue by the last example, where we saw when the Prototype was changed to <code>Shape</code> also the Constructor was changed to <code>Shape</code>, here is how to set it back to <code>Circle</code>''.''<syntaxhighlight lang="javascript" class="code-continue"> | ||
Circle.prototype = Object.create(Shape.prototype); | Circle.prototype = Object.create(Shape.prototype); | ||
Circle.prototype.constructor = Circle; | Circle.prototype.constructor = Circle; | ||
const circle3 = new Circle(3); | const circle3 = new Circle(3); | ||
</syntaxhighlight>Note in the example below the Constructor is changed back to <code>Circle</code>.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Note in the example below the Constructor is changed back to <code>Circle</code>.<syntaxhighlight lang="javascript" class="code-continue"> | ||
Object.getPrototypeOf(circle3); | Object.getPrototypeOf(circle3); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
Shape {constructor: ƒ} | Shape {constructor: ƒ} | ||
constructor: ƒ Circle(radius) | constructor: ƒ Circle(radius) | ||
Line 73: | Line 73: | ||
== Calling the Super Constructor == | == Calling the Super Constructor == | ||
<syntaxhighlight lang="javascript" class=" | <syntaxhighlight lang="javascript" class="code-continue"> | ||
function Shape(color) { | function Shape(color) { | ||
this.color = color; | this.color = color; | ||
Line 80: | Line 80: | ||
console.log('duplicate'); | console.log('duplicate'); | ||
}; | }; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
function Circle(radius, color) { | function Circle(radius, color) { | ||
Shape.call(this, color); | Shape.call(this, color); | ||
Line 88: | Line 88: | ||
console.log('draw'); | console.log('draw'); | ||
}; | }; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
Circle.prototype = Object.create(Shape.prototype); | Circle.prototype = Object.create(Shape.prototype); | ||
Circle.prototype.constructor = Circle; | Circle.prototype.constructor = Circle; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
const shape = new Shape('red'); | const shape = new Shape('red'); | ||
const circle = new Circle(10, 'blue'); | const circle = new Circle(10, 'blue'); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
circle; | circle; | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
Circle {color: 'blue', radius: 10} | Circle {color: 'blue', radius: 10} | ||
color: "blue" | color: "blue" | ||
Line 109: | Line 109: | ||
== Intermediate Function Inheritance == | == Intermediate Function Inheritance == | ||
<syntaxhighlight lang="javascript" class=" | <syntaxhighlight lang="javascript" class="code-continue"> | ||
function Shape(color) { | function Shape(color) { | ||
this.color = color; | this.color = color; | ||
Line 116: | Line 116: | ||
console.log('duplicate'); | console.log('duplicate'); | ||
}; | }; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
function Square(size, color) { | function Square(size, color) { | ||
Shape.call(this, color); | Shape.call(this, color); | ||
this.size = size; | this.size = size; | ||
} | } | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
Square.prototype = Object.create(Shape.prototype); | Square.prototype = Object.create(Shape.prototype); | ||
Square.prototype.constructor = Square; | Square.prototype.constructor = Square; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
const square = new Square(10, 'green'); | const square = new Square(10, 'green'); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
square; | square; | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
Square {color: 'green', size: 10} | Square {color: 'green', size: 10} | ||
color: "green" | color: "green" | ||
Line 138: | Line 138: | ||
constructor: ƒ Shape(color) | constructor: ƒ Shape(color) | ||
[[Prototype]]: Object | [[Prototype]]: Object | ||
</syntaxhighlight>Now let's rewrite the above code and extract the two lines that changes the Prototype and the Constructor in a Function that we can reuse multiple times.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Now let's rewrite the above code and extract the two lines that changes the Prototype and the Constructor in a Function that we can reuse multiple times.<syntaxhighlight lang="javascript" class="code-continue"> | ||
function extend(Child, Parent) { | function extend(Child, Parent) { | ||
Child.prototype = Object.create(Parent.prototype); | Child.prototype = Object.create(Parent.prototype); | ||
Child.prototype.constructor = Child; | Child.prototype.constructor = Child; | ||
} | } | ||
</syntaxhighlight>This <code>extend()</code> function is what we call Intermediate function inheritance. Here is how to use it.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>This <code>extend()</code> function is what we call Intermediate function inheritance. Here is how to use it.<syntaxhighlight lang="javascript" class="code-continue"> | ||
function Shape(color) { | function Shape(color) { | ||
this.color = color; | this.color = color; | ||
} | } | ||
Shape.prototype.duplicate = function() { console.log('duplicate'); }; | Shape.prototype.duplicate = function() { console.log('duplicate'); }; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
function Circle(radius) { | function Circle(radius) { | ||
this.radius = radius; | this.radius = radius; | ||
} | } | ||
extend(Circle, Shape); | extend(Circle, Shape); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
function Square(size) { | function Square(size) { | ||
this.size = size; | this.size = size; | ||
} | } | ||
extend(Square, Shape); | extend(Square, Shape); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
const circle = new Circle(10); | const circle = new Circle(10); | ||
const square = new Square(10); | const square = new Square(10); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
circle; | circle; | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
Circle {radius: 10} | Circle {radius: 10} | ||
radius: 10 | radius: 10 | ||
Line 172: | Line 172: | ||
constructor: ƒ Shape(color) | constructor: ƒ Shape(color) | ||
[[Prototype]]: Object | [[Prototype]]: Object | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
square; | square; | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
Square {size: 10} | Square {size: 10} | ||
size: 10 | size: 10 | ||
Line 186: | Line 186: | ||
== Method Overriding == | == Method Overriding == | ||
<syntaxhighlight lang="javascript" class=" | <syntaxhighlight lang="javascript" class="code-continue"> | ||
function extend(Child, Parent) { | function extend(Child, Parent) { | ||
Child.prototype = Object.create(Parent.prototype); | Child.prototype = Object.create(Parent.prototype); | ||
Line 202: | Line 202: | ||
const circle = new Circle(); | const circle = new Circle(); | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
circle; | circle; | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
Circle {} | Circle {} | ||
[[Prototype]]: Shape | [[Prototype]]: Shape | ||
Line 212: | Line 212: | ||
constructor: ƒ Shape() | constructor: ƒ Shape() | ||
[[Prototype]]: Object | [[Prototype]]: Object | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
circle.duplicate(); | circle.duplicate(); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
duplicate | duplicate | ||
</syntaxhighlight>Now let's imagine the duplicate() method should behave differently at Circle objects. In order to override this method (or reimplementing a method on a child object) we need to put our declaration '''after the resetting the prototype''' by the <code>extend()</code> function.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Now let's imagine the duplicate() method should behave differently at Circle objects. In order to override this method (or reimplementing a method on a child object) we need to put our declaration '''after the resetting the prototype''' by the <code>extend()</code> function.<syntaxhighlight lang="javascript" class="code-continue"> | ||
Circle.prototype.duplicate = function() { | Circle.prototype.duplicate = function() { | ||
console.log('duplicate circle'); | console.log('duplicate circle'); | ||
}; | }; | ||
</syntaxhighlight><syntaxhighlight lang="javascript" class=" | </syntaxhighlight><syntaxhighlight lang="javascript" class="code-continue"> | ||
circle.duplicate(); | circle.duplicate(); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
duplicate circle | duplicate circle | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Polymorphism == | == Polymorphism == | ||
Polymorphism - many form. In the following example the polymorphism manifests in the <code>duplicate()</code> method which is specific for each type of shape...<syntaxhighlight lang="javascript" class=" | Polymorphism - many form. In the following example the polymorphism manifests in the <code>duplicate()</code> method which is specific for each type of shape...<syntaxhighlight lang="javascript" class="code-continue"> | ||
function extend(Child, Parent) { | function extend(Child, Parent) { | ||
Child.prototype = Object.create(Parent.prototype); | Child.prototype = Object.create(Parent.prototype); | ||
Line 249: | Line 249: | ||
console.log('duplicate square'); | console.log('duplicate square'); | ||
}; | }; | ||
</syntaxhighlight>Let's define an array of shape objects.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Let's define an array of shape objects.<syntaxhighlight lang="javascript" class="code-continue"> | ||
const shapes = [ | const shapes = [ | ||
new Circle(), | new Circle(), | ||
new Square() | new Square() | ||
]; | ]; | ||
</syntaxhighlight>Now we can iterate over this array by using <code>for.. of..</code> loop in the following way.<syntaxhighlight lang="javascript" class=" | </syntaxhighlight>Now we can iterate over this array by using <code>for.. of..</code> loop in the following way.<syntaxhighlight lang="javascript" class="code-continue"> | ||
for (let shape of shapes) | for (let shape of shapes) | ||
shape.duplicate(); | shape.duplicate(); | ||
</syntaxhighlight><syntaxhighlight lang="shell-session" class=" | </syntaxhighlight><syntaxhighlight lang="shell-session" class="code-continue"> | ||
duplicate circle | duplicate circle | ||
duplicate square | duplicate square |
Latest revision as of 07:29, 26 September 2022
References
- Code with Mosh: The Ultimate JavaScript Mastery Series – Part 2
- W3School: JavaScript Tutorial
Creating Your Own Prototypical Inheritance
function Shape(color) {
this.color = color;
}
Shape.prototype.duplicate = function() {
console.log('duplicate');
};
const shape = new Shape('red');
Object.getPrototypeOf(shape);
{duplicate: ƒ, constructor: ƒ}
duplicate: ƒ ()
constructor: ƒ Shape(color)
[[Prototype]]: Object
Now we want to inherit the duplicate()
method by another type of objects, like Circle and Square.
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.draw = function() {
console.log('draw');
};
const circle1 = new Circle(1);
Note the Constructor here is ƒ Circle(radius)
.
Object.getPrototypeOf(circle1);
{draw: ƒ, constructor: ƒ}
draw: ƒ ()
constructor: ƒ Circle(radius)
[[Prototype]]: Object
Change the Prototype of the Constructor and create a new Object at this Base.
Circle.prototype = Object.create(Shape.prototype);
const circle2 = new Circle(2);
Note now the Constructor is ƒ Shape(color)
.
Object.getPrototypeOf(circle2);
Shape {}
[[Prototype]]: Object
duplicate: ƒ ()
constructor: ƒ Shape(color)
[[Prototype]]: Object
circle2.duplicate();
duplicate
Resetting the Constructor
As best practice when we reset the Prototype make sure you reset the constructor as well. Let's continue by the last example, where we saw when the Prototype was changed to Shape
also the Constructor was changed to Shape
, here is how to set it back to Circle
.
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
const circle3 = new Circle(3);
Note in the example below the Constructor is changed back to Circle
.
Object.getPrototypeOf(circle3);
Shape {constructor: ƒ}
constructor: ƒ Circle(radius)
[[Prototype]]: Object
duplicate: ƒ ()
constructor: ƒ Shape(color)
[[Prototype]]: Object
Calling the Super Constructor
function Shape(color) {
this.color = color;
}
Shape.prototype.duplicate = function() {
console.log('duplicate');
};
function Circle(radius, color) {
Shape.call(this, color);
this.radius = radius;
}
Circle.prototype.draw = function() {
console.log('draw');
};
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
const shape = new Shape('red');
const circle = new Circle(10, 'blue');
circle;
Circle {color: 'blue', radius: 10}
color: "blue"
radius: 10
[[Prototype]]: Shape
constructor: ƒ Circle(radius, color)
[[Prototype]]: Object
duplicate: ƒ ()
constructor: ƒ Shape(color)
[[Prototype]]: Object
Intermediate Function Inheritance
function Shape(color) {
this.color = color;
}
Shape.prototype.duplicate = function() {
console.log('duplicate');
};
function Square(size, color) {
Shape.call(this, color);
this.size = size;
}
Square.prototype = Object.create(Shape.prototype);
Square.prototype.constructor = Square;
const square = new Square(10, 'green');
square;
Square {color: 'green', size: 10}
color: "green"
size: 10
[[Prototype]]: Shape
constructor: ƒ Square(size, color)
[[Prototype]]: Object
duplicate: ƒ ()
constructor: ƒ Shape(color)
[[Prototype]]: Object
Now let's rewrite the above code and extract the two lines that changes the Prototype and the Constructor in a Function that we can reuse multiple times.
function extend(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
This extend()
function is what we call Intermediate function inheritance. Here is how to use it.
function Shape(color) {
this.color = color;
}
Shape.prototype.duplicate = function() { console.log('duplicate'); };
function Circle(radius) {
this.radius = radius;
}
extend(Circle, Shape);
function Square(size) {
this.size = size;
}
extend(Square, Shape);
const circle = new Circle(10);
const square = new Square(10);
circle;
Circle {radius: 10}
radius: 10
[[Prototype]]: Shape
constructor: ƒ Circle(radius)
[[Prototype]]: Object
duplicate: ƒ ()
constructor: ƒ Shape(color)
[[Prototype]]: Object
square;
Square {size: 10}
size: 10
[[Prototype]]: Shape
constructor: ƒ Square(size)
[[Prototype]]: Object
duplicate: ƒ ()
constructor: ƒ Shape(color)
[[Prototype]]: Object
Method Overriding
function extend(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
function Shape() { }
Shape.prototype.duplicate = function() {
console.log('duplicate');
};
function Circle() { }
extend(Circle, Shape);
const circle = new Circle();
circle;
Circle {}
[[Prototype]]: Shape
constructor: ƒ Circle()
[[Prototype]]: Object
duplicate: ƒ ()
constructor: ƒ Shape()
[[Prototype]]: Object
circle.duplicate();
duplicate
Now let's imagine the duplicate() method should behave differently at Circle objects. In order to override this method (or reimplementing a method on a child object) we need to put our declaration after the resetting the prototype by the extend()
function.
Circle.prototype.duplicate = function() {
console.log('duplicate circle');
};
circle.duplicate();
duplicate circle
Polymorphism
Polymorphism – many form. In the following example the polymorphism manifests in the duplicate()
method which is specific for each type of shape…
function extend(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
function Shape() { }
Shape.prototype.duplicate = function() {
console.log('duplicate');
};
function Circle() { }
extend(Circle, Shape);
Circle.prototype.duplicate = function() {
console.log('duplicate circle');
};
function Square() { }
extend(Square, Shape);
Square.prototype.duplicate = function() {
console.log('duplicate square');
};
Let's define an array of shape objects.
const shapes = [
new Circle(),
new Square()
];
Now we can iterate over this array by using for.. of..
loop in the following way.
for (let shape of shapes)
shape.duplicate();
duplicate circle
duplicate square
When to Use Inheritance
- Inheritance is great tool to solving the problem of code reuse. You have to be really careful about using it because it can make your source code complex and fragile, so don't use inheritance just for the sake of using it, especially in small projects. Keep it simple and stupid.
- Start with simple objects and then if you see number of these objects share similar features then perhaps you can encapsulate these features inside of an generic object and use inheritance.
- But remember inheritance is not the only solution that enabled code reuse. There is another technique called Composition (that can be used for the same purpose). Favor Composition over Inheritance.
- Avoid creating inheritance hierarchies, because they are very fragile. If you want to use inheritance keep it to one level – do not go than more one level of inheritance.