Extend
Also known as: extend extension method monkey patch add method to existing type implement interface for
● Intermediate4 minBefore this: MethodsSpec 2.5
extend adds methods to a type you didn't write: a built-in type, a union, or a type from another module.
extend String {
fn shout(self) -> String {
self.upper() + "!"
}
}
fn main() {
print("namaste".shout())
}The program ran and printed:
kavach run extend.kav
NAMASTE!type Status = Pending | Paid
extend Status {
fn label(self) -> String {
match self {
Status.Pending => "waiting for payment"
Status.Paid => "done"
}
}
}
extend Int {
fn is_even(self) -> Bool {
self % 2 == 0
}
}
fn main() {
print(Status.Paid.label())
print(10.is_even())
}The program ran and printed:
kavach run extend-more.kav
donetrue
Inside extend, methods are written as in a record, with self. A union's methods go in an extend too, since a union has no body of its own.
Extending a generic type
To extend a generic type, name its parameters after extend, as a generic function does: extend<S> App<S>. So a type's many methods can be spread over files:
use routes
pub type App<S> {
pub state: S
pub routes: Int = 0
}use shop.{App}
extend<S> App<S> {
pub fn route(self) -> App<S> {
self with { routes: self.routes + 1 }
}
pub fn state_of(self) -> S {
self.state
}
}use shop.{App}
fn main() {
const orders = App(state: "orders").route().route()
print("{orders.routes} routes, state: {orders.state_of()}")
const counter = App(state: 41).route()
print("{counter.routes} route, state: {counter.state_of() + 1}")
}The program ran and printed:
kavach run
2 routes, state: orders1 route, state: 42
Sstands for the type's own parameter:state_ofgives aStringfor one app and anIntfor the other.- A name after
extendthat isn't one of the type's parameters is an error.
Keeping a promise for another type
extend Rect: Describe { … } says that Rect, declared elsewhere, keeps the Describe interface:
interface Describe {
fn describe(self) -> String
}
type User: Describe {
name: String
fn describe(self) -> String { "User {self.name}" }
}
type Rect {
width: Int
height: Int
}
extend Rect: Describe {
fn describe(self) -> String { "Rect {self.width}x{self.height}" }
}
fn show<T: Describe>(item: T) -> String {
item.describe()
}
fn main() {
print(show(User(name: "Asha")))
print(show(Rect(width: 2, height: 3)))
}The program ran and printed:
kavach run interfaces.kav
User AshaRect 2x3
extend adds methods, never fields: a type's data is always where the type is declared.