ufcpp-live / UfcppLiveAgenda

@ufcpp live streaming agenda
MIT License
24 stars 2 forks source link

.NET 9 Preview 5 / Visual Studio 17.11 Preview 2 #91

Open ufcpp opened 3 weeks ago

ufcpp commented 3 weeks ago

配信URL: https://www.youtube.com/live/BkN6_8ZQQW8

IDE

library

C

今回で ref/unsafe in iterators/async と ref struct interfaces 入ってる。

でも、runtime 側の、BCL に allows ref struct 付けるやつ(runtime 102795)は main に merge 済みだけど .NET 9p5 には含まれてなさげ。

Allow ref and unsafe in iterators and async

_ = Enumerate();
_ = GetAsync();
_ = EnumerateAsync();
_ = WarnEnumerate();

IEnumerable<object?> Enumerate()
{
    unsafe { }

    yield return null;

    Span<byte> data = [];

    yield return null;

    int x = 123;
    ref int r = ref x;
}

async Task GetAsync()
{
    unsafe { }

    await Task.Yield();

    Span<byte> data = [];

    await Task.Yield();

    int x = 123;
    ref int r = ref x;
}

async IAsyncEnumerable<object?> EnumerateAsync()
{
    unsafe { }

    await Task.Yield(); yield return null;

    Span<byte> data = [];

    await Task.Yield(); yield return null;

    int x = 123;
    ref int r = ref x;
}

IEnumerable<object?> WarnEnumerate()
{
    yield return null;

    var obj = new object();
    lock (obj)
    {
        // 元々バグで書けちゃってたらしい(lock 動く保証ない)。
        // 警告出るように。
        yield return null;
    }
}

allows ref struct

基本、型引数 where T : allows ref struct に対して Span とかと同じエスケープ解析してるだけっぽく、 C# 12 で ref struct に対してダメなことは T に対してもダメ。

なので入れ子ダメか…

ref struct Node<T>
{
    public T Value;
    public ref Node<T> Next; // これやっぱダメ見たい。
}

// これは行けるけど…
ref struct Ref<T>
{
    ref T Reference;
}

ref struct RefRef<T>
    where T : allows ref struct
{
    ref T Reference; // これはダメだって。
}

ValueTuple は allows ref じゃない…

int x = 1;
double y = 2;
var t = (new Ref<int>(ref x), new Ref<double>(ref y)); // ダメ

ref struct Ref<T>(ref T reference)
{
    ref T Reference = ref reference;
}

Span<Span> もダメだったみたいね。 (T[] 受け付けるコンストラクターをどうするの?問題があることは知ってたので「やっぱり」。)

ReadOnlySpan<byte> a = "abc"u8;
ReadOnlySpan<byte> b = "xyz"u8;

Span<ReadOnlySpan<byte>> x = [a, b]; // ダメ

てか、 runtime 102795 (BCL に allows ref 付ける作業)がまだ取り込まれてないっぽい。

Func<Span<byte>, int> f = x => x.Length; // 行けるようになるはず。たぶん。今ダメ。

なのでラムダ式の自然な型もまだ変化なし。(たぶん、予定では変わるはず?)

var f = int (int x) => x + 1;
Console.WriteLine(f.GetType().Name); // Func

var g = Span<int> (Span<int> x) => x;
Console.WriteLine(g.GetType().Name); // 今、コンパイラー生成匿名型になる。 Func<Span<int>, Span<int>> になる?

<ref T>

A<ref int> refAction; // これも認めてほしいけどねぇ。ダメ。

delegate void A<T>(T arg)
    where T : allows ref struct;

https://github.com/dotnet/csharplang/blob/main/proposals/ref-struct-interfaces.md#foreach-statement allows ref struct で foreach も行けるけど… 型引数2個渡さないといけなくてだるい…

C.Test3<MyEnumerable, MyEnumerator>(new MyEnumerable()); // これは行けるけど、
C.Test3(new MyEnumerable()); // 推論が無理。

