Soppo: Golang with the Features It's Missing

fanf21 pts0 comments

Soppo

Soppo

Go, with the features it's missing.

Type safety and ergonomics, with full interop.

Take the tour

GitHub<br>Playground<br>Docs

Familiar syntax

Soppo uses Go syntax wherever possible. If you know Go, you<br>already know most of Soppo. Use any Go library directly,<br>keep your existing tooling, and introduce Soppo gradually<br>into existing projects.

package main

import (<br>"fmt"<br>"net/http"

func main() {<br>http.HandleFunc("/", handleHome)<br>http.HandleFunc("/hello", handleHello)

fmt.Println("Server starting on :8080")<br>http.ListenAndServe(":8080", nil)

Enums and pattern matching

Tagged unions with struct variants, and pattern matching<br>that ensures you handle every case. The compiler catches<br>missing branches before your code ever runs, so you can<br>refactor with confidence.

type Shape enum {<br>Circle struct { radius float64 }<br>Rectangle struct { width, height float64 }

func area(s Shape) float64 {<br>match s {<br>case Shape.Circle{radius: r}:<br>return 3.14159 * r * r<br>case Shape.Rectangle{width: w, height: h}:<br>return w * h

Error handling with ?

No more repetitive if err != nil blocks. The<br>? operator propagates errors concisely while<br>keeping error handling explicit and visible. Add custom<br>handling when you need it.

func processFile(path string) error {<br>// Propagate error directly<br>data := os.ReadFile(path) ?

// Custom handling with named error<br>result := parse(data) ? err {<br>return fmt.Errorf("parse failed: {err}")

fmt.Println("Processed {len(result)} items")<br>return nil

Nil safety

Nil pointer dereferences are a common source of runtime<br>panics in Go. Soppo tracks nilability at compile time, so<br>you catch these bugs before they reach production. After a<br>nil check, the type narrows automatically.

func findUser(id int) ?*User { // ? marks nilable<br>if id == 0 {<br>return nil<br>return &User{name: "Alice"}

func greet(id int) {<br>user := findUser(id)

if user != nil {<br>// user is *User here, not ?*User<br>fmt.Println("Hello {user.name}")

Clear error messages

When something goes wrong, Soppo tells you exactly what<br>happened and where. Error messages show the relevant code,<br>highlight the problem, and suggest how to fix it. Debugging<br>should be straightforward, not a guessing game.

× Non-exhaustive match<br>╭─[main.sop:11:5]<br>10 │ var message string<br>11 │ ╭─▶ match colour {<br>12 │ │ case Colour.Red:<br>13 │ │ message = "Stop"<br>14 │ │ case Colour.Yellow:<br>15 │ │ message = "Wait"<br>16 │ ├─▶ }<br>· ╰──── missing variants: Green<br>17 │ }<br>╰────<br>help: Ensure all enum variants are handled, or add a `default` case

Get started

The recommended way to install Soppo is through<br>SOPMOD, a version manager that handles installing, updating, and<br>switching between versions. It also manages Go, which Soppo<br>uses internally for compilation.

curl -fsSL https://soppolang.dev/install.sh | sh

Then add to your PATH and install:

export PATH="$HOME/.sopmod/bin:$PATH"

sopmod install sop latest

Or install just the sop binary using Cargo,<br>without SOPMOD (requires<br>Rust<br>and Go):

cargo install soppo

soppo user error case return install

Related Articles