Skip to content
Kavachकवच

Coming From Another Language: C++

● Beginner6 minBefore this: Coming From Another Language

From C++: native speed with no undefined behaviour, no manual memory, errors in the signature, and Drop where you would use RAII.

Here is one small program twice: in C++ 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.

#include <iostream>
#include <map>
#include <numeric>
#include <stdexcept>
#include <string>
#include <vector>

struct Order {
    std::string item;
    long qty;
    long cents;

    long cost() const { return qty * cents; }
};

struct BadQty : std::runtime_error {
    std::string item;
    explicit BadQty(const std::string& i) : std::runtime_error("no quantity for " + i), item(i) {}
};

long total(const std::vector<Order>& orders) {
    for (const auto& o : orders) {
        if (o.qty <= 0) throw BadQty(o.item);
    }
    return std::accumulate(orders.begin(), orders.end(), 0L,
                           [](long sum, const Order& o) { return sum + o.cost(); });
}

int main() {
    const std::map<std::string, long> codes{{"SPRING", 10}, {"VIP", 25}};
    const std::vector<Order> orders{{"pen", 3, 150}, {"cup", 1, 900}};

    long sum;
    try {
        sum = total(orders);
    } catch (const BadQty&) {
        sum = 0;
    }
    auto found = codes.find("SPRING");
    long off = found != codes.end() ? found->second : 0;
    std::cout << "total " << sum << ", with " << off << "% off " << sum * (100 - off) / 100 << "\n";
    auto winter = codes.find("WINTER");
    std::cout << "WINTER gives " << (winter != codes.end() ? winter->second : 0) << "%\n";

    const std::vector<Order> broken{{"kite", 0, 500}};
    try {
        long t = total(broken);
        std::cout << "total " << t << "\n";
    } catch (const BadQty& e) {
        std::cout << "refused: no quantity for " << e.item << "\n";
    }
}
orders.cpp: cpp 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 C++In KavachLearn it
a struct or class with methodstype Order { … }, its methods inside itRecords
inheritance and virtualinterfaces: a type says which ones it implementsInterfaces
exceptions, unseen in the signature! OrderError in the signature, and try or catch at each callErrors
nullptr, or find() against end()T?, and ?? 0 for when it's missingOptionals
new, delete and smart pointersno allocating or freeing: a value is freed after its last useAutomatic Memory
RAII destructorsDrop: drop runs when the block holding the value endsFreed immediately
signed overflow is undefined behaviouroverflow stops the program with a panicInt
v[5] past the end is undefined behaviourxs[5] panics; xs.get(5) gives noneReading by index
templatesgenerics: fn first<T>(items: [T]) -> T?Generics
std::thread and std::mutexspawn, and Shared<T> for what tasks change togetherShared State
headers and a build systemmodules with use, one kavach.toml, kavach buildModules
raw pointers anywhereraw memory only inside unsafe { … }Unsafe

The C++ version shows a trap of its own: std::cout << "total " << total(broken) prints total before total throws, so it is split into two statements.

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