import { Base as ImportedBase, ArityBase, arityCounts } from "./base.js"; class Middle extends ImportedBase {} class Derived extends Middle { render(value) { console.log("derived", value); } } const Expression = class extends ImportedBase { render(value) { console.log("expression", value); } }; class Leaf extends Derived { render(value) { super.render(value); console.log("leaf", value); } } function dispatch(receiver, value) { receiver.render(value); } // An unrelated method with the same name still specializes its argument. class Standalone { render(point) { console.log("standalone", point.x + point.y); } } class Short extends ArityBase { render(value) { console.log("short", value); } defaulted(value) { console.log("short default", value); } forward(value) { this.render(value); } } class Empty extends Short { render() { console.log("empty"); } } class LongAgain extends Short { render(value, time) { super.render(value); console.log("long again", value, time); } } export function exercise() { new ImportedBase().dispatch("base call"); new Derived().dispatch(7); new Leaf().dispatch("leaf call"); new Expression().dispatch("expression call"); dispatch(new Derived(), "helper call"); new Standalone().render({ x: 2, y: 3 }); new ArityBase().dispatch("base"); new Short().dispatch("short"); new Empty().dispatch("empty"); new LongAgain().dispatch("long"); new Short().render("direct"); new Empty().render(); new LongAgain().render("direct", 9); new LongAgain().forward("omitted"); new ArityBase().dispatchDefault("base"); new Short().dispatchDefault("derived"); new Short().defaulted("direct"); arityCounts(); } class Pair { constructor(x, y) { this.x = x; this.y = y; } /** @param {Pair} other */ add(other) { this.x += other.x; this.y += other.y; return this; } } class Triple { constructor(x, y, z) { this.x = x; this.y = y; this.z = z; } } class Helpers { /** @param {Pair} target @param {Pair} other @returns {Pair} */ static combine(target, other) { target.x += other.x; target.y += other.y; return target; } } class InheritedHelpers extends Helpers {} class OverriddenHelpers extends Helpers { static combine(target, other) { target.x -= other.x; target.y -= other.y; return target; } } export function structuralMethods() { const pair = new Pair(1, 2); const triple = new Triple(3, 4, 5); console.log('instance', pair.add(triple) === pair, pair.x, pair.y); console.log('static', Helpers.combine(triple, pair) === triple, triple.x, triple.y, triple.z); console.log('inherited', InheritedHelpers.combine(triple, pair) === triple, triple.x); console.log('overridden', OverriddenHelpers.combine(triple, pair) === triple, triple.x); const combine = Helpers.combine; console.log('static value', combine(pair, pair) === pair, pair.x, pair.y); const add = pair.add; try { add(pair); } catch (error) { console.log('unbound', error instanceof TypeError); } const rows = [triple, new Triple(1, 0, 0)]; function compare(a, b) { return a.x - b.x; } console.log('sort', rows.sort(compare) === rows, rows[0].x, rows[1].x); }