solod (so) is a strict subset of Go that translates to regular C – with zero runtime, manual memory management, and source-level interop.
Main characteristics:
- Go in, C out. You write regular Go code and get readable C11 as output.
- Zero runtime. No garbage collection, no reference counting, no hidden allocations.
- Everything is stack-allocated by default. Heap is opt-in through the standard library.
- Native C Interop. Call So to C and C to So – no CGO, no overhead.
- Go tooling works out-of-the-box – syntax highlighting, LSP, linting, and “Go tests”.
So supports structures, methods, interfaces, slices, multiple returns and defers. To keep things simple, there are no channels, goroutines, closures, or generics.
The same goes for systems programming in C, but with Go’s syntax, type safety, and tooling.
Examples • Installation and Usage • Language Tour • StdLib • Playground • So by Example • Testing • Benchmarks • Compatibility • Design Principles • FAQ • Roadmap • Contributions
This go code is in one file main.go: :
package main
type Person struct {
Name string
Age int
Nums [3]int
}
func (p *Person) Sleep() int {
p.Age += 1
return p.Age
}
func main() {
p := Person{Name: "Alice", Age: 30}
p.Sleep()
println(p.Name, "is now", p.Age, "years old.")
p.Nums[0] = 42
println("1st lucky number is", p.Nums[0])
}
translates to header file main.h: :
#pragma once
#include "so/builtin/builtin.h"
typedef struct main_Person {
so_String Name;
so_int Age;
so_int Nums[3];
} main_Person;
so_int main_Person_Sleep(void* self);
as well as an implementation file main.c: :
#include "main.h"
so_int main_Person_Sleep(void* self) {
main_Person* p = (main_Person*)self;
p->Age += 1;
return p->Age;
}
int main(void) {
main_Person p = (main_Person){.Name = so_str("Alice"), .Age = 30};
main_Person_Sleep(&p);
so_println("%.*s %s %" PRId64 " %s", p.Name.len, p.Name.ptr, "is now", p.Age, "years old.");
p.Nums[0] = 42;
so_println("%s %" PRId64, "1st lucky number is", p.Nums[0]);
}
See more illustrative examples and learn about supported language features in the Language Tour.
So install command line tools:
go install solod.dev/cmd/so@latest
Create a new Go project and add the soloload dependency to use the So standard library:
go mod init example
go get solod.dev@latest
Write regular Go code, but use the So package instead of the standard Go package:
package main
import "solod.dev/so/math"
func main() {
ans := math.Sqrt(1764)
println("Hello, world! The answer is", int(ans))
}
Transpile from C:
so translate -o generated .
The translated C code will be saved in generated Directory.
You can also transpile to C and compile the code to binary in one step. It uses the C compiler specified by CC environment variable:
Or you can transpile, compile and run without saving the binary:
All commands work with Go modules, not with individual files (so run .No so run main.go).
Keep in mind that the sleeper is new, so it’s still a little rough around the edges.
To learn about So’s features and limitations, see a brief overview of the language.
So provides a growing set of high-level packages similar to Go’s stdlib, as well as low-level packages that wrap the libc API.
Try online without installing anything. You can run the code or view the translated C output.
If you prefer to learn by doing, try Practical Introduction to SO with annotated example programs.
Therefore it does not have its own testing framework. Since So code is valid Go code, you can use go test As you normally do. Plus, your tests can use all Go features because they are never transpiled.
The transpilation logic is covered by the So compiler’s own tests.
It really shines when it comes to C interop, but it’s also quite fast on regular Go code – usually equal to or faster than Go.
So C11 code is generated that depends on several GCC/Clang extensions:
- binary literal (
0b1010) in the generated code. - statement expression (
({...})) in macros. __attribute__((constructor))For package-level initialization.__auto_typeFor local type inference in generated code.__typeof__For type inference in generic macros.allocaFormake()and other dynamic stack allocations.
You can use gcc, clang, or zig cc To compile transpiled C code. MSVC is not supported.
Supported operating systems: Linux, macOS, and Windows (main language only).
So very opinionated. Simplicity is key. Heap allocations are clear. Strictly Go syntax.
Frequently Asked Questions
I’ve heard these many times, so it’s worth answering.
✅ Transpiler with basic Go features.
✅ Low-level stdlib (libc wrapper). That’s it for now; I will add more if needed.
⏳ Core stdlib packages: fmt, io, strings, time, …
⏳ Map.
⬜ Rigid Transpiler.
⬜ Real-world examples.
⬜ More stdlib packages: crypto, http, json, …
⬜ Full Windows support.
Bug fixes welcome. For anything other than bug fixes, please open an issue first to discuss your proposed changes. To prevent feature bloat, it’s important to discuss any new features before adding them.
AI-assisted submissions are OK on one condition: You, the human, have read all the code and fully understand what it does. Simply having the code reviewed by another AI will not suffice.
Be sure to add or update tests as needed.
Go stdlib code by Go authors.
Transpiler and so stdlib code by Anton Ziyanov.
Released under the BSD 3-clause license.
<a href