When considering inline caches, it seems that there is no check for "or further down in the hidden class tree" (which would be costly without some trick). Even though an instance property from a base class would always be at the same offset, accessing a base class property with many different subclass instances could potentially overwhelm its inline cache (or maybe not? It's possible that I am mistaken - strongly typed languages usually handle this scenario, so perhaps there is a trick involved). This concept also applies to objects in general.
This led me to ponder: instead of subclasses, would it sometimes be more effective to have two separate objects - one with the base properties and another with the subclass properties, both referencing each other?
Class extension version:
class A {
x = 0;
}
class B1 extends A {
y = 0;
}
class B2 extends A {
z = 0;
}
const b1 = new B1();
const b2 = new B2();
const f = (p: A) => { p.x; };
// Different hidden classes.
f(b1);
f(b2);
Linked objects version:
class A<T> {
x = 0;
extension: T;
constructor(extension: T) { this.extension = extension; }
}
class B1 {
a: A<B1>;
y = 0;
constructor() { this.a = new A(this); }
}
class B2 {
a: A<B2>;
z = 0;
constructor() { this.a = new A(this); }
}
const b1 = new B1();
const b2 = new B2();
const a1 = b1.a;
const a2 = b2.a;
const f = <T>(p: A<T>) => { p.x; };
// Same hidden class.
f(a1);
f(a2);
Does this approach have any noticeable performance impact? The typical response might be "don't worry about it until you've confirmed it's a bottleneck", but it's still a question worth exploring.