BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Rust-Written Borgo Language Brings Algebraic Data Types and More to Go

Rust-Written Borgo Language Brings Algebraic Data Types and More to Go

Borgo is a statically typed language that compiles to Go and strives to be interoperable with the existing Go ecosystem. The Borgo language adds to Go algebraic data types, pattern matching, Option and Result types, and more Rust-inspired syntax. The Borgo’s compiler itself is implemented in Rust.

Borgo’s main contributor explained the key characteristics of Borgo as follows:

I want a language for writing applications that is more expressive than Go but less complex than Rust.

Go is simple and straightforward, but I often wish it offered more type safety. Rust is very nice to work with (at least for single-threaded code) but it’s too broad and complex, sometimes painfully so.

Borgo is a new language that transpiles to Go. It’s fully compatible with existing Go packages.

Borgo syntax is similar to Rust, with optional semi-colons.

Go quickly became popular with many developers due to its simplicity, efficiency, and handling of concurrency. Go’s design also favors fast compilation. As of May 2024, the language ranks in 8th place on the TIOBE index. However, developers are regularly pointing out the drawbacks of Go being by design a weakly typed language. Ian Lance Taylor, a key Go contributor, presents weak typing as a feature rather than a bug:

Go intentionally has a weak type system, and there are many restrictions that can be expressed in other languages but cannot be expressed in Go. Go in general encourages programming by writing code rather than programming by writing types.

Many experienced Go developers have however signaled interest in enriching the type system. One Reddit user for instance mentions:

  • Errors as values is nice, but a lack of a sum type hurts.
  • Lack of syntax sugar for returning errors leads to boilerplate.
  • Lack of proper typedefs means I can’t use type-safety as much as I would like.

Borgo’s language syntax seems heavily inspired by Rust and, while striving to maintain compatibility with existing Go libraries, Borgo adds key language features to Go. The following code illustrates Borgo’s algebraic data types and pattern matching:

use fmt

enum NetworkState<T> {
    Loading,
    Failed(int),
    Success(T),
}

struct Response {
    title: string,
    duration: int,
}

fn main() {
    let res = Response {
        title: "Hello world",
        duration: 0,
    }

    let state = NetworkState.Success(res)

    let msg = match state {
        NetworkState.Loading => "still loading",
        NetworkState.Failed(code) => fmt.Sprintf("Got error code: %d", code),
        NetworkState.Success(res) => res.title,
    }

    fmt.Println(msg)
}

The following code sample illustrates Borgo’s Rust-inspired Result and Option types ( strconv.Atoi returns an Option<int>
and Reader.ReadString returns a Result<string, error>):

use bufio
use fmt
use math.rand
use os
use strconv
use strings
use time

fn main() {
    let reader = bufio.NewReader(os.Stdin)

    let secret = rand.Intn(100) + 1

    loop {
        fmt.Println("Please input your guess.")

        let text = reader.ReadString('\n').Unwrap()
        let text = strings.TrimSpace(text)

        let guess = match strconv.Atoi(text) {
            Ok(n) => n,
            Err(_) => continue,
        }

        fmt.Println("You guessed: ", guess)

        if guess < secret {
            fmt.Println("Too small!")
        } else if guess > secret {
            fmt.Println("Too big!")
        } else {
            fmt.Println("Correct!")
            break
        }
    }
}

Borgo also allows error handling with the ? operator:

use fmt
use io
use os

fn copyFile(src: string, dst: string) -> Result<(), error> {
    let stat = os.Stat(src)?

    if !stat.Mode().IsRegular() {
        return Err(fmt.Errorf("%s is not a regular file", src))
    }

    let source = os.Open(src)?
    defer source.Close()

    let destination = os.Create(dst)?
    defer destination.Close()

    // ignore number of bytes copied
    let _ = io.Copy(destination, source)?

    Ok(())
}

As Borgo’s compiler is written in Rust, developers will need cargo to compile Borgo source files:

$ cargo run -- build

The compiler will generate .go files which can be run with the usual Go toolchain:

# generate a go.mod file if needed
# $ go mod init foo
$ go run .

Recent reactions from developers on Reddit have been generally positive with one developer saying:

This addresses pretty much all of my least favorite things with writing Go code at work, and I hope–at the very least–the overwhelming positivity (by HN standards – even considering the typical Rust bias!) of the responses inspires Go maintainers to consider/prioritize some of these features.

The full list of Borgo’s language features can be found in the online documentation together with Borgo’s playground.

About the Author

Rate this Article

Adoption
Style

BT