본 문서는 GPT-5.5를 이용해서 분석 후 요약한 글입니다.
(그런데 오랜만에 글을 써서 어느 카테고리인지 좀 헷갈리네요 ^^;)
Roslyn Working Set C# 기능 정리
기준 문서: roslyn/docs/Language Feature Status.md - Working Set C#
Roslyn 저장소의 Working Set C# 표에 올라온 항목들을 기능 중심으로 정리했습니다. 이 목록은 "다음 C# 버전에 반드시 들어간다"는 확정 목록이라기보다는, Roslyn 컴파일러 팀이 지금 실제로 추적하거나 구현 중인 언어/컴파일러 기능 목록에 가깝습니다. 표 자체도 "목표 버전은 보장이 아니다"라고 안내하고 있으니, 현재 작업 흐름을 이해하기 위한 정리로 보는 것이 적절합니다.
정리 기준은 Working Set C# 표의 Feature, Branch, State 링크입니다. Developer, Reviewer, IDE Buddy, LDM Champ의 사람 프로필 링크까지 따라가면 글의 초점이 흐려질 수 있어, 기능 설명과 상태 확인에 필요한 링크 위주로 정리했습니다.
한눈에 보기
| 기능 | 현재 상태 | 핵심 의미 |
|---|---|---|
| Dictionary expressions | 진행 중 | 딕셔너리도 컬렉션 표현식처럼 짧게 만들 수 있게 하는 문법 |
| Unions | 진행 중 | 값이 여러 타입 중 하나일 수 있음을 언어가 알고 패턴 매칭/철저성 검사를 지원 |
| Extension indexers | 진행 중 | 확장 멤버 모델에 this[...] 인덱서를 추가 |
| Labeled break/continue | 진행 중 | 중첩 루프에서 break outer;, continue outer; 지원 |
| Null-conditional await | 진행 중 | null일 수 있는 awaitable에 await?로 null 전파 |
| Chained relational comparison | 진행 중 | min <= x < max 같은 연쇄 비교 지원 |
| Target-typed static member access | 진행 중 | 대상 타입이 명확할 때 .Member로 정적 멤버 접근 |
| Relax modifier ordering | 진행 중 | partial, ref modifier 순서 제한 완화 |
| Compound assignment in initializers | 진행 중 | object initializer와 with에서 +=, -=, ??= 등 허용 |
| Extension members on typeless receivers | 진행 중 | 타입이 아직 없는 표현식에도 확장 메서드/속성/인덱서 적용 |
| Closed class hierarchies | 미리보기 기능으로 병합됨 (.NET 11 p5 / VS 18.8) | 상속 가능한 타입 집합을 같은 어셈블리 안으로 닫고 switch 철저성 검사에 활용 |
| Unsafe evolution | 미리보기 기능으로 병합됨 (.NET 11 p2 / VS 18.6) | unsafe의 의미를 포인터 존재가 아니라 실제 메모리 위험 사용 중심으로 재정의 |
| ExtendedLayoutAttribute | 병합 완료 (VS 18.3) | 런타임 interop layout 정보를 새 attribute로 표현하도록 컴파일러 지원 |
| Runtime Async | main에 미리보기로 병합됨 | async state machine 일부를 컴파일러 생성이 아니라 런타임 지원 모델로 이동 |
| Collection expression arguments | 병합 완료 (.NET 11 p1 / VS 18.4) | 컬렉션 표현식에 생성자/빌더 인자를 넘기는 with(...) 요소 추가 |
1. Dictionary expressions
링크: Feature, Spec, State, Branch
이 기능은 C# 12의 collection expressions를 딕셔너리까지 확장하려는 작업입니다. 지금은 리스트나 배열류는 [1, 2, 3]처럼 표현할 수 있지만, 딕셔너리는 여전히 new Dictionary<TKey, TValue> { ... } 형태가 중심입니다. 제안은 키/값 쌍을 key: value 형태로 컬렉션 표현식 안에 넣는 방식입니다.
Dictionary<string, int> scores = ["kim": 90, "lee": 82];
Dictionary<string, int> merged =
[
..baseScores,
"park": 77,
];
의미상 단순한 축약 문법만은 아닙니다. 스펙은 Dictionary<TKey, TValue>, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> 같은 well-known 타입뿐 아니라, CollectionBuilderAttribute와 create method 패턴을 통해 ImmutableDictionary, FrozenDictionary 같은 타입까지 지원하려고 합니다.
여기서 중요하게 본 부분은 딕셔너리 표현식의 .. spread가 단순히 요소를 이어 붙이는 것이 아니라, 대상이 딕셔너리라면 키를 기준으로 인덱서 assignment에 가까운 의미를 갖는다는 점입니다. comparer 지원도 주요 쟁점이고, 별도 with(...) 인자 기능과도 연결됩니다.
2. Unions
링크: Feature, Spec, State, Branch
Unions는 C#에서 오랫동안 요구되어 온 "값이 여러 타입 중 하나일 수 있다"는 개념을 언어가 직접 이해하도록 만드는 큰 기능입니다. 제안은 단순 문법 하나가 아니라, union type, case type, union conversion, union matching, switch exhaustiveness, nullability 분석까지 묶은 기능군입니다.
예상되는 사용감은 대략 다음과 같습니다.
public union PaymentResult(Success, Declined, Timeout);
PaymentResult result = new Success(orderId);
string text = result switch
{
Success s => s.OrderId,
Declined d => d.Reason,
Timeout => "timeout",
};
핵심은 switch가 union의 case type을 알고 있다는 점입니다. 모든 case를 처리하면 default가 없어도 철저하다고 판단할 수 있습니다. 또한 Success 값을 PaymentResult로 넣는 implicit conversion, PaymentResult를 switch에서 바로 Success/Declined로 매칭하는 동작이 포함됩니다.
스펙상 union declaration은 opinionated한 축약 문법입니다. 낮은 수준에서는 [Union] attribute와 Value property, 생성자 또는 factory method 패턴을 갖춘 기존 타입도 union behavior에 참여할 수 있게 설계되어 있습니다. 즉 새 문법으로 만든 union뿐 아니라, 수동 구현한 타입도 규칙을 만족하면 union처럼 다룰 여지를 둡니다.
아직 작업 범위가 넓습니다. Roslyn 테스트 플랜에는 LangVersion, nullability, exhaustiveness, BCL의 IUnion/UnionAttribute, creation member, TryGetValue, HasValue 등 많은 항목이 남아 있습니다. 따라서 이 항목은 "드디어 DU가 확정됐다"기보다는, C# 팀이 type union 방향으로 실제 구현을 추적하기 시작한 흐름으로 보는 것이 더 적절합니다.
3. Extension indexers
링크: Feature, Spec, State, Branch
C# 14에서 확장 멤버 문법이 들어오면서 extension method뿐 아니라 extension property/operator 같은 방향이 열렸습니다. Extension indexers는 여기에 this[...] 인덱서를 추가하려는 기능입니다.
public static class BitExtensions
{
extension(int value)
{
public bool this[int bit]
{
get => ((value >> bit) & 1) != 0;
}
}
}
bool enabled = flags[3];
일반 인덱서와 비슷하게 보이지만, 실제로는 확장 멤버이기 때문에 lookup 규칙이 중요합니다. 먼저 타입 자체의 instance indexer를 찾고, 없으면 Index/Range 기반 implicit indexer를 시도하며, 그래도 없을 때 extension indexer lookup으로 넘어갑니다.
이 기능은 list pattern, null-conditional element access, object initializer의 index assignment 같은 다른 element-access 기반 기능과도 연결됩니다. 예를 들어 어떤 타입이 실제 Length/Count나 Slice를 갖고 있지 않더라도, 적절한 extension member가 있다면 range/index 접근의 일부로 고려될 수 있습니다.
4. Labeled break/continue
링크: Feature, Spec, State, Branch
이 기능은 중첩 루프에서 바깥 루프를 직접 break하거나 continue할 수 있게 합니다. 지금은 goto, flag 변수, 함수 분리 등으로 우회해야 하는 패턴을 언어 차원에서 간단히 표현합니다.
outer: for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (ShouldSkipColumn(x, y))
continue outer;
if (Found(x, y))
break outer;
}
}
break label;은 해당 label이 붙은 가장 가까운 switch 또는 반복문을 빠져나가고, continue label;은 해당 label이 붙은 가장 가까운 반복문의 다음 반복으로 이동합니다. continue는 switch가 아니라 loop를 대상으로 한다는 차이가 있습니다.
작아 보이지만 실제 코드에서는 꽤 반가운 기능입니다. 특히 2중/3중 루프에서 조건을 만족했을 때 바깥 반복을 제어하는 코드는 flag 변수를 쓰면 의도가 흐려지고, goto를 쓰면 label 위치가 어색해집니다. 이 기능은 label을 제어 대상에 직접 붙이므로 읽는 사람이 이동 대상을 바로 알 수 있습니다.
5. Null-conditional await
링크: Feature, Spec, State, Branch
await?는 awaitable 값이 null이면 await하지 않고 null/default를 반환하도록 하는 기능입니다. 중요한 점은 "null Task를 반환하는 async API를 장려"하려는 기능이 아니라, null-conditional chain 때문에 await할 대상이 null이 되는 상황을 자연스럽게 처리하려는 기능이라는 점입니다.
await? service?.FlushAsync();
int? count = await? cache?.GetCountAsync();
현재 await service?.FlushAsync() 같은 코드는 문법상 가능해 보여도, service가 null이면 결과가 null이 되고 그 null을 await하려다가 런타임 예외가 날 수 있습니다. await?는 이 지점에서 null-conditional 의미를 await까지 이어줍니다.
결과 타입 규칙도 중요합니다. Task<int>?를 await?하면 결과는 int?가 되고, Task<string>?를 await?하면 결과는 string?가 됩니다. ValueTask<T>처럼 non-nullable value-type awaitable 자체에는 그대로 쓸 수 없고, nullable로 감싸진 경우에만 null 테스트 대상이 됩니다.
6. Chained relational comparison
링크: Feature, Spec, State, Branch
수학식처럼 min <= x < max를 쓸 수 있게 하는 기능입니다. 의미는 대략 min <= x && x < max이지만, 가운데 표현식 x를 한 번만 평가한다는 점이 중요합니다.
if (0 <= index < items.Length)
{
Use(items[index]);
}
if (low < ComputeScore() <= high)
{
...
}
두 번째 예시를 기존 문법으로 단순히 low < ComputeScore() && ComputeScore() <= high라고 바꾸면 ComputeScore()가 두 번 호출됩니다. chained comparison은 이 문제를 피하려는 목적도 있습니다.
호환성 때문에 규칙이 조금 섬세합니다. C#에서는 a < b < c 형태가 아주 특이한 operator overload 조합으로 이미 컴파일될 수 있습니다. 그래서 제안은 먼저 기존 방식으로 바인딩을 시도하고, 실패했을 때 chained comparison 의미로 해석하는 방향입니다. 즉 실사용에서는 직관적인 의미를 주되, 기존에 컴파일되던 코드를 가능한 한 깨지 않으려는 설계입니다.
7. Target-typed static member access
링크: Feature, Spec, State, Branch
대상 타입이 문맥상 명확할 때 정적 멤버의 타입 이름을 생략하고 .Member로 접근하는 기능입니다. enum, flags enum, factory method, singleton, nested derived type에서 반복되는 타입명을 줄이는 것이 목적입니다.
BindingFlags flags = .Public | .Instance | .DeclaredOnly;
StringComparison comparison = .OrdinalIgnoreCase;
Option<int> option = hasValue ? .Some(42) : .None;
패턴 매칭과도 연결됩니다. 특히 generic nested type을 반복해서 써야 하는 계층형 결과 타입이나 union-like 타입에서 가독성 차이가 큽니다.
return result switch
{
.Success(var value) => value,
.Error(var message) => fallback,
};
이 기능의 핵심은 "target type이 있는 자리"에서만 동작한다는 점입니다. 단독으로 .Some(42)를 쓰면 어떤 타입의 Some인지 알 수 없기 때문에 의미가 없습니다. 반대로 변수 대입, return type, 인자 타입, switch pattern처럼 대상 타입이 있는 자리에서는 타입명을 반복하지 않아도 됩니다.
8. Relax modifier ordering
링크: Feature, Spec, State, Branch
이 기능은 partial과 ref modifier의 위치 제한을 완화합니다. 대부분의 C# modifier는 순서에 비교적 관대하지만, partial과 ref는 특정 위치를 요구하는 예외가 있었습니다.
partial public class Widget { }
partial ref struct BufferView { }
partial public void Render();
의미가 바뀌는 기능은 아닙니다. 기존에는 modifier 순서 때문에 에러였던 코드를, 다른 modifier처럼 자연스럽게 허용하는 정리성 기능에 가깝습니다. source generator나 code fix가 modifier를 조합할 때도 불필요한 순서 계산 부담이 줄어듭니다.
9. Compound assignment in initializers
링크: Feature, Spec, State, Branch
object initializer와 record with expression 안에서 +=, -=, *=, ??= 같은 compound assignment를 허용하려는 기능입니다. 가장 직관적인 사용처는 이벤트 구독입니다.
var button = new Button
{
Text = "Run",
Click += OnRunClicked,
};
또는 기존 값을 기준으로 clone을 만들 때도 자연스럽습니다.
var next = current with
{
Count += 1,
LastUpdated = now,
};
중요한 규칙은 initializer의 compound assignment가 "보이지 않는 임시 객체"에 대해 실제 statement처럼 실행된다는 점입니다. 예를 들어 Value += 5는 임시 객체의 현재 Value를 읽고, 더한 뒤, 다시 씁니다. 따라서 property/indexer라면 compound assignment에 필요한 getter와 setter/init 접근 가능성이 필요합니다.
또한 required 멤버는 compound assignment만으로는 충족되지 않습니다. 새 객체의 required 값은 먼저 =로 유효한 상태가 되어야 하고, 그 다음 += 같은 연산을 할 수 있다는 방향입니다.
10. Extension members on typeless receivers
링크: Feature, Spec, State, Branch
이 기능은 아직 타입이 없는 표현식에도 확장 멤버를 적용할 수 있게 합니다. 대표 동기는 collection expression입니다. [1, 2, 3]은 대상 타입이 있어야 타입이 결정되므로, 오늘날에는 그 자체에 .ToImmutableArray() 같은 확장 메서드를 바로 붙이기 어렵습니다.
var values = [1, 2, 3].ToImmutableArray();
var query =
from x in [1, 2, 3, 4]
where x > 2
select x * 10;
제안의 핵심은 receiver를 확장 메서드의 첫 번째 인자로 보고, 후보 확장 멤버의 첫 번째 파라미터 타입에 대해 기존 overload resolution과 type inference를 돌리는 것입니다. 이미 타입이 있는 receiver는 기존 규칙 그대로 처리합니다.
이 기능은 collection expression뿐 아니라 lambda, method group, 공통 타입이 없는 conditional expression 같은 "typeless expression"에도 확장될 수 있습니다.
var cached = SomeOverloadedMethod.Memoize();
var maybe = (condition ? null : GetValue()).ToOptional();
단, 이 기능은 범위가 넓기 때문에 LDM에서 어떤 receiver category까지 허용할지 조정될 수 있습니다.
11. Closed class hierarchies
링크: Feature, Spec, State, Branch
closed class는 직접 파생 타입을 같은 assembly/module 안으로 제한하는 기능입니다. 목적은 "이 계층의 직접 하위 타입 집합은 작성자가 통제한다"는 사실을 컴파일러가 알고, switch exhaustiveness에 활용할 수 있게 하는 것입니다.
public closed record class DoorState;
public record class Open(int Percent) : DoorState;
public record class Closed : DoorState;
string Describe(DoorState state) => state switch
{
Open open => $"{open.Percent}%",
Closed => "closed",
};
다른 assembly에서 DoorState를 직접 상속하려 하면 에러가 됩니다. 다만 같은 assembly 안의 하위 타입이 다시 non-closed 타입이라면, 그 타입을 통해 간접 상속하는 경우까지 모두 막는 것은 아닙니다. closed는 직접 파생 관계를 닫는 기능입니다.
closed class는 암시적으로 abstract입니다. 따라서 sealed, static, 명시적 abstract와 같이 쓸 수 없습니다. generic closed hierarchy에서는 파생 타입의 type parameter가 base type specification에 사용되어야 하는 제한도 있습니다. 이는 특정 closed generic instantiation에 대해 가능한 파생 타입 집합을 계산하기 위함입니다.
Roslyn 상태상 preview feature로 내려가 있으며, 테스트 플랜에는 C# 15 이상 LangVersion 항목이 보입니다. 그래도 Roslyn 문서의 FAQ처럼 목표 버전 자체는 보장으로 읽으면 안 됩니다.
12. Unsafe evolution
링크: Feature, Spec, State, Branch
이 기능은 unsafe의 의미를 크게 재정의합니다. 기존 C#에서는 포인터 타입이 등장하는 것 자체가 unsafe 문맥과 강하게 묶여 있었습니다. 새 방향은 "포인터가 존재하는 것"보다 "런타임이 관리하지 않는 메모리를 실제로 역참조하거나 접근하는 것"에 unsafe 의미를 집중합니다.
void M()
{
int value = 1;
int* p = &value; // 포인터를 만드는 것 자체는 허용 방향
unsafe
{
Console.WriteLine(*p); // 역참조는 unsafe
}
}
또 하나의 큰 변화는 member-level unsafe가 caller에게도 의미를 갖게 된다는 점입니다. 어떤 API가 memory safety 검토를 호출자에게 요구한다면, 그 API 사용 자체가 unsafe context를 요구할 수 있습니다. BCL의 Unsafe, Marshal, reflection 계열 API에 memory-safety annotation을 붙이는 생태계 작업과 연결됩니다.
스펙에는 safe contextual keyword도 등장합니다. 특히 extern 멤버처럼 런타임이 안전성을 판단하기 어려운 경계에서 unsafe/safe를 명시하게 하는 방향입니다.
여기서 눈여겨봐야 할 부분은 breaking change 가능성입니다. 포인터 타입 허용은 완화처럼 보이지만, member-level unsafe의 의미 강화, extern 처리, 특정 stackalloc 조건, safe contextual keyword 도입 등은 기존 코드에 영향을 줄 수 있습니다. 그래서 이 기능은 단순 문법 편의가 아니라 C#/.NET의 memory safety audit 모델을 다시 설계하는 작업으로 보입니다.
13. ExtendedLayoutAttribute
링크: Feature/API issue, State PR
이 항목은 일반적인 C# 문법 기능이라기보다 interop layout을 표현하기 위한 런타임/컴파일러 지원입니다. .NET의 기존 StructLayoutAttribute는 metadata pseudo-attribute 성격이 강해서, 새 layout 요구사항을 계속 확장하기 어렵습니다. 그래서 System.Runtime.InteropServices.ExtendedLayoutAttribute를 통해 더 확장 가능한 layout 정보를 제공하려는 작업입니다.
주요 동기는 Swift interop 같은 시나리오입니다. 예를 들어 generic struct의 Swift layout을 .NET metadata와 runtime이 이해할 수 있게 표현해야 하는데, 기존 StructLayout.Size 방식으로는 일반화하기 어렵습니다.
Roslyn PR의 핵심은 C# 코드에서 ExtendedLayoutAttribute가 붙은 타입을 emit할 때, runtime이 인식할 수 있는 extended layout bit를 올바르게 설정하도록 허용하는 것입니다. 사용자가 새 layout kind 값을 직접 지정하는 것이 아니라, attribute를 통해 컴파일러가 올바른 metadata를 내보내는 방향입니다.
따라서 이 항목은 "C# 문법이 예뻐지는 기능"이라기보다, interop 고급 시나리오를 위한 layout metadata 확장으로 이해하는 것이 적절합니다.
14. Runtime Async
링크: State, Runtime spec, Compiler design, Branch
Runtime Async는 C# 사용자가 쓰는 async/await 문법을 크게 바꾸는 기능이 아닙니다. 핵심은 async state machine 생성 방식입니다. 지금은 C# 컴파일러가 async 메서드를 상태 머신 클래스로 낮추는 방식이 중심인데, runtime async는 이 역할의 일부를 런타임/JIT 쪽 지원 모델로 옮기려는 작업입니다.
대략적인 변환 이미지는 다음과 같습니다.
async Task SaveAsync()
{
await FlushAsync();
}
컴파일러는 특정 조건에서 이 메서드를 runtime async 형태로 emit하고, suspension point를 AsyncHelpers.Await(...) 같은 helper 호출 또는 runtime async call pattern으로 표현합니다. 런타임 쪽에는 MethodImplOptions.Async flag와 async-capable assembly 개념이 제안되어 있습니다.
상태 이슈에는 .NET 10 preview에 포함된 부분과 post-.NET 10 작업이 나뉘어 있습니다. 이미 direct IL verification, helper API 감지, Task/ValueTask 계열 await 최적화, await using, await foreach 같은 항목이 추적되고 있습니다. 반면 PDB/debugging, instrumentation, dynamic, async iterator, 안정화 후 임시 attribute/feature flag 제거 같은 후속 작업도 남아 있습니다.
즉 이 기능은 "코드를 이렇게 새로 쓰세요"라기보다, "같은 async 코드를 더 효율적이고 런타임 친화적인 방식으로 실행하기 위한 기반"입니다.
15. Collection expression arguments
링크: Feature, Spec, State, Branch
collection expression 안에서 생성자나 builder method에 인자를 넘기는 기능입니다. 문법은 첫 번째 요소 위치에 with(...)를 두는 방식입니다.
List<string> names = [with(capacity: estimatedCount), ..source];
Dictionary<string, int> map =
[
with(StringComparer.OrdinalIgnoreCase),
"one": 1,
"two": 2,
];
동기는 dictionary/set comparer나 collection capacity처럼, 컬렉션의 "내용"은 collection expression으로 쓰고 싶지만 "생성 방식"도 함께 지정해야 하는 경우입니다. 기존 [a, b, c]는 요소만 표현하므로 new List<T>(capacity)나 ImmutableXxx.Create(...) 같은 생성 인자를 전달할 방법이 부족했습니다.
스펙은 세 가지 축을 다룹니다.
- 일반 collection type이면
with(...)인자를 적절한 생성자 overload resolution에 사용합니다. CollectionBuilderAttribute기반 타입이면 create method의 마지막ReadOnlySpan<T>앞쪽 인자에with(...)값을 전달합니다.- interface target type이면 well-known 구현체 생성 규칙과 comparer 규칙을 제한적으로 적용합니다.
여기서 기억할 부분은 with(...)가 collection expression의 첫 번째 요소여야 한다는 점입니다. 또한 dynamic 인자는 허용하지 않는 방향으로 설계되어 있습니다. 이 기능은 이미 상태 이슈가 closed이고 Merged into .NET 11 p1 and VS 18.4로 기록되어 있습니다.
전체 흐름
이번 Working Set C#의 큰 축은 세 가지로 나눌 수 있습니다.
첫째, union과 closed hierarchy입니다. C#이 패턴 매칭의 철저성을 더 강하게 이해하도록 만드는 방향입니다. Unions는 값이 여러 case type 중 하나임을 표현하고, Closed class hierarchies는 class 상속 계층의 직접 하위 타입 집합을 닫습니다.
둘째, collection/extension 계열 ergonomics입니다. dictionary expressions, collection expression arguments, extension indexers, typeless receiver extension members는 모두 C# 12 이후 collection expression과 C# 14 extension members를 더 실전적으로 만드는 흐름입니다.
셋째, runtime/compiler 기반 개선입니다. unsafe evolution, runtime async, extended layout은 겉보기 문법보다 언어/런타임 경계의 의미를 다시 정리하는 항목입니다. 특히 unsafe evolution은 단순 편의 기능이 아니라 memory safety audit 모델의 변화입니다.
정리하면, C#의 다음 작업 흐름은 단순 문법 설탕을 추가하는 데서 그치지 않고, 타입 시스템이 더 많은 의도를 이해하도록 만드는 쪽으로 이동하고 있습니다. union/closed hierarchy는 패턴 매칭의 철저성을, dictionary/collection/extension 관련 기능은 컬렉션 표현식 이후의 사용성을, unsafe/runtime async/layout 항목은 런타임과 컴파일러의 책임 경계를 다시 다듬는 흐름으로 읽힙니다.
참고 링크
- Roslyn Language Feature Status - Working Set C#
- Dictionary expressions spec
- Unions spec
- Extension indexers spec
- Labeled break/continue spec
- Null-conditional await spec
- Chained relational comparison spec
- Target-typed static member access spec
- Relaxed modifier ordering spec
- Compound assignment in initializers spec
- Extension members on typeless receivers spec
- Closed hierarchies spec
- Unsafe evolution spec
- ExtendedLayoutAttribute API issue
- Runtime async runtime spec
- Runtime async compiler design
- Collection expression arguments spec