Re[6]: [C# 7] Design notes, Mar 18
От: IT Россия linq2db.com
Дата: 19.05.15 23:01
Оценка:
Здравствуйте, samius, Вы писали:

S>Возражаю, не нужен такой констрейнт. Контракт на IDisposable предполагает возможность многократного вызова метода Dispose() и только. А флаги об успешном освобождении ресурса вовсе не обязательно держать в теле структуры.


Ну-ну.
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: [C# 7] Design notes, Mar 18
От: samius Япония http://sams-tricks.blogspot.com
Дата: 20.05.15 03:03
Оценка: :)
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, samius, Вы писали:


S>>Возражаю, не нужен такой констрейнт. Контракт на IDisposable предполагает возможность многократного вызова метода Dispose() и только. А флаги об успешном освобождении ресурса вовсе не обязательно держать в теле структуры.


IT>Ну-ну.

Using(new List<int>().GetEnumerator(), myStruct => myStruct.MoveNext())
Re[8]: [C# 7] Design notes, Mar 18
От: IT Россия linq2db.com
Дата: 20.05.15 04:05
Оценка: +1
Здравствуйте, samius, Вы писали:

IT>>Ну-ну.

S>Using(new List<int>().GetEnumerator(), myStruct => myStruct.MoveNext())

Как насчёт железной ленейкой по пальцам за такое?
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: [C# 7] Design notes, Mar 18
От: samius Япония http://sams-tricks.blogspot.com
Дата: 20.05.15 04:09
Оценка:
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, samius, Вы писали:


IT>>>Ну-ну.

S>>Using(new List<int>().GetEnumerator(), myStruct => myStruct.MoveNext())

IT>Как насчёт железной ленейкой по пальцам за такое?

После того как компилятор запретит стейтмент using для страктов покорно приму линейкой.
Re[10]: [C# 7] Design notes, Mar 18
От: IT Россия linq2db.com
Дата: 20.05.15 13:17
Оценка:
Здравствуйте, samius, Вы писали:

IT>>>>Ну-ну.

S>>>Using(new List<int>().GetEnumerator(), myStruct => myStruct.MoveNext())
IT>>Как насчёт железной ленейкой по пальцам за такое?
S>После того как компилятор запретит стейтмент using для страктов покорно приму линейкой.

А пока буду морозить уши назло маме?
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: [C# 7] Design notes, Mar 18
От: samius Япония http://sams-tricks.blogspot.com
Дата: 20.05.15 13:56
Оценка: +2
Здравствуйте, IT, Вы писали:

IT>Здравствуйте, samius, Вы писали:


IT>>>Как насчёт железной ленейкой по пальцам за такое?

S>>После того как компилятор запретит стейтмент using для страктов покорно приму линейкой.

IT>А пока буду морозить уши назло маме?

Почему маме? Только тем, кто считает что struct не должен быть IDisposable.
И уши будут морозить вместе со мной все, кто использует итерацию в foreach-е по List<T>.
Re[12]: [C# 7] Design notes, Mar 18
От: Sinix  
Дата: 20.05.15 14:27
Оценка:
Здравствуйте, samius, Вы писали:

S>И уши будут морозить вместе со мной все, кто использует итерацию в foreach-е по List<T>.

Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные.

И да, struct: IDisposable (да и вообще любой mutable-интерфейс для value-типов) — зло в чистейшем виде. Ибо допустить косяки при их использовании намного проще, чем не допустить.
Re[13]: [C# 7] Design notes, Mar 18
От: samius Япония http://sams-tricks.blogspot.com
Дата: 20.05.15 16:09
Оценка: +2
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, samius, Вы писали:


S>>И уши будут морозить вместе со мной все, кто использует итерацию в foreach-е по List<T>.

S>Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные.
Полагаю что для перечислителя списка и других подобных ему страктов это не существенно.
Тем более, что диспозиться должно то, что было выделено, а не то что менялось. Здесь я говорю о значении, а не об экземпляре.
Если копия стракта (пусть измененная, или нет, не важно) освобождает не то, что было выделено и положено в оригинал, то это проблема реализации стракта и интерфейса IDisposable, а не проблема создания лишней копии.

S>И да, struct: IDisposable (да и вообще любой mutable-интерфейс для value-типов) — зло в чистейшем виде. Ибо допустить косяки при их использовании намного проще, чем не допустить.

Видимо, разработчики фреймворка с вами не совсем согласны, иначе не разложили бы грабли с чистейшим 3х-кратным (аж 3 изменяемых интерфейса) злом в столь частоиспользуемом месте, как List<T>.
Хотя, я согласен что это зло. Но оно заключается не в реализации интерфейсов страктами, а в самой природе изменяемых страктов. Зло космическое, но не столь ужасное, что бы запрещать изменяемые стракты на уровне CLR или языка. И если уж что и надо было запрещать, то не передачу страктов (всех без разбора) в некий метод, а саму возможность существования изменяемых страктов, причем, с рождения, а не теперь. Но все, поезд ушел, и теперь надо не запрещать, а учить обращаться с такими вещами.
Вот как сейчас никто не пытается запретить кастом реализацию IComparer интерфейса, но грабли там кое-какие имеются в виде требований рефлексивности, антисимметричности и транзитивности. Куча народу уже набили шишки этими граблями,причем, многие даже не поняли за что именно. Вот так же надо выдвигать требования к реализации структурами мутабельных интерфейсов, в том числе IDisposable.
Re[14]: [C# 7] Design notes, Mar 18
От: Sinix  
Дата: 21.05.15 06:15
Оценка:
Здравствуйте, samius, Вы писали:


S>>Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные.

S>Полагаю что для перечислителя списка и других подобных ему страктов это не существенно.
Угу. Осталось рассказать об том всем, кто пишет подобные структуры на шарпе
Лучше уж сначала сделать ограничение, если припрёт — снять, чем потом держать неправильный код годами из-за совместимости.

Тем более что в таких структурах практически нет смысла. Для числодробилок всё понятно: используем массивы и не страдаем фигнёй. Для остального надо делать вызовы миллионами, чтоб была хоть какая-то разница.
         array:   342ms, ips:       2 922 833 113,83 | Mem:   8,00 kb, GC0: 0 => 1000000000
          list:  2857ms, ips:         350 003 155,28 | Mem:   8,00 kb, GC0: 0 => 1000000000
    enumerable:  7082ms, ips:         141 186 108,45 | Mem: 840,04 kb, GC0: 1 => 1000000000
          linq:  7106ms, ips:         140 721 245,64 | Mem:  56,04 kb, GC0: 1 => 1000000000
        linq 2:  9653ms, ips:         103 591 285,06 | Mem: 840,10 kb, GC0: 1 => 1000000000



  код:
using System;
using System.Diagnostics;
using System.Linq;

class Program
{

    static void Main()
    {
        Console.WindowHeight = 30;
        Console.WindowWidth = 120;

        const int RepeatCount = 100 * 1000;
        const int Size = 10 * 1000;
        var rnd = new Random(0);

        var items = Enumerable.Range(1, Size)
            .Select(i => (long)rnd.Next())
            .ToArray();
        var list = items.ToList();
        var enumerable = list.AsEnumerable();

        Measure("array", () =>
        {
            long result = 0;
            for (int i = 0; i < RepeatCount; i++)
            {
                result = 0;
                foreach (var item in items)
                {
                    result += item;
                }
            }
            return RepeatCount * Size;
        });

        Measure("list", () =>
        {
            long result = 0;
            for (int i = 0; i < RepeatCount; i++)
            {
                result = 0;
                foreach (var item in list)
                {
                    result += item;
                }
            }
            return RepeatCount * Size;
        });

        Measure("enumerable", () =>
        {
            long result = 0;
            for (int i = 0; i < RepeatCount; i++)
            {
                result = 0;
                foreach (var item in enumerable)
                {
                    result += item;
                }
            }
            return RepeatCount * Size;
        });

        Measure("linq", () =>
        {
            long result = 0;
            for (int i = 0; i < RepeatCount; i++)
            {
                result = items.Sum();
            }
            return RepeatCount * Size;
        });

        Measure("linq 2", () =>
        {
            long result = 0;
            for (int i = 0; i < RepeatCount; i++)
            {
                result = enumerable.Aggregate(0L, (k, j) => k + j);
            }
            return RepeatCount * Size;
        });

        Console.Write("Done.");
        Console.ReadKey();
    }


    static void Measure(string name, Func<long> callback)
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        var mem = GC.GetTotalMemory(true);
        var gc = GC.CollectionCount(0);

        var sw = Stopwatch.StartNew();
        var result = callback();
        sw.Stop();

        var mem2 = GC.GetTotalMemory(false);
        var gc2 = GC.CollectionCount(0);

        var memDelta = (mem2 - mem) / 1024.0;
        var gcDelta = gc2 - gc;

        Console.WriteLine(
            "{0,14}: {1,5}ms, ips: {2,22:N} | Mem: {3,6:N2} kb, GC0: {4} => {5,6}",
            name, sw.ElapsedMilliseconds, result / sw.Elapsed.TotalSeconds, memDelta, gcDelta, result);
    }
}
Re[15]: [C# 7] Design notes, Mar 18
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.05.15 14:54
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, samius, Вы писали:



S>>>Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные.

S>>Полагаю что для перечислителя списка и других подобных ему страктов это не существенно.
S>Угу. Осталось рассказать об том всем, кто пишет подобные структуры на шарпе
Под подобными я подразумевал не всевозможные структуры с первой попавшейся реализацией изменяемых интерфейсов, а структуры, чей Dispose не ломается от копирования.
S>Лучше уж сначала сделать ограничение, если припрёт — снять, чем потом держать неправильный код годами из-за совместимости.
Неправильный код лучше не писать, и уж тем более не стоит держать его годами. Что там неправильного, я так и не осилил.

S>Тем более что в таких структурах практически нет смысла. Для числодробилок всё понятно: используем массивы и не страдаем фигнёй.

Для числодробилок используем C++ и не страдаем фигней. Если не хочется страдать C++-ом, то массивы, конечно, не решают все задачи полностью. Они хороши там, где можно сначала один раз получить массив, а потом бегать по нему сколько влезет. Когда же придется менять коллекцию динамически и довольно часто, то фигней все же будет страдать тот, кто будет для этого использовать массив, а не List<T>. Особенно на миллионных размерах коллекции.

S>Для остального надо делать вызовы миллионами, чтоб была хоть какая-то разница.

Да, представляете, бывают задачи, где надо делать вызовы миллионами! И разница в таких задачах может быть существенна, а не просто какая-то.
Но я не пойму, чего мы обсуждаем констрейнт у функции? Если есть одна функция с констрейнтом, то можно написать свою без констрейнта. И к дизайну очередной версии языка это отношения не имеет.
Напомню, меня же интересовал експрешн (не для ExpressionTree) using (в общем случае try/finally) без оборачивания его в функцию. Обернуть-то и сейчас можно.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.