iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
⚛️

Classes That Ensure Thread Safety

に公開

I reproduced Swift's actor[1] and defer[2] in C#.

Atom<T>

The C# version of actor has a DSL-like syntax. This wasn't so much about making it look like Swift, but rather a necessity to enforce thread-safety.

var atom = new Atom<int>();

atom.Set = 42;
atom.Update = v => ++v;  // 43

atom.Set = 310;
atom.Read = v => Console.WriteLine(v);

It is difficult to enforce thread-safety for reads using simple syntax.

👇 If you are using .NET 7+, you can also write it in a functional language style.

atom <<= 310;
atom >>= Console.WriteLine;

Apart from these, there is also a version that can be written in standard C# style. This one is mainly intended to avoid closure allocations.

atom.WriteLock((x: 42, y: "Tuple"), static (args, current) =>
{
    return current + args.x + args.y.Length;
});

Reference types can still be modified within the ReadLock scope. It can't be helped.

var atom = new Atom<MyClass>(value: new());

atom.ReadLock(foo, async static (foo, myClass) =>
{
    // 👇 Since the entire block is inside the lock, other threads cannot access it for 1 second.
    await Task.Delay(1000);

    myClass.Data = foo.Value;
});

// 👇 Minimize lock time while avoiding allocations (might not always be appropriate)
atom.ReadLock(foo, (foo, value) => foo.Data = value);
async foo.ProcessDataAsync();

Source Code

https://github.com/sator-imaging/Unity-Fundamentals/blob/310d83180e722965011388bf47d77829b7e79219/Runtime/FancyStuff/Atom.cs

 

defer

C# implementations already exist. Since it's not supported at the language level, it's honestly a bit lukewarm. It's a feature that exists in Go as well, and it's almost at the level where it's weird that C# doesn't support it natively.

// Rewind the stream when exiting the block
using var _ = stream.Defer(stream => stream.Position = 0);

Source Code

https://github.com/sator-imaging/Unity-Fundamentals/blob/main/Runtime/System/Defer.cs

 

guard

The feature I want the most in C#, and also the most difficult one. I recently discovered a way to use a helper instead of ?? throw, but making it perform a return is absolutely impossible no matter how you try.

[DoesNotReturn] static T Throw<T>() => throw new Exception();

int? value = null;
var x = value ?? Throw<int>();

 

Conclusion

⬆⬆⬆ https://github.com/dotnet/csharplang/discussions/9695 ⬆⬆⬆

That's all. Thank you for your time.

References

脚注
  1. https://zenn.dev/sator_imaging/articles/a5d419867ff981#2.-actor-%3D-rust-が欲しかったやつ ↩︎

  2. https://zenn.dev/sator_imaging/articles/a5d419867ff981#2.-defer(raii-を構文にしたもの) ↩︎

Discussion