A modern, simple, and accessible programming language for .NET.
G# brings Go-, Kotlin-, and Swift-style ergonomics to the CLR. The
syntax stays small and predictable; the runtime is the same .NET you
already know, so every BCL type, NuGet package, and dotnet tool works
out of the box.
📖 Documentation: https://davidobando.github.io/gsharp/ — language
tour, tutorials, specification, and tooling reference. The site source
lives in website/.
A short tour of v0.2 idioms — the same ones the documentation site uses.
package GSharp.Tour.DataClass
import System
data class Person(Name string, Age int32)
let alice = Person("Alice", 30)
let older = alice with { Age = 31 }
let (n, a) = older
Console.WriteLine("$n is $a") // Alice is 31
Console.WriteLine(alice == older) // False — different Age
Console.WriteLine(alice == Person("Alice", 30)) // True — structural equality
data struct is the value-typed counterpart, with the same synthesized
equality, with-copy, and deconstruction.
package GSharp.Tour.IfLet
import System
func Greet(name string?) {
if let n = name {
Console.WriteLine("hi $n")
} else {
Console.WriteLine("hi stranger")
}
}
Greet("Ada")
Greet(nil)
guard let v = expr else { return } is the partner form: it binds v for
the remainder of the enclosing block when the value is non-nil, and the
else branch must unconditionally exit.
package GSharp.Tour.Sequences
import System
import Gsharp.Extensions.Sequences
for pair in Sequences.Range(1, 5).Indexed() {
Console.WriteLine("${pair.Item1}: ${pair.Item2}")
}
for trio in Sequences.Range(1, 6).Windowed(3) {
Console.WriteLine(String.Join(",", trio))
}
Sequences ships builders (Range, RangeStep, Iterate, Repeat,
Of, Empty), transformers (Indexed, Windowed, Chunked,
Pairwise, Interleave), safe terminals (FirstOrNil, LastOrNil,
SingleOrNil), and G#-shaped collectors (ToSlice, ToMap).
package GSharp.Tour.Optional
import System
import Gsharp.Extensions.Optional
let name string? = "ada"
let upper = name.Map((s string) -> s.ToUpper())
Console.WriteLine(upper ?: "<absent>") // ADA
let absent string? = nil
Console.WriteLine(absent.OrElse("default")) // default
let short = name.Filter((s string) -> s.Length <= 2)
Console.WriteLine(short ?: "<filtered out>") // <filtered out>
package GSharp.Tour.AsyncScope
import System
import System.Threading.Tasks
async func compute(n int32) int32 {
await Task.Delay(5)
return n * 2
}
async func runAll() {
let a = await compute(3)
let b = await compute(4)
Console.WriteLine("a = $a, b = $b")
}
scope {
runAll().Wait()
}
Console.WriteLine("done")
scope { ... } is the structured-concurrency block: child work
registered inside the scope is joined before control leaves it, and
failures are observed instead of silently lost.
G# ships an MSBuild SDK (Gsharp.NET.Sdk)
and a dotnet new template package (Gsharp.Templates),
both available on NuGet, so a .gsproj is just a regular .NET project
that happens to compile .gs files. After installing the template
package, you can scaffold and run a console app in three commands:
dotnet new install Gsharp.Templates
dotnet new gsharp-console -n MyApp
cd MyApp && dotnet build && dotnet run
# -> Hello from GSharp!A minimal .gsproj looks like any other modern .NET project:
<Project Sdk="Gsharp.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>MyApp</RootNamespace>
</PropertyGroup>
</Project>The SDK is validated against net8.0 and net10.0; adding additional
target frameworks is a one-line change in
e2etests/multitarget-e2e.sh.
The G# VS Code extension is published on the
Visual Studio Marketplace.
It provides syntax highlighting, language-server features (completion,
hover, diagnostics, formatting, and more), build/run commands, and
debugger configuration for .gs and .gsproj files. Install it from
within VS Code (search for "G#") or from the command line:
code --install-extension gsharplang.vscode-gsharpEvery .NET type — your packages, third-party NuGet packages, the BCL —
is callable from G# with the syntax you already know. CLR generics use
G#'s bracket spelling, and method calls, properties, indexers, and
for in over IEnumerable[T] all just work:
package GSharp.Tour.Interop
import System
import System.Collections.Generic
import System.Linq
let nums = List[int32]()
nums.Add(1)
nums.Add(2)
nums.Add(3)
nums.Add(4)
let evens = nums.Where((x int32) -> x % 2 == 0)
for v in evens {
Console.WriteLine(v)
}
Console.WriteLine(nums.Sum())
G# also speaks the unmanaged boundary directly. A func declaration
whose body is ; and that carries @DllImport or @LibraryImport
binds as a P/Invoke stub — no extern keyword needed:
package GSharp.Tour.PInvoke
import System
import System.Runtime.InteropServices
@DllImport("libc", EntryPoint: "strlen", CharSet: CharSet.Ansi)
func StrLen(text string) nint;
Console.WriteLine(StrLen("Hello, world!")) // 13
The full interop story — events, delegates, ref/out parameters, function pointers, struct marshalling — is documented in the CLR interop reference.
| Topic | Where |
|---|---|
| Live documentation site | https://davidobando.github.io/gsharp/ |
| A Tour of G# (start here) | website/docs/tour/ |
| Tutorials | website/docs/tutorials/ |
| Language guide | website/docs/guide/ |
| Language specification | website/docs/ref/spec.md |
| Architecture Decision Records | docs/adr/ |
| MSBuild SDK + templates | docs/sdk-usage.md |
| Compiler architecture | docs/emit-pipeline.md |
src/
Core/ # Shared front-end: syntax, binder, lowering, symbols, emit
Compiler/ # gsc.dll command-line driver
Interpreter/ # In-process evaluator (REPL + language tests)
LanguageServer/ # LSP server backing the editor experience
Sdk/
Gsharp.NET.Sdk/ # MSBuild SDK that wires .gsproj into dotnet build
Gsharp.Templates/ # dotnet new template package (gsharp-console)
Gsharp.Extensions/ # Opt-in idiomatic helpers (Optional, Sequences, Go)
samples/ # End-user fixtures referenced by docs and tests
e2etests/ # End-to-end smoke scripts: sdk-e2e, templates-e2e, multitarget-e2e
test/ # xUnit projects covering Core, Compiler, Interpreter, LSP
website/ # Docusaurus site (source for the docs above)
Contributions are welcome. Open an issue to discuss your idea before
sending a pull request — agreeing on the shape up front keeps the
review cycle short. The docs/ folder has the ADRs and design
notes that explain why specific decisions were made.