struct MyEnumerable : IGetEnumerator<MyEnumerator>
{
    public MyEnumerator GetEnumerator() => new MyEnumerator();
}

struct MyEnumerator : IMyEnumerator<int>
{
    public int Current => throw new NotImplementedException();
    public bool MoveNext() => throw new NotImplementedException();
    public void Dispose() => throw new NotImplementedException();
}

interface IGetEnumerator<TEnumerator> where TEnumerator : allows ref struct
{
    TEnumerator GetEnumerator();
}
ufcpp-live commented 3 weeks ago
try
{
    await Task.WhenAll(t1, t2, t3, t4);
}
catch(Exception ex)// これの例外、最初の1個しか来ない。
{
    Console.WriteLine((t1.IsCompleted, t2.IsCompleted, t3.IsCompleted, t4.IsCompleted));
}
// 例外漏らしたくなければこう書いた方がいい気がする。
await foreach (var t in Task.WhenEach(t1, t2, t3, t4))
{
    try
    {
        await t;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
ufcpp-live commented 3 weeks ago

lock 抜けるときに例外出るやつ

foreach (var item in M())
{
    await Task.Delay(1);
}

static IEnumerable<object?> M()
{
    lock (new object())
    {
        yield return null;
    }
}
ufcpp-live commented 3 weeks ago
M<int, MyList, MyList.MyEnumerator>(new MyList());

static void M<TElement, TEnumerable, TEnumerator>(TEnumerable list)
    where TEnumerable : IEnumerable<TElement, TEnumerator>, allows ref struct
    where TEnumerator : IEnumerator<TElement>, allows ref struct
{
    foreach (var item in list)
    {
    }
}

interface IEnumerable<T, TEnumerator>
    where TEnumerator : IEnumerator<T>, allows ref struct
{
    TEnumerator GetEnumerator();
}

class MyList : IEnumerable<int, MyList.MyEnumerator>
{
    public MyEnumerator GetEnumerator() => new MyEnumerator();

    public struct MyEnumerator : IEnumerator<int>
    {
        public int Current => throw new NotImplementedException();

        object IEnumerator.Current => throw new NotImplementedException();

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public bool MoveNext()
        {
            throw new NotImplementedException();
        }

        public void Reset()
        {
            throw new NotImplementedException();
        }
    }
}
ufcpp-live commented 3 weeks ago
interface ICollection<T>
{
    public int Length { get; }

    [UnscopedRef]
    ref T this[int index] { get; }
}

readonly ref struct SpanWrapper<T>(Span<T> span) : ICollection<T>
{
    private readonly Span<T> _span = span;

    public int Length => _span.Length;

    // unscoped ref 要らない。
    public ref T this[int index] => ref _span[index];
}

struct Int4  : ICollection<int>
{
    private int _x0, _x1, _x2, _x3;

    public readonly int Length => 4;

    [UnscopedRef]
    public ref int this[int index] => ref Unsafe.Add(ref _x0, index);
}
ufcpp-live commented 3 weeks ago
ref struct S
{
    private Span<int> _span;

    // OK
    public void M1(Span<int> span) => _span = span;

    // ダメ。これが scoped の効果。
    public void M2(scoped Span<int> span) => _span = span;

    // ダメ。params は暗黙的に scoped になる。
    public void M3(params Span<int> span) => _span = span;
}
ufcpp-live commented 3 weeks ago
Handler M()
{
    Span<char> buffer = stackalloc char[256];

    var x = 1;
    Handler handler = default;
    handler.AppendFormatted(x);
    return handler;
}

ref struct Handler
{
    Span<char> 書き込み先;

    public void AppendFormatted<T>(in T value)
    {

    }

    public void AppendFormatted(scoped ReadOnlySpan<char> value)
    {
    }
}
ufcpp-live commented 3 weeks ago

exit code -2146232797.

image

ufcpp-live commented 3 weeks ago

image

ufcpp-live commented 3 weeks ago

image