Classes and Inheritance
Also known as: class classes object oriented oop inheritance extends subclass superclass base class abstract class constructor static method composition polymorphism
● Intermediate6 minBefore this: Interfaces, Interface ValuesSpec 2.8
Kavach has no classes and no inheritance. Records, methods, interfaces and composition do the same jobs, with fewer surprises.
From classes to Kavach
| In Java, C#, Python… | In Kavach |
|---|---|
| A class with fields | a type (a record) |
| Methods | methods inside the type, with self |
| A constructor | User(name: …), with defaults for optional fields |
| A static method | a method without self: Rect.square(2.0) |
| An abstract class or interface | an interface |
| Implementing it | type Circle: Shape, or extend Rect: Shape |
| A list of different subclasses | a list of an interface type: [Shape] |
| Inheriting fields | a field holding the other value (composition) |
| A fixed set of subclasses | a union, type Shape = Circle | Square, checked by match |
| Adding methods to a class you didn't write | extend |
All of it together
interface Shape {
fn area(self) -> Float
fn name(self) -> String
}
type Circle: Shape {
radius: Float
fn area(self) -> Float { 3.14 * self.radius * self.radius }
fn name(self) -> String { "circle" }
}
type Square: Shape {
side: Float
fn area(self) -> Float { self.side * self.side }
fn name(self) -> String { "square" }
}
type Label {
text: String
shape: Shape
fn describe(self) -> String {
"{self.text}: a {self.shape.name()} of area {self.shape.area()}"
}
}
fn main() {
const shapes: [Shape] = [Circle(radius: 1.0), Square(side: 2.0)]
for s in shapes {
print("{s.name()}: {s.area()}")
}
print(Label(text: "logo", shape: Square(side: 3.0)).describe())
}The program ran and printed:
kavach run classes.kav
circle: 3.14square: 4.0logo: a square of area 9.0
Shapeis the interface: what every shape can do.CircleandSquarekeep that promise, each its own way.- A
[Shape]holds both kinds, and each call runs the right method. Labelhas a shape instead of being one: composition.
Extending a record is refused
Writing a subclass out of habit gets an error that names both ways to do it in Kavach:
type Animal {
name: String
}
type Dog: Animal {
breed: String
}The compiler refused the program:
kavach run inherit.kav
error: `Dog` can't extend `Animal`: `Animal` is a type, not an interface, and Kavach has no inheritance (decision 0029). Give `Dog` a field `animal: Animal`, or make `Animal` an interfaceGo deeper the why, for readers who want it
Inheritance ties a class to everything above it: change a base class, and every subclass may break, even ones you have never seen (the "fragile base class" problem). Deep hierarchies also hide where a method really comes from.
Kavach keeps the useful half. Interfaces give polymorphism (one call, many types), and composition gives reuse (a value that holds another). Every method a type has is written in its own declaration or in an extend, so it is always easy to find.