Release notes
G# is pre-1.0. The repository's version base is currently 0.4, and product versions are derived by Nerdbank.GitVersioning from that base and the Git commit. Until the project reaches a stable compatibility promise, release notes should be read as implementation status notes rather than a long-term compatibility contract.
Unreleased (0.5 line)
Breaking changes
chan Tis respelledchan[T](ADR-0174 D2). The element type moves inside brackets likesequence[T]andmap[K, V];in chan[T]/out chan[T]are the receive-only / send-only handles (ChannelReader<T>/ChannelWriter<T>),chan[T]?is a nullable channel andchan[T?]a channel of nullable — the(chan T)?grouping carve-out is gone. The legacy spelling is rejected withGS0567, which names the exact replacement.make(chan T[, n])is retired in favour ofchan[T]()(rendezvous — capacity 0, Go's unbuffered channel),chan[T](n), andChan.Unbounded[T]()(the wave-1 behavior ofmake(chan T), now named).GS0566names the replacement per site; note the semantic change for the no-capacity form.close(ch)is retired in favour of the memberch.Close()(GS0566). Closing twice throws (Go's panic);Dispose()is the idempotent close, sousing letworks.len(ch)/cap(ch)becomech.Length()/ch.Capacityon a channel you constructed.- Receiving from a closed channel no longer raises and swallows
ChannelClosedException— the zero value is delivered directly (about 400× faster on that path). import Gsharp.Extensions.Gois gone (ADR-0174 D13): the concurrency syntax is the language, the namespace and its marker type are deleted, and the gate diagnosticsGS0316/GS0317are retired. The concurrency library lives in the implicitly importedGsharp.Concurrencynamespace (/noimplicitimportsdisables it).len,cap,append, anddeleteare retired (ADR-0174 D13). A call reportsGS0566naming the member replacement for that site:xs.Length,m.Count,m.Remove(k),ch.Length()/ch.Capacity;appendhas no member spelling — a slice is a fixed CLR array, so keep a growableList[T]and.Add;capon a slice is removed outright (its capacity was its length). A user-defined function of the same name is an ordinary call.
Added
Gsharp.Runtime.Channels: a C#-authored channel runtime bundled with the SDK (tools/channels/) and auto-referenced by every project.Chan<T>is a rendezvous-capableChannel<T>subclass with Go-exact close semantics, a two-value receive, batch transfer, and the transactionalselectwaiter protocol;gsccopies it beside an emitted program that references it.- Directional channel types and the D2 operation matrix: foreign BCL channels, readers, and writers flow into
chan[T]/in chan[T]/out chan[T]with no adapter. GS0548(advisory:chan[T]()is a rendezvous channel),GS0549/GS0550(send/receive through the wrong directional handle),GS0554(a channel-receive binding form with the wrong number of targets),GS0555(while let v = chwhere a receive was meant).go { … }(ADR-0174 D14): the block form ofgospawns the block as a goroutine, capturing the enclosing locals (per iteration for afor … invariable) —go func() { … }()without the ceremony.scopeis completed (ADR-0174 D5/D6): everygoinside a scope reports to the scope's frame (noTaskper goroutine); the block binds an implicitctx(Gsharp.Concurrency.Context) that the first goroutine failure cancels promptly; exit follows the documented precedence table (ScopeExceptionwith the cause first, a failing body rethrown unwrapped) and, inside a suspending function, is awaited rather than blocked. A nested scope'sctxis linked to the enclosing one (ctx.Parent), andreturnfrom inside a scope still counts as returning on every path. A freegooutside any scope is fail-fast on an unhandled exception (GoroutineRuntime.UnhandledGoroutineExceptionto observe).- A small concurrency library (ADR-0174 D9):
after(d)andtick(d)are selectable timers —case <-after(d)is the timeout arm, and a select receive arm now accepts anything selectable, not only a channel — andmerge(a, b, …)fans several channels into one receive-only channel that closes when the last input does. They live in the implicitly importedGsharp.Concurrencynamespace and are called by bare name; a program that declares its ownafterkeeps its own. - Batch channel operations and
chunks(ADR-0174 D10). A channel handle gainsTryReceiveBatch/TrySendBatch(aSpan[T], never waits) andReceiveBatch/SendBatch(aMemory[T], can park — a destination that survives a park cannot be ref-like).chunks(ch, n)reads a channel in batches:for batch in chunks(input, 1024)is ordinary channel iteration wherebatchis aReadOnlyMemory[T]that the receiver owns, so one lock acquisition and one park are amortized across the batch. A batch cut short by a close or a cancellation returns the count it moved rather than throwing, so a retry cannot duplicate elements.GS0562warns when the channel is a rendezvous, where batching is correct but pointless. async let(ADR-0174 D15):async let name = exprstartsexpras a child of the enclosingscopeand bindsnameto its eventual result, read asawait name. Both children of twoasync letbindings run concurrently; the binding is a value of typeR, never a handle, so a spawn cannot outlive the block that owns it. A binding you never read has its child cancelled and joined at block exit, and a failure nobody read still reaches the block'sScopeExceptionrather than being dropped; a failing child does not cancel its siblings. New diagnostics:GS0551(no enclosingscope),GS0559(never awaited),GS0569(read withoutawait).- Three more
selectarm shapes (ADR-0174 D8). Every arm may carry awhenguard, evaluated once when the select is entered; a false guard keeps its arm out of the select entirely, which is how G# spells Go's "set the channel tonilto disable this case".case await taskandcase let v = await tasklet aTaskorTask[T]race the channels on the same waiter.case cancelledreplaces Go'scase <-ctx.Done(): the ambient context's cancellation becomes an arm instead of an unwind. New diagnostics:GS0556(a guard that is not abool),GS0557(acancelledarm with no context to observe, so it would be unreachable), andGS0564(one channel both sent to and received from by the same select). Cancellation also now reaches aselectwritten in a callee with noscopeof its own, through the caller's context. selectis rebuilt on one registered waiter (ADR-0174 D8): arms are attempted in uniform-random order like Go's, so two ready arms are both chosen instead of the first one written always winning; a select with no ready arm registers on every arm at once and parks the state machine rather than blocking a thread onTask.WhenAny; and winning is the transfer, so a value can no longer be stolen between choosing an arm and running it. Aselectinside a cancelledscopeunwinds.- Cancellation unwinds parked channel operations (ADR-0174 D7): a receive, send, or channel loop inside a
scopeparks on that block'sctx, so the first goroutine failure collapses siblings that are waiting on a channel instead of leaving them parked. An operation that already committed keeps its value — cancellation wins only before the transfer. Hosts can retune the budgets and observe the diagnostics throughGsharp.Concurrency.GsharpRuntime(DeferGraceBudget,ScopeStallTimeout,DeferGraceExpired,ScopeStalled). Cancellation crosses calls: a suspending function receives the caller's context as a trailing optional parameter, so an operation inside a callee unwinds with the caller's scope. Declaringctx Contextin a signature uses that parameter instead, and a C# consumer calls the signature as written or passes aContextexplicitly. defercleanup is shielded (ADR-0174 D7): a deferred body runs under a cancellation-immune context, so cleanup that drains a channel or signals completion still runs while the block around it unwinds. A grace budget bounds it (GSHARP_DEFER_GRACE_MS, five seconds by default) so cleanup cannot hold cancellation up forever;GsharpRuntime.DeferGraceExpiredreports an abandoned one. Cleanup outside any scope costs nothing.- Suspension is inferred (ADR-0174 D4): a plain
functhat performs a channel operation, or calls a function that suspends, is compiled as a suspending function — aValueTask[R]state machine labelled[Suspending]— with no keyword, as a fixed point over the call graph. Go-shaped pipelines keep their shape and stop holding threads. Inference stops atasync func,open/override/abstract methods, interface members and their implementations, constructors, accessors, operators, P/Invoke, iterators,Dispose, and function literals; a call to a suspending function from one of those blocks through the runtime's root bridge and warns withGS0558. Every emitted G# method that suspends now returnsValueTask/ValueTask[R]instead ofR— a binary change for C# callers of such functions. suspend func(ADR-0174 D4, the declared form): a suspending function compiles to aValueTask[R]-returning state machine on the pooling builder, carries[Suspending], and is awaited implicitly by every G# call site — callers writelet v = take(ch)and seeR; an explicitawait take(ch)is accepted as the same thing. From a function that is neither suspending norasyncthe call blocks the thread andGS0558warns; the entry point is the silent root. Inference of suspension for plainfuncfollows in a later step of Phase 3.- Debugging through suspension (ADR-0174 P3-8): every async or suspending kickoff carries
[AsyncStateMachine]and[DebuggerStepThrough], soEnvironment.StackTraceand debuggers name the logical function instead of<f>d__1.MoveNext, and the Portable PDB carries the async-method-stepping blob (yield/resume offsets per await) that lets a debugger step over a parked channel receive onto the next source line. Fixed: bodies rewritten by the compiler — everyasync funcbody, and now every suspending one — carried no line information at all, so breakpoints inside them never bound; each source line of such a body now maps into the state machine. - Channel operations inside an
async funcsuspend instead of blocking (ADR-0174 D4, first step): a receive, two-value receive, send,for v in ch, orwhile let v = <-chin anasync func(or async lambda /async sequence) parks the state machine, not a thread — hundreds of parked receives no longer pin thread-pool threads. A channel operation inside alockbody keeps the blocking lowering (the monitor is thread-affine). - Observable completion (ADR-0174 D3): the two-value receive
let (v, ok) = <-ch(orv, ok = <-ch) distinguishes a delivered zero value from a closed channel;while let v = <-ch { … }andfor v in ch { … }loop until the channel is closed. Achan[T?]element that isnilis delivered, not mistaken for close.
0.4
The fourth pre-1.0 line focuses on sound defaults, expressive control flow, and faithful CLR interop. Collection zero values are now usable without hidden nulls, pattern matching works directly in boolean and loop conditions, rectangular CLR arrays have native syntax, and explicit extension receivers preserve extension semantics for owned types and enums. Tooling adds synchronized-map support, clearer REPL display, and dotnet watch hot reload.
Highlights
- Sound collection zero values. Initializer-less maps, slices, fixed arrays, rectangular arrays, and sequences receive usable empty instances, including collection fields nested through structs. Channels remain explicit: globals and fields require
make(chan T), while locals use definite-assignment analysis and nullable channels use(chan T)?. - Richer conditions and blocks. Boolean
isaccepts the full pattern grammar, including constant, type, property, relational, list, and composed patterns.while letintroduces a narrowed, body-scoped binding that is re-evaluated before each iteration. General block expressions can contain declarations and statements before their trailing value. - Native rectangular arrays.
[,]T,[,,]T, and higher ranks preserve CLR type identity.[rows, columns]Tallocates storage, flat initializers use row-major order, anda[i, j]supports reads, writes, compound assignment, address-taking, null-conditional access, iteration, and interop. - Cleaner extension declarations.
func extension (receiver T) Name()explicitly declares an extension for an owned type or enum without turning it into an instance member. - Migration fidelity.
cs2gsnow emits native block expressions, rectangular arrays, multi-target storage assignment,if let/while letbindings, nativeispattern variables, explicit extensions, and value-position assignments instead of synthetic spill-heavy rewrites.
Added
- Full patterns in
value is patternandvalue !is pattern, with type-plus-property composition and narrowed right-handandpatterns. - Pattern variables in boolean
is(ADR-0166):value is string text && text.Length > 3,value is { Length: > 0 } text,box is { Value: Dog d },values is [1, ..rest], and the guard idiomif !(value is string text) { return }followed by uses oftext. Variables are scoped to the regions where the match is known to have happened;Type namedesignations are also accepted inswitcharms.cs2gspreserves C#ispattern syntax and names for these shapes instead of hoisting__spillNtemporaries. while let name = nullableExpression { ... }, including multiple bindings and normal labeledbreak/continuebehavior.- General value-producing block expressions such as
{ let x = compute(); x + 1 }. - Native rectangular array types, allocation, initialization, indexing, iteration, nullable forms, metadata, and expression-tree support.
- Explicit extension receiver clauses through
func extension. - Map iteration through
for key, value in maporfor entry in map. Gsharp.Extensions.Sync.SyncMap[K,V]for goroutine-safe shared maps with atomicUpdate.- Structural display of plain user values in the REPL while preserving their emitted CLR
ToStringbehavior. dotnet watchhot reload for SDK projects.
Changed
- The
asoperator now has nullable result typeT?; useif let, keep the nullable value, or apply!!when a prior check guarantees success. - The deprecated
name = valuenamed-argument spelling is removed. Usename: value;=in an argument is an ordinary assignment expression. - Multi-target assignment accepts all writable storage forms, including fields, properties, indexed elements, nested members, and pointer dereferences.
- Nil comparison is available for every reference-backed built-in type. Comparisons against bare non-null collection types are diagnosed as statically constant.
- Legacy
print,input, andrndbuilt-ins and thestring(T)conversion are removed; use CLR APIs and explicit formatting/conversion methods. - The website specification, guides, tutorials, feature matrix, diagnostics catalogue, bridges, and tooling pages now describe the complete 0.4 surface without implementation-tracker references outside the design-decision index.
- The Docusaurus site cuts a new
0.4snapshot from the live docs. The version dropdown lists0.4,0.3, andNext.
Fixed
- Generic delegate, enclosing-generic, function-pointer, method-group, map, imported override, XML documentation, channel capture, boxing, and tuple-return emission now preserve the source type and storage semantics across compilation boundaries.
- Null-conditional delegate invocation, nullable-flow analysis, rejected-call diagnostics, interpolation spans, and source-migration output are aligned with the emitted behavior.
Known limitations
- A non-empty rectangular-array initializer requires constant non-negative dimensions and a flat row-major element list.
- Pattern variables introduced by a boolean
ispattern (value is string text, ADR-0166) are read-only and are in scope only where their match is known to have happened; C# forms that rely on full definite-assignment data flow (for example a variable read after awhilewhose exit depends on the pattern) reportGS0532.
0.3
The third pre-1.0 line is a breadth-and-interop release. The language gains a large batch of C#-parity expression and declaration constructs, an unsafe pointer surface, partial types, and anonymous-object literals. Tooling adds the cs2gs C#→G# migration tool and the gsgen Roslyn source-generator host for native G# projects. The language server gains incremental binding, an incremental semantic-model pipeline, and a cross-session cold-start cache. This release also cuts a fresh 0.3 docs snapshot from the live docs and retires the 0.2 snapshot.
Highlights
- Unsafe pointer surface. An
unsafecontext now supports unmanaged raw pointers*T,stackalloc [n]Tproducing either safeSpan[T]or unsafe*Tstorage, thefixedpinning statement, theunmanagedtype-parameter constraint,sizeof(T), and pointer compound-assignment and cast lowering. - New expression and statement forms. Throw expressions, value-producing increment and decrement expressions
++/--, from-end indexes^n, standaloneSystem.Rangevalues such as1..3, expression-bodied members via->, generalgoto/ labels, collection initializersList[T]{…}/HashSet[T]{…}/Dictionary[K,V]{…}, and inferred-type arrow lambdas with statement-block bodies. - New declaration forms.
partialclasses, structs, and interfaces; anonymous-object literalsobject { … }; nested type declarations; user-defined conversion operatorsoperator implicit/operator explicit; user indexer membersprop this[i int32] T { get; set }; theshared { init { … } }static-initializer block; static imports throughimport Ns.Type; and top-levelprivatemapping to ILassembly/ internal. cs2gsC#→G# migration. The new translator lowers C# source to canonical G#, with construct coverage, gap triage, and a build-time strategy that reproduces generated code rather than freezing it. See the new cs2gs tooling page.- Source generators for native G#. The
gsgenhost runs Roslyn analyzers and generators against native G# projects.gsc /analyzer:<asm>spawnsgsgenas a sibling before compiling. A shared resx codebehind generator emitsResources.Designer.gs. - Language-server performance. Incremental binding, instance-keyed semantic-model memoization, a cross-session cold-start cache, completion-as-you-type triggering, and unified member resolution reduce repeated work across binder and LSP flows.
- Diagnostics catalogue extended. v0.3 adds diagnostics through the
GS04xxrange. The Diagnostics reference is reconciled against the compiler source and lists the current per-ID cause and fix detail.
Added
- Null-coalescing operator respelled
??. The null-coalescing operator isa ?? b. The earlier?:spelling is retired in that role;cond ? a : bremains the ternary expression. - Runtime array allocation
[n]T. A length-bearing[n]Tallocates a zero-initialised array at runtime, complementing array literals. - Nullable array-element spelling.
[]T?is an array of nullable elements;[]?Tis a nullable array. - Nullable function-type spelling. Nullable function types are spelled and displayed with the appropriate parenthesisation.
- Expression-tree lambda conversions. A lambda converts to
Expression[TDelegate]where the target demands an expression tree. - Delegate return-type covariance. Delegate return types can be covariant, including lambda target-typing on CLR method calls.
- Predefined type aliases as static-member receivers. Friendly numeric aliases can be used as receivers for static member access.
- Assembly-attribute parity with C#. Assembly-level attributes are accepted with C#-equivalent behavior.
- Collection spreads. Array, slice, and CLR collection initializers accept
...source, preserving lexical evaluation order and applying ordinary element conversions. - Safe structural projections. Compatible public object shapes project into safely constructible concrete targets;
Target{ ...source, Member: override }provides explicit object-spread mapping. - Explicit interface qualifier clauses. Methods, properties, indexers, events, and static interface members can use
(IFace)to provide distinct implementations without source-visible mangled names. - User-defined compound-assignment operators. Classes and structs can declare in-place
operator +=and related one-operand, void-returning instance operators.
Changed
- C#-compatible numeric conversions. Numeric literal narrowing and widening, plus implicit numeric promotion at call sites, now align with C# behavior.
- Unannotated imported reference types are nullable by default. Imported reference types without nullable annotations bind as nullable.
charbitwise and shift operators promote toint32. Enum==/!=comparisons against the integer literal0are also permitted.- The website spec, feature matrix, diagnostics reference, CLR-interop reference, guides, tour, tutorials, and tooling docs were refreshed to match compiler ground truth for the 0.3 surface; a new
cs2gstooling page was added. - The Docusaurus site cuts a new
0.3snapshot from the live docs and retires the0.2snapshot. The version dropdown lists0.3andNext.
Fixed
- Extensive
cs2gstranslator hardening across nullability promotion, extension-call lowering, deconstruction and indexer targets, pattern binding, named-argument lowering, and source-generator-shaped constructs. - Numerous
gscbinder, emitter, and interpreter correctness fixes across imported generic interface methods, nullable value-tuple boxing,data classequality andwith, overload resolution, async lambda inference, and smart-cast narrowing.
Known limitations
gsc --helpadvertises/implicitimports[+|-]; the+/-suffix form is not currently accepted by the Release parser. Use/noimplicitimports.- Migration coverage in
cs2gsis still expanding. C# source generators are reproduced at build time rather than translated, and some constructs remain on the gap-triage backlog.
0.2
The second pre-1.0 line is a syntax-and-ergonomics release. The parser, binder, and emitter absorb substantial additions; several legacy Go-flavored spellings are retired in favour of canonical G# forms; and the native-interop and default-interface-method surfaces ship end-to-end. This release also formally introduces docs versioning: the 0.1 snapshot is removed and a fresh 0.2 snapshot is cut from the live docs.
Highlights
- New language surface.
while/do…whileloops with labeledbreak/continue;if let/guard let/while letsmart-cast bindings; null-coalescing compound assignment??=; null-conditional indexinga?[i]; arrow lambdasx => body; canonical(T1, T2) -> Rfunction-type clauses; lambda binding-type inference; Kotlin/Swift-style type-declaration grammar; if-as-expression completion; smart-cast extensions; discriminated-union enum payloads;default(T)and target-typed baredefault; variadic...Tparameters in function and anonymous function-type clauses;class/struct/init()constraint flag spellings; default-interface methods; reified generics;Gsharp.Extensions.OptionalandGsharp.Extensions.Sequences; friendly numeric type aliases; and the canonical map type clausemap[K,V]. - Removals and migrations. Legacy spellings now produce focused, span-accurate diagnostics with canonical replacements so IDE quick-fixes can patch most migrations in one edit.
typekeyword for type declarations (type Foo struct { … }→struct Foo { … }).recordkeyword, replaced bydata classordata struct.:=short variable declaration, replaced bylet/var, with diagnosticGS0305.name = valuenamed-argument separator, replaced byname: value, with diagnosticGS0315.func(T) Rlegacy function-type clause, replaced by(T) -> R, with diagnosticGS0303.- Go-flavored
map[K]Vtype clause, replaced bymap[K,V], with diagnosticGS0366. static funcon interface methods is removed. Static-virtual interface members now live inside the interfaceshared { … }block. A body-lessfuncinside that block is an abstract static-virtual slot; afuncwith a body is the default. Static private helpers also move into theshared { … }block asprivate func, while instance private helpers stay directly in the interface body. The oldstatic func …shape now produces a parser error, andGS0330fires when a non-funcmember appears inside an interfaceshared { … }block.
- Body-less
funcnow requires;. Afuncdeclaration without a{ … }block is terminated by the universal no-body marker;. This already held for P/Invoke (func getpid() int32;) and now also applies to abstract interface methods and abstract static-virtual slots inside an interfaceshared { … }block. A body-less interfacefuncmissing its;reportsGS0368; afunccarrying a body still takes no;. - Native interop end-to-end. P/Invoke via
@DllImport, source-generator-shaped@LibraryImport, struct and class marshalling,ref/out/inparameter marshalling, function-pointer marshalling, and@MarshalAsparameter overrides are supported. - Go-flavored concurrency moved behind an opt-in import.
go,chan,select, channel send and receive,make(chan T), and the built-inslen,cap,append,make, anddeletenow requireimport Gsharp.Extensions.Go. DiagnosticsGS0316/GS0317point at the missing import. - Tooling polish. LSP completion understands async-shaped types such as
async (T) -> Randasync sequence[T];textDocument/codeActionoffers nil-related quick fixes; andnullnow produces anil"did you mean" diagnosticGS0273. - Diagnostics catalogue extended. v0.2 introduces
GS0273andGS0288–GS0366. The Diagnostics reference has the per-ID cause and fix detail.
Added
- Friendly numeric type aliases.
int,uint,long,ulong,short,ushort,byte,sbyte,float, anddoubleare accepted everywhere a type name is accepted, as a strict superset on top of the canonical width-bearing names (int32,uint32, …). The alias resolves to the canonicalTypeSymbolat the binder, so diagnostics,typeof,nameof, hover, and emitted IL always print the canonical spelling. Canonical names remain preferred in documentation and public library APIs; aliases are appropriate inside function bodies and local code. Aliases are reserved type names, sotype int = stringand equivalents are rejected withGS0102. - Null-conditional indexing
a?[i].a?[i]evaluates receiveraexactly once. If it isnil, the whole expression yieldsnil; otherwise the result is the indexed value lifted to the nullable form of the indexer's return type. It works on arrays, slices, maps, and CLR indexers on both emit and interpreter paths. Chained forms (h?.Data?[i]?.c) short-circuit on the first nil. The new token?[is recognized only when[immediately follows?, preservingcond ? [arr] : [arr]ternary parses. DiagnosticsGS0300andGS0301cover non-nullable receivers and assignment left-hand sides. - Documentation comments. Markdown-authored
///documentation comments round-trip losslessly to CLR XML doc. Hover renders merged documentation for both G# declarations and imported CLR APIs. New warnings includeGS0227,GS0228,GS0229,GS0230, andGS0231. - Named delegate types.
delegate Name(...)declares a real CLRMulticastDelegate-derived type so C# consumers see a conventional handler type and G# events can carry first-class custom delegate types. DiagnosticsGS0233–GS0234cover invalid forms.; ref/out/inparameters. Declaration-site and call-site ref-kind modifiers are supported, including inlineout var/out let/out _declarations. DiagnosticsGS0235–GS0243cover the rules. Passing a value to aninparameter without writinginat the call site is warningGS0242rather than a silent spill.- Ref-aliasing locals.
let ref m = arr[i]andvar ref v = c.Fieldproduce locals whose IL slots areT&and alias another lvalue. DiagnosticsGS0256–GS0258cover invalid aliases. - Ref returns.
func f(...) ref T { return ref <expr> }is supported. DiagnosticsGS0248–GS0255cover escape rules, async and iterator bans, and override matching. - Conditional ref-arguments. The narrow
ref cond ? a : bform is supported inside ref-kind argument payloads. DiagnosticsGS0260–GS0262cover invalid forms. - Generalized ternary expression.
cond ? a : bis now a normal expression.GS0259is retired in value contexts;GS0263covers "no common type" failures. - Method overloading and optional parameters. User G# functions can carry overload sets that differ by parameter types or ref-kinds, and optional parameters can use compile-time-constant defaults. Diagnostics
GS0264–GS0267cover invalid overloads and defaults. - Named arguments at call sites.
Foo(timeout: 30, retries: 3)works for free functions, user methods, user constructors, extension functions, inherited CLR methods, and delegateInvoke. DiagnosticsGS0244–GS0247cover invalid usage. The legacyname = valueform is deprecated this release with diagnosticGS0315; migrate.copy(...)and attribute argument lists alongside ordinary call sites. scopedparameter modifier.scopedconstrains aref structor managed-pointer parameter from escaping, enforced byGS9004/GS9006.data structsynthesis completed. Everydata structsynthesizesEquals(object),Equals(T),GetHashCode(),ToString(),op_Equality,op_Inequality, andDeconstruct(...). Hand-written versions are rejected withGS0232.- Editor features. Hover for CLR XML docs, live pull-based diagnostics, CodeLens reference counts on members of structs, interfaces, and enums, implicit
thisfor properties, methods, and events, hover forthis, bare static-member access from instance methods, chained-member hover, and six VS Code color themes inspired by the G# logo: Ember, Magma, and Synthwave in dark and light variants. :=short variable declaration removed. Every binding site now requiresletfor immutable bindings orvarfor mutable bindings. The lexer still recognizes:=so the parser can emitGS0305with context-sensitive migration suggestions such asx := 1→let x = 1,for i := 0 ... 10→for i in 0 ... 10, andcase v := <-ch→case let v = <-ch.
Changed
- The website spec, feature matrix, FAQ, bridges page, guide pages, and design-decisions index were refreshed to match compiler ground truth. Outdated statements such as "Parameters do not have default-value syntax" and "Named arguments — Partial" were rewritten.
- The repo
docs/lexical.mdblock-comment paragraph is corrected, and a documentation-comments subsection was added. - The VS Code TextMate grammar adds contextual keywords (
data,inline,record,delegate,event,prop,init,shared,scoped, accessor namesget/set/add/remove/raise, and ref-kindsref/out), operators (:=,?.,??,?/:,!!,...,=>), an@Annotationscope, and a///documentation-comment scope with@taghighlighting. The VS Code snippet set was rewritten to match current grammar. - The Docusaurus site cuts a new
0.2snapshot from the live docs and retires the0.1snapshot. The version dropdown lists0.2andNext; the0.1URL space is no longer served.
Fixed
- Numerous IL-emit, determinism, language-server, and editor hardening rounds improve CLR verification, byte-for-byte reproducibility, property access, CodeLens accuracy, and stale-tree handling.
Known limitations
- Full ref-safe-to-escape analysis is partial;
GS0257is reserved for a future pass. - Unsupported async state-machine emit shapes continue to report
GS0190.
0.1
The 0.1 version base identifies the first pre-1.0 line. This is not a dated stable release announcement; it summarizes the major capabilities implemented in the repository at that point.
Language and libraries
- Packages, imports, import aliases, top-level declarations, and multi-file or multi-package compilation.
- Width-bearing primitive names such as
int32,uint64,float32, andfloat64, plusbool,char,string,object,decimal,nint,nuint, andvoid. - Nullable
T?types withnil,?.,??, and!!. - Structs, classes, interfaces, enums,
data struct,recordas adata structalias, andinline structvalue wrappers. - Generic functions and types with square-bracket type parameters and arguments, constraints, method inference, and CLR variance support where applicable.
- Fixed arrays, slices, maps, tuples, function values, delegates,
sequence[T],async sequence[T], and iteratoryieldsupport. - Control flow including
if,for,for inorrangeforms, switches, switch expressions,try,catch,finally,throw,using, anddefer. - Go-shaped concurrency with
go,scope, channels, channel send and receive,make(chan T),close, andselect. async func,await, async lambdas, awaitable-shape support, andawait forover async sequences.- CLR interop for imported constructors, methods, overload resolution, fields, properties, indexers, events, delegates, extension methods, optional CLR arguments, operators, conversions, attributes, and generic types.
Tooling
gsccompiler driver with immediate execution when no/out:is supplied and saved managed executables or libraries with/out:.- Managed PE and metadata emission without Roslyn, optional reference assemblies, target-framework-aware reference resolution, runtime configuration output, and Portable PDB support.
- MSBuild SDK support through
Gsharp.NET.Sdk,.gsprojprojects,dotnet build,dotnet run, templates, and SDK-side response-file invocation. - VS Code extension and language server support for diagnostics, hover, definitions, references, symbols, formatting, completions, signature help, rename, code actions, CodeLens, semantic tokens, inlay hints, and debugging integration.
- Stable diagnostic IDs in the
GS####form, with warning suppression and warning-as-error controls.
Pre-1.0 notes
- The language is still evolving; source compatibility may change before a stable release.
- Some surfaces are intentionally documented as current implementation behavior rather than final specification guarantees.
- The Playground page exists, but browser-hosted execution is deferred.
Future release-note format
Use reverse chronological order. Each version entry should identify the version and, when a real release process exists, its date. Do not invent dates or version numbers; derive versions from the repository's release process. Write for end users: describe what changed, what it means, and any migration steps they should take.
## X.Y.Z
Short summary of the release.
### Added
- New language, tooling, documentation, or interop capabilities users can try.
### Changed
- Behavior changes, breaking changes, renamed features, or migration notes.
### Fixed
- Short grouped quality notes for user-visible correctness, diagnostics, emit, interpreter, or tooling improvements.
### Known limitations
- Important limitations users should know before upgrading.