Skip to content
Kavachकवच

Coming From Another Language: Go

● Beginner6 minBefore this: Coming From Another Language

From Go: try instead of if err != nil, no nil, interfaces a type names, and no garbage collector.

Here is one small program twice: in Go as you would write it, then in Kavach. Orders with a quantity and a price, a total that refuses an order with no quantity, and discount codes that may be missing. Both print the same three lines.

package main

import "fmt"

type Order struct {
	Item  string
	Qty   int
	Cents int
}

func (o Order) Cost() int {
	return o.Qty * o.Cents
}

type BadQty struct {
	Item string
}

func (e BadQty) Error() string {
	return "no quantity for " + e.Item
}

func total(orders []Order) (int, error) {
	sum := 0
	for _, o := range orders {
		if o.Qty <= 0 {
			return 0, BadQty{Item: o.Item}
		}
		sum += o.Cost()
	}
	return sum, nil
}

func main() {
	codes := map[string]int{"SPRING": 10, "VIP": 25}
	orders := []Order{{"pen", 3, 150}, {"cup", 1, 900}}

	sum, err := total(orders)
	if err != nil {
		sum = 0
	}
	off := codes["SPRING"]
	fmt.Printf("total %d, with %d%% off %d\n", sum, off, sum*(100-off)/100)
	fmt.Printf("WINTER gives %d%%\n", codes["WINTER"])

	broken := []Order{{"kite", 0, 500}}
	if t, err := total(broken); err != nil {
		if bad, ok := err.(BadQty); ok {
			fmt.Printf("refused: no quantity for %s\n", bad.Item)
		}
	} else {
		fmt.Printf("total %d\n", t)
	}
}
orders.go: go code
type Order {
    item: String
    qty: Int
    cents: Int

    fn cost(self) -> Int {
        self.qty * self.cents
    }
}

type OrderError = BadQty(item: String)

fn total(orders: [Order]) -> Int ! OrderError {
    for o in orders {
        if o.qty <= 0 {
            fail OrderError.BadQty(item: o.item)
        }
    }
    orders.sum(o => o.cost())
}

fn main() {
    const codes = ["SPRING": 10, "VIP": 25]
    const orders = [Order(item: "pen", qty: 3, cents: 150), Order(item: "cup", qty: 1, cents: 900)]

    const sum = total(orders) catch _ => 0
    const off = codes["SPRING"] ?? 0
    print("total {sum}, with {off}% off {sum * (100 - off) / 100}")
    print("WINTER gives {codes["WINTER"] ?? 0}%")

    const broken = [Order(item: "kite", qty: 0, cents: 500)]
    match total(broken) {
        ok(t) => print("total {t}"),
        err(OrderError.BadQty(item)) => print("refused: no quantity for {item}"),
    }
}

The program ran and printed:

kavach run orders.kav

total 1350, with 10% off 1215WINTER gives 0%refused: no quantity for kite
orders.kav: Kavach code, then what running it prints

What changes

In GoIn KavachLearn it
a struct with methods on a receivertype Order { … }, its methods inside itRecords
interfaces met without saying soa type names the interfaces it implements: type Guard: DropInterfaces
(int, error) and if err != nil-> Int ! OrderError, and try to pass the error ontry
nilnone, only in a type that ends in ?Optionals
codes["WINTER"] gives 0 when it's missingcodes["WINTER"] is an Int?: you say ?? 0Reading a value
goroutinesspawn; a task never outlives the function that started itTasks Never Leak
channelschannels too: put and takeChannels
a garbage collectorno collector: a value is freed after its last useAutomatic Memory
a capital letter exports a namepub exports itpub
fmt.Printf("%d", n)print("{n}")Interpolation
go.modkavach.tomlPackages

Habits from other languages get a clear error that says what to write instead: see Habits from other languages.