Skip to content

Instantly share code, notes, and snippets.

@jaredpar
Created January 12, 2023 23:35
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jaredpar/6706628bfe0098840ce453c1c71098a9 to your computer and use it in GitHub Desktop.
Save jaredpar/6706628bfe0098840ce453c1c71098a9 to your computer and use it in GitHub Desktop.
This is the code I demonstrated at the .NET Community Standup on 2023/1/12 with comments to explain how it works.
using System;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
#nullable disable
// The stand up link https://www.youtube.com/watch?v=jaPk6Nt33KM
// String vs. string
// - string is a C# keyword that binds to System.String in corelib
// - String is just another name. Most of the time it binds to the same type
// as string but it doesn't have to. Defining the type String here lets us
// subvert expectations around String behavior
//
// More details
// https://blog.paranoidcoding.com/2019/04/08/string-vs-String-is-not-about-style.html
class String {
public static implicit operator String(dynamic var) => null;
}
// Let's define a few type names that mirror contextual keywords. This lets
// us subvert expectations by having the compiler bind these as types
// instead of keywords.
class record { }
class where { }
class dynamic { }
class var {
// This defines a property named dynamic that has type dynamic (defined
// above). It's no different than Color Color (common in UI) because in
// this program dynamic is a type. The only difference is expectation
// around what dynamic should be.
dynamic dynamic => null;
// Even though we defined a type named record, this is not a method. Instead
// this is a record definition. That is because record is one of the few
// places where C# took a back compat hit on upgrade and always treats
// record as a keyword.
record nameof(where String = null)
{
}
// The @ in front of record causes the language to not treat record as a
// keyword but as a normal identifier. That makes this a normal method
// where named orderby (a contextual keyword but for back compat reasons
// have to accept it as a member name).
//
// The @ trick goes all the way back to C# 1.0 and can be applied to _any_
// keyword. That is what allows us to declare a parameter named @int below
// where the type is string (not String)
@record orderby(string @int = null)
{
// Here String binds to our type and that has an implicit conversion from
// the type dynamic.
String s = this.dynamic;
// Didn't want to return so throw instead. ;)
throw null;
}
async Task<int> M() {
// This is a local of type var (see above) named var that initialized
// via a target typed new expression.
var var = new();
// Here we call var.async and await the result.
await var.async(new async());
return 0;
}
// The buffalo example.
//
// - This is a method named async
// - The method is async, can contain await expressions
// - The return type is class async
// - The first parameter is of type class async and has a name async
async async async(async async) =>
// This is await on a type which satisfies the task-like pattern
// hence can be awaited
await async;
}
// Do you C what I'm doing here?
// Can't resist a good dad joke
class C{ }
// This is a typed named await that implements the awaiter pattern
// in C#.
class await : INotifyCompletion {
public bool IsCompleted => true;
public void GetResult() { }
public void OnCompleted(Action continuation) { }
}
// This is a type async which satisfies the Task-like pattern and thus
// can be the return type on an async method.
[AsyncMethodBuilder(typeof(builder))]
class async {
public await GetAwaiter() => throw null;
}
class builder
{
public builder() { }
public static builder Create() => new();
public void SetResult() { }
public void SetException(Exception e) { }
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine => throw null;
public async Task => null;
public void AwaitOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine => throw null;
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine => throw null;
public void SetStateMachine(IAsyncStateMachine stateMachine) => throw null;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment