ufcpp-live / UfcppLiveAgenda

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

VS 17.7 Preveiw 5 にコレクション式入ってた #75

Closed ufcpp closed 11 months ago

ufcpp commented 1 year ago

image

こんなアナウンスブログもなければ、リリースノートもバグ修正数行だけのリリースで新機能が追加されてるとか思わないじゃん?

↓みたいなコードは通るように。

int[] array = [1, 2, 3];
IEnumerable<string> list = ["abc", "ABC"];

とはいえなんか中途半端な状態。 たぶん .NET 8 RC 1 の頃にはもうちょっとまともになりそうなものの… 一応現状報告な配信を1回やろうかという感じに。

ufcpp commented 1 year ago

意図的に12からカットされてるやつ:

12までには入るはずだと思うけど今ないやつ:

ufcpp commented 1 year ago
using System.Collections;
using System.Runtime.CompilerServices;

MyArray<int> array = [1, 2, 3];

[CollectionBuilder(typeof(MyArray), nameof(MyArray.Create))] // 17.7p5 時点で効いてなさげ
struct MyArray<T> : IEnumerable<T>
{
    private readonly T[] _array;
    public MyArray(T[] items) => _array = items;
    public MyArray(IEnumerable<T> items) : this(items.ToArray()) { }
    public MyArray(ReadOnlySpan<T> items) : this(items.ToArray()) { }

    public IEnumerator<T> GetEnumerator() => _array.AsEnumerable().GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _array.GetEnumerator();

    public MyArray<T> Add(T item) => new(_array.Append(item));
}

class MyArray
{
    public static MyArray<T> Create<T>(ReadOnlySpan<T> items) => new(items);
}
ufcpp-live commented 1 year ago
// natural type 何にすべき?
var array = [1, 2, 3];

array.Add(4); // この需要はある = List

foreach (var x in [1,2,3,4,5,]) // アロケーションかかってほしくない = Span
{
}

これがあるのでC# 13行き。

ufcpp-live commented 1 year ago
List<string> list1 = ["abc", .. sub, .. ["", ""]]; // これ今ダメ。natural type 決まらない
List<string> list2 = ["abc", .. sub, .. ((string[])["", ""])]; // キャストちょいめんどい
ufcpp-live commented 1 year ago
using System.Collections;

// List<T> が実装しているインターフェイスなら通る。
// 全部実態は new List<T>();
IEnumerable<string> list = ["abc", "ABC"];
IList<string> l1 = [];
ICollection<string> l2 = [];
IEnumerable<string> l3 = [];
IReadOnlyList<string> s4 = [];
IReadOnlyCollection<string> s5 = [];

// List<T> が実装していないインターフェイスは通らない。
IReadOnlySet<string> s6 = [];

// non-generic 不可。
IList l7 = [];
ufcpp-live commented 1 year ago
// 現状(17.7p5時点) new string[]
// 最終的には InlineArray になる予定
ReadOnlySpan<string> x = ["a", "b"];
ufcpp-live commented 1 year ago
// コレクション初期化子が使えるものなら何でも行ける。
// ただし、Comparer 指定の手段なくなる。
HashSet<string> x = ["a", "b"];
ufcpp-live commented 1 year ago
// コレクション式は target-typed。
// これは右辺の時点で object[]。
object[] objList = ["a", "b"];
ufcpp-live commented 1 year ago
using System.Collections.Immutable;

// 現状(17.7p5時点)、昔ながらにコレクション初期化子が呼ばれる。
// default(ImmutableArray<string>).Add が呼ばれてぬるぽ。
ImmutableArray<string> objList = ["a", "b"];

// ↓
// 近々(おそらく .NET 8 Preview 7? RC 1?)で、
//  [CollectionBuilder(typeof(ImmutableArray), nameof(ImmutableArray.Create))] が付く
// そうすると、
// ImmutableArray.Create("a", "b") が呼ばれる。
ufcpp-live commented 1 year ago
// ※コレクション式だけ
// .NET 8 GA しても、↓はダメ。ぬるぽ。
ImmutableArray<string> objList = new() { "a", "b" };
ufcpp-live commented 1 year ago
// 配列に関しては {} と [] 同じ。
int[] a1 = { 1, 2, 3 };
int[] a2 = [ 1, 2, 3 ];

List<int> l1 = { 1, 2, 3 }; // ダメ
List<int> l2 = [1, 2, 3]; // OK

var x1 = new X
{
    A = { 1 }, // var x1 = new(); x1.A.Add(1); 扱い(ぬるぽる)。
    // こっちは init なくても平気。

    B = new() { 1 }, // アロケーション2重にかかるのいや
    B = { 1 }, // なので、B みたいなケースではこっちの方がいいはず。
};

var x2 = new X
{
    A = [ 1 ], // x1.A = new() { 1 } 扱い。大丈夫。
};

class X
{
    public List<int> A { get; init; }
    public List<int> B { get; init; } = new();
}
ufcpp-live commented 1 year ago
IList<int> l1 = [1, 2, 3]; // List<T> になっちゃう
IList<int> l2 = (int[])[1, 2, 3]; // まあ、キャストすれば?(ちゃんと int[] に)

「不要キャスト」リファクタリングが働いちゃってる。 バグ報告案件。

ufcpp-live commented 1 year ago
IList<int> l1 = [1, 2, 3]; // List<T> になっちゃう
IList<int> l2 = (int[])[1, 2, 3]; // まあ、キャストすれば?(ちゃんと int[] に)

byte[] x = new byte[0];
// ↓ 今、これにリファクタリングされる。
byte[] x = Array.Empty<byte>();
// ↓ 次、これに変換するリファクタリング入れるみたい。作業中。
byte[] x = [];
ufcpp-live commented 1 year ago
Sum([1, 2, 3]);

static int Sum(IEnumerable<int>? items)
{
    // 現状(17.7p5時点)、 [] は new List<int>() になっちゃうんで、アロケーションかかる。
    // 将来の最適化どうだったかちょっと忘れた。
    var sum = 0;
    foreach (var item in items ?? []) sum += item;
    return sum;
}
ufcpp-live commented 1 year ago
Sum([1, 2, 3]);

static int Sum(IEnumerable<int>? items)
{
    var sum = 0;
    // foreach? (var item in items) // これで if (items != null) 判定入れてほしいという話もある
    // 今、↓これでいいじゃん?って空気になりがち。
    foreach (var item in items ?? []) sum += item;
    return sum;
}