Inheritance and checked downcasts
This example uses single inheritance for shared implementation and an interface for the public behavior contract.
Source
ts
import go fmt from "fmt";
interface Speaker { function speak(): string; }
class Animal implements Speaker {
constructor(public name: string) {}
public virtual function speak(): string { return "animal"; }
public function describe(): string { return this.name + ":" + this.speak(); }
}
class Dog extends Animal {
constructor(name: string, public sound: string) { super(name); }
public override function speak(): string {
return super.speak() + "/" + this.sound;
}
}
final class GuideDog extends Dog {
constructor(name: string) { super(name, "woof"); }
public final override function speak(): string {
return super.speak() + "/guide";
}
}
function describe(value: Animal): string { return value.describe(); }
function main(): void {
const guide = new GuideDog("Hana");
const animal: Animal = guide;
fmt.Println(describe(animal));
const [restored, ok] = animal as? GuideDog;
if (ok) { fmt.Println(restored.speak(), restored === guide); }
const plain: Animal = new Animal("Mugi");
const [missing, found] = plain as? GuideDog;
fmt.Println(found, missing === nil);
}Run
sh
keika check inheritance.km
keika run inheritance.kmExpected output:
text
Hana:animal/woof/guide
animal/woof/guide true
false trueWhat the example proves
GuideDoginitializes its base classes throughsuper(...).- Calls made through
Animalstill dispatch to the most-derived override. - An upcast preserves reference identity.
value as? GuideDogreturns[value, boolean]and never panics.- A failed checked downcast returns the nil zero value plus
false.
Use as! only when failure is a programmer error; a failed forced downcast panics with the corresponding Go assertion behavior. Downcasts are valid only within one class inheritance chain. Interface assertions use the same surface syntax but follow Go interface method-set rules.
See Classes and structs for initialization, visibility, virtual, override, and final rules.