Skip to main content
Version: 0.3

Design decisions (ADRs)

This is a curated reference index of the Architecture Decision Records in the repository. ADRs explain design intent and tradeoffs; they are not the normative language specification. Each link points to the source ADR on GitHub. The repository currently has accepted/proposed ADRs through ADR-0146 (plus the 0000 template).

Null model, values, and primitives

ADRTitleSummary
0001Absence / null model — Kotlin-style nullable typesUses explicit nullable T?, nil, safe access, and assertion instead of a universal null.
0073Null-conditional indexing a?[i]Adds the ?[ token; result lifts to the nullable form of the indexer's return type; receiver evaluated exactly once; rejected as assignment LHS.
0008Variable bindings — keep Go's var/const/:=, add letOriginal decision; the := short-declaration leg was superseded by ADR-0077.
0077Drop := short variable declarationRemoves := from the language; the parser hard-rejects it with GS0305 and a context-sensitive let/var/for … in … migration suggestion.
0015Multi-target assignment evaluation orderEvaluates all right-hand values before observable writes, matching Go swap semantics.
0016Slice backing storage — T[]Represents slices with CLR single-dimensional zero-based arrays.
0044Complete numeric primitive coverageDefines full width-bearing numeric primitive coverage and conversion behavior.
0045object as the universal upper boundMakes object the top type for assignment compatibility, boxing, and object equality.
0046'c' character literal grammarSpecifies character literal grammar, escapes, static type, and diagnostics.
0049Width-bearing integer keyword namesChooses explicit names such as int32 and uint64 over ambiguous aliases.
0098Friendly numeric type aliasesAdds int / uint / long / ulong / short / ushort / byte / sbyte / float / double as binder-resolved aliases on top of the canonical width-bearing names; diagnostics and IL keep the canonical spelling.

Concurrency, async, and resource scope

ADRTitleSummary
0002Concurrency model — Go surface, .NET runtime, Kotlin scopesCombines Go-like go/channel syntax with .NET tasks and structured scopes.
0022go / chan / select → .NET loweringDefines how goroutine-like calls, channels, send/receive, and select lower to .NET.
0023async func / await — state-machine strategyCommits to compiler-generated async state machines for emitted async functions.
0030defer and block-scoped cleanup convergenceMakes cleanup block-scoped and aligns defer with using/finally lowering.
0040sequence[T] type alias and yield statementIntroduces sequence types and iterator yield statements.
0041sequence[T] in an async context aliases IAsyncEnumerable[T]Explores async sequence feasibility and binding shape.
0042async sequence[T] as a type-clause spelling for IAsyncEnumerable[T]Chooses an explicit type-clause spelling for async streams.
0043async func(P) R as a type-clause spelling for func(P) Task[R]Defines async function type clauses as task-returning function types. Re-spelled as async (P) -> R by ADR-0075.

Object model, OO, and data types

ADRTitleSummary
0003OO surface — data-oriented core with light OO escape hatchAdds classes/interfaces without making OO the center of the language.
0017Method virtuality — sealed by default, opt-in with openRequires explicit open for inheritable classes and overridable methods.
0018Interface default methods — not in Phase 3Defers default interface methods from the early interface surface.
0024Methods with receivers vs. extension functions canonical styleEstablishes receiver functions as the canonical extension/method style.
0079Restrict receiver-clause methods to non-owned receiver types (warning)Reserves func (r T) M() for types the package does not own; same-package owned receivers emit the soft GS0314 warning. Operators are exempt.
0025record keyword alias for data structMakes record syntactic sugar for data struct.
0029data struct synthesized membersDefines synthesized equality, copy, and ergonomic members for data structs.
0032Data-struct ergonomics polishRefines copying, deconstruction, and update syntax for data structs.
0033Inline value classes / inline structIntroduces single-field inline structs for value-class ergonomics.
0051Property declarations — prop keyword with accessor bodiesSpecifies property syntax, auto-properties, and accessors.
0052Event declarations on user types — event keywordDefines field-like and custom event declarations on user types.
0053Static members on user types — shared blockAdds static fields, methods, properties, and events through a shared block.

Generics and functions

ADRTitleSummary
0004Generics — consumption and definition in a single phase, with constraintsDefines initial generic types/functions, constraints, and reified-CLR-generics commitment (now fully delivered; the original implementation-status addendum was superseded by ADR-0087 R1–R7).
0020Generic type-parameter brackets — Go-style [T]Chooses square brackets for type parameters and type arguments.
0021Generic variance modifiers — in / out on interface type parametersAdds variance markers for interface type parameters.
0038Type-argument inference for imported open generic methodsDefines inference for imported generic method calls and associated emit fixes.
0050-> arrow trailing-lambda syntaxSuperseded by ADR-0074. The proposed ->-connector trailing-lambda was never implemented and never will be — -> is now the lambda operator, so the connector spelling collides with (params) -> … lambdas. Full arrow lambdas plus the live Phase 4.9 func(...) trailing-call form cover the need (revisited under issue #411).
0087Reified-generics emit — open-shape erasure audit, staged elimination plan, and v1 dispositionImplementation-status addendum to ADR-0004. Catalogued every open-generic erasure site (53 across 14 source files), specified the target CLR metadata (TypeDef+GenericParam, TypeSpec/MethodSpec, Var/MVar encoding), staged the elimination R1–R7 (all implemented), and pinned the v1 disposition. Supersedes issue #484.

Error handling and control flow

ADRTitleSummary
0005Error handling — exceptions only, uncheckedUses CLR exceptions instead of checked exceptions or Go-style error returns.
0009switch semantics — expression + statement, patterns, exhaustiveDefines switch statements, switch expressions, patterns, and exhaustiveness.
0013Drop Go's fallthroughReserves fallthrough but rejects it; cases never fall through.
0031Canonical for x in collectionEstablishes for x in collection as the preferred range iteration spelling.

Syntax, naming, and documentation policy

ADRTitleSummary
0006Visibility — explicit modifiers, public defaultReplaces Go capitalization export rules with explicit visibility modifiers.
0007String interpolation syntax — Kotlin-styleChooses $name and ${expr} interpolation forms.
0010Aspirational samples policy — rewrite to today's subset, re-expand per phaseKeeps samples aligned with implemented language phases.
0011String interpolation grammar and loweringSpecifies interpolation parsing and lowering details.
0012Raw string delimiter — backtickChooses backtick-delimited raw strings.
0014Visibility defaults — public for top-level declarationsMakes unmodified top-level declarations public by default.
0054Postfix member/index access on primary expressionsChains ./?./[] after any primary except a bare numeric literal ((42).Member).
0055String interpolation revampDelimiter-aware multiline holes, alignment/format clauses, late context-driven lowering (DefaultInterpolatedStringHandler/FormattableString), and full IDE support inside holes.
0057Documentation commentsMarkdown-authored /// documentation comments with lossless CLR XML-doc round-trip; hover renders the merged XML on imported APIs. Diagnostics GS0227GS0231.
0062Generalized ternary expressionPromotes cond ? a : b from the narrow ADR-0061 ref form to a normal expression; retires GS0259 in value contexts and adds GS0263.
0074-> for lambda expressions, : for switch-expression armsAdds the arrow-lambda expression form (x int32) -> x * x and migrates switch-expression arms from -> to : (deprecated old arm form emits GS0302).
0075(T) -> R as the canonical function-type clause syntaxFunction-type clauses are spelled (T1, T2) -> R and async (T) -> R. The legacy func(T) R and async func(T) R type-clause spellings stay valid for one release and emit GS0303.
0076Type inference for let / var lambda bindingsWhen a let / var binding is initialized with a lambda whose parameter types are fully spelled, the binding's type is inferred to the lambda's (T1, ...) -> R function type. Open lambdas (untyped params and no target type) emit GS0304.
0128Arrow-lambda / func-literal parity — statement-block arrow bodiesA block-bodied arrow lambda (p) -> { … } becomes a statement block with an optional trailing value expression: an if-without-else (and other void control-flow) is a void statement instead of being rejected with GS0276, reaching full parity with func literals. The parser classifies if as a value-producing if-expression only when it has a matching else. cs2gs reverts the #1160 workaround and emits idiomatic arrow lambdas for block-bodied C# lambdas.
0129C#-compatible numeric literal narrowing/wideningA constant integer expression (an integer literal, or unary +/- over one) implicitly narrows to any integer target whose range contains its value (C# §10.2.11), so var x uint8 = 42 / var a int8 = -5 compile with no cast; out-of-range constants still error (GS0156). Non-constant values widen implicitly per the lattice and narrow only via the explicit T(x) conversion-call form (truncating like C#).

CLR interop

ADRTitleSummary
0019Extension function declaration syntax — func (Receiver) Name(...) ...Defines receiver-based extension function syntax.
0026Operator-by-name on user types — deferredDefers user operator naming until a later design is chosen.
0034Imported CLR interop — static members, writes, operators, conversions, overload resolutionExtends imported CLR support across static members, writes, operators, conversions, and overloads.
0035User-defined operator keyword on GSharp typesAdds receiver-style operator declarations for G# types.
0036CLR event subscription with += / -=Uses assignment-like syntax for CLR event add/remove.
0037Numeric better-conversion target tie-breaking in overload resolutionDefines numeric conversion ranking for overload resolution.
0039By-ref pointers and CLR interop for ref / out / in parametersIntroduces *T, &, dereference, ref arguments, and related diagnostics.
0047Attribute consumption and declaration (Kotlin-style annotations)Defines @ annotation syntax, use-site targets, attribute arguments, and @Attribute sugar.
0056Span consumption v1 — ref-returning members, span element access, closed generic value-type fieldsAuto-dereferences ref-returning members in rvalue position, makes spans indexable (read/write), applies []T → Span[T] conversion in argument position, and gives closed generic value-type fields real layout.
0058Ref-safe-to-escape and the scoped modifierAdds the scoped parameter modifier and the supporting GS9004/GS9006 ref-pointer escape diagnostics.
0059Named delegate typestype Name = delegate func(...) declares a real CLR MulticastDelegate-derived type; generic delegates supported per issue #1503; diagnostic GS0233.
0060ref/out/in parametersDeclaration-site and call-site ref-kind modifiers with diagnostics GS0235GS0243; ref-aliasing locals (let ref/var ref) and ref returns are follow-ups (GS0248GS0258).
0061Conditional ref-argumentsNarrow ref cond ? a : b form inside ref-kind argument payloads; diagnostics GS0259GS0262.
0063Method overloading and optional parametersLifts the v0 "one declaration per name" rule and adds default parameter values; diagnostics GS0264GS0267.
0080Deprecate name = value named-argument spelling (warning)Reserves name: value as the canonical call-site and attribute named-argument separator (issue #343); the legacy = spelling kept for back-compat by ADR-0032 / ADR-0047 emits the soft GS0315 warning before removal.

Emit and tooling

ADRTitleSummary
0027Roslyn-fork decision for v1.0 — stay on the bespoke emitterKeeps the direct metadata emitter instead of adopting a Roslyn fork for v1.0.
0028Multi-package emit model — Option B, C#-faithfulDefines how multiple packages map to emitted CLR namespaces/types.
0048Portable PDB emitAdds portable PDB, source mapping, and debug-symbol policy to the emitter.

0.3 ADRs (0105-0146)

The 0.3 documentation audit covers these ADRs landed after the 0.2 snapshot. The earlier curated sections above remain grouped by topic; this table keeps the current ADR range visible.

ADRTitle
0105Incremental (delta) binding for the language server
0106Incremental LSP SemanticModel via instance-keyed memoization
0107Cross-session cold-start cache for the language server
0108Delegate return-type covariance and lambda target-typing on CLR method calls
0109Top-level private maps to IL assembly (internal)
0110Nested type declarations
0111Completion-as-you-type triggering policy
0112Unified member resolution
0113Predefined type aliases as static-member-access receivers
0114Nested (and forward-referenced) class constructor emission
0115cs2gs — a C#→G# migration tool and gap-discovery pipeline
0116Null-coalescing operator spelled ?? (replacing ?:)
0117Collection initializers — List[T]{…}, HashSet[T]{…}, Dictionary[K,V]{…}
0118User indexer-member declaration — prop this[i int32] T { get; set }
0119Inferred-type arrow lambdas are the canonical lambda form
0120User-defined conversion operators (operator implicit / operator explicit)
0121Throw expressions (throw in value position)
0122Unsafe context and unmanaged raw pointers (*T = ELEMENT_TYPE_PTR)
0123From-end index operator (^n) for index and range bounds
0124stackalloc [n]T stack allocation (localloc) — safe Span<T> and unsafe T* forms, with initializers
0125fixed statement — pinning a managed buffer and binding an unmanaged *T
0126Increment / decrement as value-producing expressions (++ / --)
0127Standalone System.Range value (let r = 1..3)
0128Arrow-lambda / func-literal parity — statement-block arrow bodies
0129C#-compatible numeric literal narrowing/widening
0130[n]T runtime/zero-initialised array allocation
0131Expression-bodied members via the -> arrow
0132[]T? array of nullable elements vs []?T nullable array
0133Implicit numeric promotion at call sites
0134Static imports — import Ns.Type exposes shared members for unqualified use (C# using static)
0135unmanaged type-parameter constraint and sizeof(T) expression
0136Unannotated imported reference types are nullable by default
0137Nullable function type spelling
0138cs2gs construct-coverage program and gap-triage automation
0139general goto / label statements
0140shared { init { … } } static-initializer block
0141lambda conversions to Expression[TDelegate]
0142resx codebehind generator (Resources.Designer.gs)
0143generated code in cs2gs migration — reproduce at build, don't freeze
0144partial types (partial on class / struct / interface)
0145Roslyn source-generator host for native G# projects (gsgen)
0146Anonymous-object literal (object { ... }, Kotlin-style)