Здравствуйте, samius, Вы писали:
S>Возражаю, не нужен такой констрейнт. Контракт на IDisposable предполагает возможность многократного вызова метода Dispose() и только. А флаги об успешном освобождении ресурса вовсе не обязательно держать в теле структуры.
Ну-ну.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, samius, Вы писали:
S>>Возражаю, не нужен такой констрейнт. Контракт на IDisposable предполагает возможность многократного вызова метода Dispose() и только. А флаги об успешном освобождении ресурса вовсе не обязательно держать в теле структуры.
IT>Ну-ну.
Using(new List<int>().GetEnumerator(), myStruct => myStruct.MoveNext())
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, samius, Вы писали:
IT>>>Ну-ну. S>>Using(new List<int>().GetEnumerator(), myStruct => myStruct.MoveNext())
IT>Как насчёт железной ленейкой по пальцам за такое?
После того как компилятор запретит стейтмент using для страктов покорно приму линейкой.
Здравствуйте, samius, Вы писали:
IT>>>>Ну-ну. S>>>Using(new List<int>().GetEnumerator(), myStruct => myStruct.MoveNext()) IT>>Как насчёт железной ленейкой по пальцам за такое? S>После того как компилятор запретит стейтмент using для страктов покорно приму линейкой.
А пока буду морозить уши назло маме?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, samius, Вы писали:
IT>>>Как насчёт железной ленейкой по пальцам за такое? S>>После того как компилятор запретит стейтмент using для страктов покорно приму линейкой.
IT>А пока буду морозить уши назло маме?
Почему маме? Только тем, кто считает что struct не должен быть IDisposable.
И уши будут морозить вместе со мной все, кто использует итерацию в foreach-е по List<T>.
Здравствуйте, samius, Вы писали:
S>И уши будут морозить вместе со мной все, кто использует итерацию в foreach-е по List<T>.
Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные.
И да, struct: IDisposable (да и вообще любой mutable-интерфейс для value-типов) — зло в чистейшем виде. Ибо допустить косяки при их использовании намного проще, чем не допустить.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>И уши будут морозить вместе со мной все, кто использует итерацию в foreach-е по List<T>. S>Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные.
Полагаю что для перечислителя списка и других подобных ему страктов это не существенно.
Тем более, что диспозиться должно то, что было выделено, а не то что менялось. Здесь я говорю о значении, а не об экземпляре.
Если копия стракта (пусть измененная, или нет, не важно) освобождает не то, что было выделено и положено в оригинал, то это проблема реализации стракта и интерфейса IDisposable, а не проблема создания лишней копии.
S>И да, struct: IDisposable (да и вообще любой mutable-интерфейс для value-типов) — зло в чистейшем виде. Ибо допустить косяки при их использовании намного проще, чем не допустить.
Видимо, разработчики фреймворка с вами не совсем согласны, иначе не разложили бы грабли с чистейшим 3х-кратным (аж 3 изменяемых интерфейса) злом в столь частоиспользуемом месте, как List<T>.
Хотя, я согласен что это зло. Но оно заключается не в реализации интерфейсов страктами, а в самой природе изменяемых страктов. Зло космическое, но не столь ужасное, что бы запрещать изменяемые стракты на уровне CLR или языка. И если уж что и надо было запрещать, то не передачу страктов (всех без разбора) в некий метод, а саму возможность существования изменяемых страктов, причем, с рождения, а не теперь. Но все, поезд ушел, и теперь надо не запрещать, а учить обращаться с такими вещами.
Вот как сейчас никто не пытается запретить кастом реализацию IComparer интерфейса, но грабли там кое-какие имеются в виде требований рефлексивности, антисимметричности и транзитивности. Куча народу уже набили шишки этими граблями,причем, многие даже не поняли за что именно. Вот так же надо выдвигать требования к реализации структурами мутабельных интерфейсов, в том числе IDisposable.
Здравствуйте, samius, Вы писали:
S>>Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные. S>Полагаю что для перечислителя списка и других подобных ему страктов это не существенно.
Угу. Осталось рассказать об том всем, кто пишет подобные структуры на шарпе
Лучше уж сначала сделать ограничение, если припрёт — снять, чем потом держать неправильный код годами из-за совместимости.
Тем более что в таких структурах практически нет смысла. Для числодробилок всё понятно: используем массивы и не страдаем фигнёй. Для остального надо делать вызовы миллионами, чтоб была хоть какая-то разница.
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);
}
}
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>>Кэп: в foreach будет одна копия. У вас изменяться и диспозиться будут разные. S>>Полагаю что для перечислителя списка и других подобных ему страктов это не существенно. S>Угу. Осталось рассказать об том всем, кто пишет подобные структуры на шарпе
Под подобными я подразумевал не всевозможные структуры с первой попавшейся реализацией изменяемых интерфейсов, а структуры, чей Dispose не ломается от копирования. S>Лучше уж сначала сделать ограничение, если припрёт — снять, чем потом держать неправильный код годами из-за совместимости.
Неправильный код лучше не писать, и уж тем более не стоит держать его годами. Что там неправильного, я так и не осилил.
S>Тем более что в таких структурах практически нет смысла. Для числодробилок всё понятно: используем массивы и не страдаем фигнёй.
Для числодробилок используем C++ и не страдаем фигней. Если не хочется страдать C++-ом, то массивы, конечно, не решают все задачи полностью. Они хороши там, где можно сначала один раз получить массив, а потом бегать по нему сколько влезет. Когда же придется менять коллекцию динамически и довольно часто, то фигней все же будет страдать тот, кто будет для этого использовать массив, а не List<T>. Особенно на миллионных размерах коллекции.
S>Для остального надо делать вызовы миллионами, чтоб была хоть какая-то разница.
Да, представляете, бывают задачи, где надо делать вызовы миллионами! И разница в таких задачах может быть существенна, а не просто какая-то.
Но я не пойму, чего мы обсуждаем констрейнт у функции? Если есть одна функция с констрейнтом, то можно написать свою без констрейнта. И к дизайну очередной версии языка это отношения не имеет.
Напомню, меня же интересовал експрешн (не для ExpressionTree) using (в общем случае try/finally) без оборачивания его в функцию. Обернуть-то и сейчас можно.