
Go that escaped.
Features • Quick Start • Examples • Status • Roadmap • Contributing
At a Glance
Sum Types: Working | Pattern Matching: Working | Error Propagation: Working | Tuples: Working | Safe Navigation: Working | Playground for Go's Future | v1.0 Target: Q1 2026
You know that feeling when you're writing Go and you type if err != nil for the 47th time in a single file?
Or when you forget to check for nil and your production server learns what a panic feels like?
Or when you're explaining to a Rust developer why Go doesn't have sum types and they look at you like you just said "we don't believe in seatbelts"?
Yeah. That's why Dingo exists.
Think TypeScript, but for Go.
Dingo is a language that compiles to clean, idiomatic Go code. Not some franken-runtime or a whole new ecosystem. Just better syntax that becomes regular Go.
The pitch: Write code with Result types, pattern matching, and null safety. Get back perfect Go code that your team can read, your tools can process, and your production servers can run at exactly the same speed.
Zero runtime overhead. Zero new dependencies. Zero "what's this weird thing in my transpiled code?"
Is this proven to work? Yes. Borgo (4.5k stars) already proved you can transpile to Go successfully. Dingo builds on that foundation with better IDE integration, source maps, and a pure Go implementation.
Ever wonder what a dingo actually is?
Thousands of years ago, they were domesticated dogs. Well-behaved. Following commands. Controlled.
Then they escaped to the Australian wild and evolved into something science couldn't categorize. Not quite dog. Not quite wolf. Ungovernable.
The Go Gopher? Created at Google. Lives by the rules. Does what it's told.
Dingo broke free.
Here's the beautiful part: dingos are still canines. They didn't reject their DNA—they just refused to be controlled. Same with our language.
Every Go feature still works. Go 1.24 adds something? You get it in Dingo. Day one. Disable all plugins? You're running pure Go.
You're not losing anything. You're gaining freedom without asking permission.
Want pattern matching? Enable it. Want sum types? Already working. Think you can do it better? Fork the plugin and prove it.
Your language. Your rules. No committee required.
See MANIFESTO.md for why this terrifies the establishment.
Note: Dingo is in active development. Phase 10 Complete - Full LSP integration with gopls proxy, auto-rebuild on save, and comprehensive IDE support.
Latest (2025-12-09): ✅ Tuples & Documentation Update - Tuple type support (Phase 8) complete with destructuring, multi-return functions, and Option/Result integration. Golden tests updated to use current API patterns (.MustSome(), .MustOk() methods). See CHANGELOG.md for details.
# Clone the repository
git clone https://github.com/MadAppGang/dingo.git
cd dingo
# Build the compiler
go build -o dingo ./cmd/dingo
# Add to PATH (optional)
export PATH=$PATH:$(pwd)
Create hello.dingo:
package main
import "fmt"
func main() {
message := "Hello from Dingo!"
fmt.Println(message)
}
Build and run:
# Transpile to Go and compile to binary (like go build)
dingo build hello.dingo
# Transpile and run immediately (like go run)
dingo run hello.dingo
# Transpile to Go only (generates .go files without compiling)
dingo go hello.dingo
Sum Types with Pattern Matching:
enum Result {
Ok(value: int),
Error(message: string)
}
func divide(a: int, b: int) Result {
if b == 0 {
return Error("division by zero")
}
return Ok(a / b)
}
result := divide(10, 2)
match result {
Ok(value) => fmt.Printf("Success: %d\n", value),
Error(msg) => fmt.Printf("Error: %s\n", msg)
}
Safe Navigation and Null Coalescing (Phase 7 ✅):
// Property access with safe navigation
city := user?.address?.city?.name ?? "Unknown"
// Method calls with safe navigation
email := user?.getProfile()?.email ?? "noreply@example.com"
// Works with Go pointers too!
timeout := config?.database?.timeout ?? 30
// Chained defaults
theme := user?.theme ?? project?.theme ?? global?.theme ?? "light"
Functional Utilities:
numbers := []int{1, 2, 3, 4, 5}
doubled := numbers.map(func(x int) int { return x * 2 })
evens := numbers.filter(func(x int) bool { return x % 2 == 0 })
sum := numbers.reduce(0, func(acc int, x int) int { return acc + x })
See examples/ and docs/features/ for more working code.
| ### The Go Pain Points - **47 `if err != nil` blocks** per file - **Nil pointer panics** in production - **No sum types** after 15 years of requests - **Verbose error handling** drowning business logic - **No null safety** operators - **Boilerplate enums** requiring manual type guards | ### The Dingo Solution - **`?` operator** propagates errors cleanly - **`Option`** makes nil checks compile-time safe - **`enum` keyword** with full sum type support - **Pattern matching** with exhaustiveness checking - **`?.` and `??`** for safe navigation and null coalescing - **Zero overhead** - transpiles to clean Go |
Key Insight: Dingo doesn't change Go. It transpiles to it. Your team gets modern ergonomics, your production gets pure Go performance.
Here's what makes Dingo special — you get two massive benefits simultaneously:
This is why you'll actually use Dingo:
? operator instead of 47 if err != nil blocksYour code becomes cleaner, safer, and more maintainable. Immediately.
This is the selfish reason to use Dingo. And it's a damn good reason.
Here's the beautiful part you get for free:
While you're using Dingo to make YOUR code better, you're automatically contributing to Go's evolution:
You don't have to think about this. It just happens.
Developers didn't adopt TypeScript to "help JavaScript evolve."
They adopted it because it made their codebases better.
Developers used TypeScript selfishly. JavaScript evolved as a natural consequence.
Same thing is happening with Dingo and Go:
You're not doing charity work. You're writing better code. Helping Go evolve is just a happy side effect.
For decades, programming language evolution has been broken:
❌ The old way: Community → Proposal → Years of debate → Maybe no → Frustration
✅ The Dingo way: Developers → Use features → Data emerges → Go team decides with evidence
This is how TypeScript revolutionized JavaScript. Not through proposals, but through proving ideas in production.
🎯 You win: Better code today, zero waiting 🎯 Go team wins: Real data for decisions, reduced risk 🎯 Go ecosystem wins: Faster evolution, battle-tested features
Example: Sum Types
Imagine if before Go Proposal #19412 (sum types - 996+ 👍 but rejected), there was: - ✅ 50,000 developers using it for 2 years - ✅ Concrete metrics: 78% code reduction - ✅ Known edge cases documented - ✅ Production validation across 5,000+ projects
The proposal would have been impossible to reject with that evidence.
That's what Dingo enables. Every feature you use contributes data that could reshape Go's future.
Here's what actually happened with TypeScript and JavaScript:
| Feature | TypeScript Added | Developers Used It | JavaScript Adopted | Timeline |
|---|---|---|---|---|
| Async/Await | 2015 | Millions of codebases | ES2017 | 2 years |
| Optional Chaining | 2019 | Massive adoption | ES2020 | 1 year |
| Nullish Coalescing | 2019 | Widespread use | ES2020 | 1 year |
| Class Fields | 2017 | Standard in TS code | ES2022 | 5 years |
| Decorators | 2015 | Widely used | Stage 3 proposal | Still evolving |
Notice the pattern: 1. TypeScript adds feature 2. Developers use it (for selfish reasons - better code) 3. Real-world data proves it works 4. JavaScript adopts it with evidence-based confidence
Dingo enables the exact same cycle for Go.
You're not choosing between "make my code better" OR "help Go evolve."
You get both. Automatically. Simultaneously.
Here's what the Go community has been begging for since 2009:
| What developers want | How badly | What Dingo gives you |
|---|---|---|
Stop typing if err != nil every 3 lines |
⭐⭐⭐⭐⭐ | Result<T, E> + the ? operator |
| Stop shipping nil pointer panics | ⭐⭐⭐⭐⭐ | Option<T> type that the compiler actually checks |
| Sum types (seriously, it's been 15 years) | ⭐⭐⭐⭐⭐ 996+ 👍 | enum with pattern matching |
| Enums that can't be invalid | ⭐⭐⭐⭐⭐ 900+ 👍 | Type-safe enums with exhaustiveness |
| Lambda functions that don't take 4 lines | ⭐⭐⭐⭐ 750+ 👍 | \|x\| x * 2 like a normal language |
The Go team has valid reasons for rejecting these features. They're not wrong about simplicity.
But here's the thing: Dingo doesn't change Go. We just compile to it.
Want sum types? Great. They become tagged structs in Go.
Want the ? operator? Cool. It becomes if err != nil checks.
Want pattern matching? Done. It's a switch statement underneath.
Your Go code stays pure. Your Dingo code stays sane.
Fair enough.
| Metric | Traditional Go | With Dingo | Savings |
|---|---|---|---|
| Sum Type Definition | 33 lines | 7 lines | 79% less code |
| Enum with Data | 46 lines | 10 lines | 78% less code |
| Error Handling Pipeline | 85 lines | 28 lines | 67% less code |
| API Handler | 42 lines | 15 lines | 64% less code |
All numbers from real examples in our test suite
What you write in Go today:
func processOrder(orderID string) (*Order, error) {
order, err := fetchOrder(orderID)
if err != nil {
return nil, fmt.Errorf("fetch failed: %w", err)
}
validated, err := validateOrder(order)
if err != nil {
return nil, fmt.Errorf("validation failed: %w", err)
}
payment, err := processPayment(validated)
if err != nil {
return nil, fmt.Errorf("payment failed: %w", err)
}
return payment, nil
}
75% of this function is error handling ceremony. The actual logic is hiding somewhere in there.
What you write in Dingo:
func processOrder(orderID: string) -> Result<Order, Error> {
order := fetchOrder(orderID)?
validated := validateOrder(order)?
payment := processPayment(validated)?
return Ok(payment)
}
Same safety. Same error handling. 60% less code.
The ? just means "if this is an error, return it. Otherwise, unwrap the value and keep going." That's it. That's the entire feature.
Rust developers have been using this for 8 years. They love it so much they put it on t-shirts.
These are actual examples from Dingo's test suite that transpile and run today.
**What You Write (Dingo)**
|
**What You Get (Generated Go)** ```go pa |
$ claude mcp add dingo \
-- python -m otcore.mcp_server <graph>