Skip to main content
Version: 0.1

G# for Go developers

G# is a Go-inspired language for .NET. You will recognize packages, func, defer, go, channels, select, for, and slices, but the type system and runtime are intentionally CLR-shaped.

Quick comparison

Go constructG# equivalentNotes
package mainpackage MyApp.CliPackages map to CLR namespaces rather than import paths.
import "fmt"import SystemImports bind CLR namespaces, G# packages, and aliases.
func main()top-level statements or func Main()SDK projects synthesize an entry point from top-level statements.
fmt.Println(x)Console.WriteLine(x)Use .NET library types directly.
var x intvar x int32 or var x int64G# uses width-bearing numeric names.
:=:=Short declarations are available where inference is possible.
[]T[]TSlices are backed by CLR arrays and support len, cap, and append.
[3]T[3]TFixed arrays carry the length in the type.
map[K]Vmap[K]V or Dictionary[K, V]CLR generic syntax uses brackets.
structstruct, data struct, record, or classG# also has CLR classes and structural data structs.
exported by Namepublic NameVisibility is explicit: public, private, or internal.
goroutine go f()go f()Scoped go joins through scope.
channel chan Tchan TLowered to System.Threading.Channels.
selectselectCases cover sends, receives, and default.
defer cleanup()defer cleanup()Defers run at block exit.
interface{}object or an interface typeCLR object identity and interfaces apply.
error returnsexceptions or result valuesG# interoperates with .NET exceptions.
generics func F[T any]func F[T](x T) TType parameters use bracket syntax without Go constraints.
automatic semicolonsnoneNewlines are significant in the grammar; do not rely on semicolon insertion.

Packages are CLR namespaces

In Go, the package clause and module path determine import identity. In G#, a file starts with package, and that package becomes the emitted CLR namespace:

package Inventory.Cli

import System

Console.WriteLine("inventory")

A single .gsproj can contain several packages and emit one assembly. That makes internal visibility assembly-scoped, just like C#.

Numbers name their width

Go's int has architecture-dependent width. G# makes width explicit in source: int8, int16, int32, int64, uint32, float32, float64, and friends. That keeps CLR signatures stable and avoids surprises when calling .NET APIs.

Visibility is not capitalization

Go exports identifiers by capitalization. G# uses explicit modifiers:

public class Customer {
private id string
internal func DebugId() string { return id }
}

This matches CLR metadata and lets PascalCase or camelCase be stylistic choices rather than access control.

Control flow is familiar, but switches do not fall through

G# keeps Go-shaped if, for, for in, switch, and select. Switch cases do not fall through. The fallthrough keyword is reserved only so the compiler can issue a clear diagnostic.

Generics and CLR interop use bracket syntax

Generic type and method arguments use brackets:

import System.Collections.Generic

let names = List[string]()
names.Add("gopher")

G# can construct CLR types, call methods and properties, subscribe to events, convert functions to delegates on the emit path, and use extension methods.

Exceptions are part of the platform

Go code normally returns error. G# can still model results explicitly, but imported .NET APIs throw exceptions. Use try, catch, finally, or using when you are working with APIs that follow .NET conventions.

Where to go next