Свеженькое (ну, относительно ) о _возможных_ добавлениях в c#7:
Non-nullable reference types (already working on them)
Non-nullary constructor constraints (require CLR support)
Support for INotifyPropertyChanged (too specific; metaprogramming?)
GPU and DirectX support (mostly library work; numeric constraints?)
Extension properties and static members (certainly interesting)
More code analysis (this is what Roslyn analyzers are for)
Extension methods in instance members (fair request, small)
Unmanaged constraint (requires CLR support)
Mulitple returns (working on it, via tuples)
ISupportInitialize (too specific; hooks on object initializers?)
Statement lambdas in expression trees (fair request, big feature!)
Language support for Lists, Dictionaries and Tuples (Fair; already working on tuples)
Don't instantiate C![] : it's elements would be null.
This seems like a draconian restriction — as long as you only ever read fields from the array that were previously written,
no-one would observe the default value. Many data structures wrapping arrays observe this discipline.
Всё обсуждение тоже советую почитать, там очень любопытный и подробный комментарий Мэтта Торвальдсена про "string == string!". Как всегда, некоторые вещи надо делать с самого начала...
Здравствуйте, Sinix, Вы писали:
S>Всё обсуждение тоже советую почитать, там очень любопытный и подробный комментарий Мэтта Торвальдсена про "string == string!".
Все Ок, только Мэдса зовут Мэдс Торгерсен (Mads Torgersen) =)
Здравствуйте, VladD2, Вы писали:
VD>Ух! Ну, хорошо, что не Ингеборга Дапкунайте (человек-скороговорка).
Да ну! Я общался с чуваком по имени Анандхариву Джхаранджья. Вот это — скороговорка.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Да ну! Я общался с чуваком по имени Анандхариву Джхаранджья. Вот это — скороговорка.
Да фиг с ним, с индусом. То как ты с Рихтером общался, не затмит ничто и останется на вечно! =)) И, что характерно, Мэдс принимал в этом диалоге посильное участие — если возвращаться к теме топика
Здравствуйте, Sinix, Вы писали:
S>Что-то все забыли про сабж.
Интересно, никому не приходило в голову что Expression Bodied Functions and Properties хорошо бы дополнить возможностью использовать using statement в качестве expression? Да и само по себе using expression кажется весьма полезным на первый взгляд.
S>Интересно, никому не приходило в голову что Expression Bodied Functions and Properties хорошо бы дополнить возможностью использовать using statement в качестве expression? Да и само по себе using expression кажется весьма полезным на первый взгляд.
Что-то типа
using x = (string a) => int.Parse(a);
...
var b = x("123");
?
Не, нафиг-нафиг. Получится что-то типа текстовых макросов с, только ещё и живущих в рамках одного файла. Используйте методы, тем более что с инлайном простых выражений особых проблем нет.
S>using x = (string a) => int.Parse(a);
S>...
S>var b = x("123");
S>
S>?
S>Не, нафиг-нафиг. Получится что-то типа текстовых макросов с, только ещё и живущих в рамках одного файла. Используйте методы, тем более что с инлайном простых выражений особых проблем нет.
Речь про то, что return из using (var r = ...) { } делать можно, но сам он не является выражением, что препятствует написанию
public string GetSomething(string a) => using (var r = GetR(a)) { [return] r.DoSomething(); }
Здравствуйте, Sinix, Вы писали:
S>Всё обсуждение тоже советую почитать, там очень любопытный и подробный комментарий Мэтта Торвальдсена про "string == string!". Как всегда, некоторые вещи надо делать с самого начала...
А почему нельзя сделать новую версию компилятора и сломать совместимость со старыми граблями? В новом коде ставить какую-нибудь директиву, предписывающую компилировать по новым правилам.
Здравствуйте, samius, Вы писали:
S>Речь про то, что return из using (var r = ...) { } делать можно, но сам он не является выражением, что препятствует написанию
public string GetSomething(string a) => using (var r = GetR(a)) { [return] r.DoSomething(); }
Ну, т.е. нужно добавить новую фичу в язык, чтобы можно было не писать "{ ... }". Это при том, что и исходный лямбда-синтаксис без поддержки pure-методов тоже не очень нужен был.
Нафиг-нафиг. А то потом понадобится for/if expressions, затем semicolon operator, затем last statement as return и всё это потому, что девелопер хочет запихнуть в одно выражение всё тело метода.
Если совсем коротко:
1. не надо хороший язык превращать в PHP
2. у statement и expression есть чёткое разделение: последнее не приносит побочных эффектов, по крайней мере, не должно. Во времена раннего шарпа это кучу раз обсуждалось, в последнее время под наплывом начинающих разработчиков про это все основательно забыли
Ну и взгляд на это же дело из лагеря F#. Автор отмороженный на всю голову (в хорошем смысле) фанат функционального программирования, читать с осторожностью
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>Ну, т.е. нужно добавить новую фичу в язык, чтобы можно было не писать "{ ... }". Это при том, что и исходный лямбда-синтаксис без поддержки pure-методов тоже не очень нужен был. S>Нафиг-нафиг. А то потом понадобится for/if expressions, затем semicolon operator, затем last statement as return и всё это потому, что девелопер хочет запихнуть в одно выражение всё тело метода.
Мы ведь это обсуждаем как раз в контексте новой фичи, позволяющей не писать "{ ... }" для методов и свойств, записываемых одним выражением.
if-у есть замена ?:, а for expression это ИМХО перебор.
S>Если совсем коротко: S>1. не надо хороший язык превращать в PHP S>2. у statement и expression есть чёткое разделение: последнее не приносит побочных эффектов, по крайней мере, не должно. Во времена раннего шарпа это кучу раз обсуждалось, в последнее время под наплывом начинающих разработчиков про это все основательно забыли
Это не аргумент против using-expression, т.к. будучи обернутым в тело метода, using statement может (но вовсе не обязан) натворить побочных эффектов, и сойдет за варажение.
S>Конкретно для шарпа: S>http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx S>http://stackoverflow.com/questions/19132/expression-versus-statement
Я знаю, чем отличается выражение от стейтмента
S>Ну и взгляд на это же дело из лагеря F#. Автор отмороженный на всю голову (в хорошем смысле) фанат функционального программирования, читать с осторожностью
Кстати, в F# try/catch, try/finally являются выражениями, а use keyword работает практически как let-binding. Да и методы могут объявляться без скобочек. F# уже PHP, или еще не дорос?
Здравствуйте, samius, Вы писали:
S>>Нафиг-нафиг. А то потом понадобится for/if expressions, затем semicolon operator, затем last statement as return и всё это потому, что девелопер хочет запихнуть в одно выражение всё тело метода. S>Мы ведь это обсуждаем как раз в контексте новой фичи, позволяющей не писать "{ ... }" для методов и свойств, записываемых одним выражением.
Ну а смысл пытаться запихнуть в одно выражение то, что в него не лезет?
Код пишут для того, чтоб его читали и поддерживали, а не чтобы LoC экономить.
Уже есть стандартные coding guidelines, которые в частности рекомендуют сразу использовать полную форму, например
if (SomeCondition)
{
DoSomething();
}
// вместоif (SomeCondition)
DoSomething();
Причин этому куча, самые простые: меньше дурацких ошибок, одинаковый стиль кода, при правках не надо впихивать/убирать скобки, они есть всегда.
Нет блин, хочется сначала понаступать на те же грабли, а затем добавлять coding guidelines уже для expression-ов
S>if-у есть замена ?:, а for expression это ИМХО перебор.
т.е. using — это не перебор? Как насчёт foreach/ifelse? Вложенные ifelse кстати лучше читаются, чем "?:".
+ надо помнить, что expression-ы могут использоваться везде, т.е. using внутри linq — уже легальная штука. Получаем правку expression trees, костыли ко всем linq-провайдерам и невозможность компиляции кода под младшие версии фреймворка. Зашибись исправленьице, да?
S>Это не аргумент против using-expression, т.к. будучи обернутым в тело метода, using statement может (но вовсе не обязан) натворить побочных эффектов, и сойдет за варажение.
Скажем так: есть хороший дизайн, который надо постараться чтобы использовать неправильно, а есть фиговый дизайн, который фиг используешь правильно, зато ошибки допускаются на раз-два.
Плохой — это не значит "намеренно сделан плохим", всё проще: дизайн ваял человек, который не знает/не заботится о _реальных_ сценариях использования.
Каждое "фигак-фигак и в продакшн" само по себе может и неплохо, но в итоге любой долгоживущий код превращается в маленький кошмар. Потому что человек А зафанател от ФП и прикрутил всё на выражениях, человек Б упростил всё до хелперов, человек C поверх этого написал оппа-оппа-интерн-стайл и всё это в конце уходит на поддержку к самым квалифицированным специалистам, потому что 1: срочно, 2: никто больше не разберётся
Не, можно утвердить стандарт кодирования, втащить код-ревью и просто не допускать неправильных сценариев, но это опять-таки работа на ровном месте, из разряда "лишь бы не как раньше".
К сожалению, чтобы прочувствовать всю прелесть решений "ты усложняешь, всё ж просто?" надо поработать над большим (т.е. в принципе не делается одной группой из 5-10 человек) долгоживущим (минимум 2-3 года продуктивной разработки) проектом. И вот когда три года твоей работы придётся или закопать из-за "всё-просто" решений или ценой усилий всей команды оставить свою часть в отличном состоянии — вот тогда к фигак-фигак нарабатывается очень здоровый скептицизм.
Да, вполне возможно я ошибаюсь и рано или поздно using expr в шарпе появится. Но и тогда я могу быть уверен, что перед добавлением c# team рассмотрела все косяки и corner cases (типа возни с expression trees) и или документировала их, или предусмотрела какое-то решение на будущее. Т.е. с меня эта головная боль снята
В общем, это всё тот же вопрос о последствиях расширении языка неспециалистами. Кто пробовал — больше что-то не хочет.
Так вот, using в expression-ах — это плохой дизайн. Именно потому, что использование юзиногв обычно предполагает внесение неявных побочных эффектов.
Если уж припёрло — такие вещи надо всё-таки явно документировать, вытащив в отдельный метод, а не смешивать pure и impure-часть.
S>>Ну и взгляд на это же дело из лагеря F#. Автор отмороженный на всю голову (в хорошем смысле) фанат функционального программирования, читать с осторожностью S>Кстати, в F# try/catch, try/finally являются выражениями, а use keyword работает практически как let-binding. Да и методы могут объявляться без скобочек. F# уже PHP, или еще не дорос?
Не дорос. Потому что f# с самого начала был FP-языком, большинство стейтментов в нём — pure, mutable декларируется явно. Поэтому "всё есть выражение" на F# ложится очень классно.
На изначально олдскульно-императивный шарп ФП-заморочки напротив, налезают с трудом. Потому что реальный код и реальный API не заточены под принятые в ФП сценарии использования. Следовательно, или новые добавления будут использоваться в мизерных количествах в весьма специфичном коде, или будут использоваться во вред.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Мы ведь это обсуждаем как раз в контексте новой фичи, позволяющей не писать "{ ... }" для методов и свойств, записываемых одним выражением. S>Ну а смысл пытаться запихнуть в одно выражение то, что в него не лезет?
В F# залезло S>Код пишут для того, чтоб его читали и поддерживали, а не чтобы LoC экономить. S>Уже есть стандартные coding guidelines, которые в частности рекомендуют сразу использовать полную форму, например S>
S> if (SomeCondition)
S> {
S> DoSomething();
S> }
S>// вместо
S> if (SomeCondition)
S> DoSomething();
S>
S>Причин этому куча, самые простые: меньше дурацких ошибок, одинаковый стиль кода, при правках не надо впихивать/убирать скобки, они есть всегда.
S>Нет блин, хочется сначала понаступать на те же грабли, а затем добавлять coding guidelines уже для expression-ов
Expression Bodied Functions уже наступили на все грабли. И не я их предложил. То есть скобки и грабли с гайдлайнами не аргумент в случае Expression Bodied Functions, но почему-то аргумент в случае using...
S>>if-у есть замена ?:, а for expression это ИМХО перебор. S>т.е. using — это не перебор? Как насчёт foreach/ifelse? Вложенные ifelse кстати лучше читаются, чем "?:".
S>+ надо помнить, что expression-ы могут использоваться везде, т.е. using внутри linq — уже легальная штука. Получаем правку expression trees, костыли ко всем linq-провайдерам и невозможность компиляции кода под младшие версии фреймворка. Зашибись исправленьице, да?
Ненене, Дэвид Блейн! Не все что можно засунуть легально в expression проглотят linq-провайдеры и это не приводит к костылям. Поэтому не аргумент.
S>>Это не аргумент против using-expression, т.к. будучи обернутым в тело метода, using statement может (но вовсе не обязан) натворить побочных эффектов, и сойдет за варажение. S>Скажем так: есть хороший дизайн, который надо постараться чтобы использовать неправильно, а есть фиговый дизайн, который фиг используешь правильно, зато ошибки допускаются на раз-два. S>Плохой — это не значит "намеренно сделан плохим", всё проще: дизайн ваял человек, который не знает/не заботится о _реальных_ сценариях использования.
S>Каждое "фигак-фигак и в продакшн" само по себе может и неплохо, но в итоге любой долгоживущий код превращается в маленький кошмар. Потому что человек А зафанател от ФП и прикрутил всё на выражениях, человек Б упростил всё до хелперов, человек C поверх этого написал оппа-оппа-интерн-стайл и всё это в конце уходит на поддержку к самым квалифицированным специалистам, потому что 1: срочно, 2: никто больше не разберётся
S>Не, можно утвердить стандарт кодирования, втащить код-ревью и просто не допускать неправильных сценариев, но это опять-таки работа на ровном месте, из разряда "лишь бы не как раньше".
Expression Bodied Functions потребуют утверждения стандартов кодирования. На том же ровном месте.
S>К сожалению, чтобы прочувствовать всю прелесть решений "ты усложняешь, всё ж просто?" надо поработать над большим (т.е. в принципе не делается одной группой из 5-10 человек) долгоживущим (минимум 2-3 года продуктивной разработки) проектом. И вот когда три года твоей работы придётся или закопать из-за "всё-просто" решений или ценой усилий всей команды оставить свою часть в отличном состоянии — вот тогда к фигак-фигак нарабатывается очень здоровый скептицизм.
Работал на проектах и побольше. И мне не очевидно, почему такие проекты придется закапывать из-за using-expression.
S>Да, вполне возможно я ошибаюсь и рано или поздно using expr в шарпе появится. Но и тогда я могу быть уверен, что перед добавлением c# team рассмотрела все косяки и corner cases (типа возни с expression trees) и или документировала их, или предусмотрела какое-то решение на будущее. Т.е. с меня эта головная боль снята
Вопрос был изначально не в том, что бы на кого-то повесить головную боль, а в том, не приходило ли кому в голову, не обсуждалось ли? И только лишь.
S>В общем, это всё тот же вопрос о последствиях расширении языка неспециалистами. Кто пробовал — больше что-то не хочет.
S>Так вот, using в expression-ах — это плохой дизайн. Именно потому, что использование юзиногв обычно предполагает внесение неявных побочных эффектов. S>Если уж припёрло — такие вещи надо всё-таки явно документировать, вытащив в отдельный метод, а не смешивать pure и impure-часть.
pure и impure отлично смешиваются и без using-ов. да и никто не озаботился явной документацией pure и impure.
S>>Кстати, в F# try/catch, try/finally являются выражениями, а use keyword работает практически как let-binding. Да и методы могут объявляться без скобочек. F# уже PHP, или еще не дорос? S>Не дорос. Потому что f# с самого начала был FP-языком, большинство стейтментов в нём — pure, mutable декларируется явно. Поэтому "всё есть выражение" на F# ложится очень классно.
S>На изначально олдскульно-императивный шарп ФП-заморочки напротив, налезают с трудом. Потому что реальный код и реальный API не заточены под принятые в ФП сценарии использования. Следовательно, или новые добавления будут использоваться в мизерных количествах в весьма специфичном коде, или будут использоваться во вред.
F# как раз заточен на работу в том же рантайме и том же фреймворке, что и C#. Кейворд use в частности заточен на работу с IDisposable, сценарии использования которого в точности совпадают со сценариями его использования на C#.
Здравствуйте, Sinix, Вы писали:
S> Mulitple returns (working on it, via tuples)
А чего за этим зайцем-то погнались? Кому-то сахара не хватает? Вот серьёзно, кто-то может привести пример реального кода, который станет "гораздо более лучше" с множественным возвратом?
Т.е. вдруг я отстал от жизни и что-то реально упускаю?
Здравствуйте, Mr.Delphist, Вы писали:
S>> Mulitple returns (working on it, via tuples) MD>Вот серьёзно, кто-то может привести пример реального кода, который станет "гораздо более лучше" с множественным возвратом?
Для существующих областей применения шарпа — нет его практически. Лучше бы declaration expressions для
if (int.TryParse(input, out var x))
{
// use x
}
сделали. Пока про них ничего не слышно, но это и понятно — для c#7 только-только предложения отбираются.
Но во-первых, бардак с тюплами/анонимными типами и рекордами надо бы свести к одному знаменателю. В связи с добавлением паттерн-матчинга это особенно актуально. Иначе получится один синтаксис для ПМ, другой для разбора/сбора тюплов, третий — для рекордов и тд.
И во вторых, шарп пытаются сделать более дружественным к скриптовому стилю в связи с свежим asp.next и попытками привлечь линуксоводов и мобильных разработчиков. Хорошо это или плохо — это уже как кому нравится.
S>>Нет блин, хочется сначала понаступать на те же грабли, а затем добавлять coding guidelines уже для expression-ов S>Expression Bodied Functions уже наступили на все грабли. И не я их предложил. То есть скобки и грабли с гайдлайнами не аргумент в случае Expression Bodied Functions, но почему-то аргумент в случае using...
Потому что exp bodied хороши для существующих выражений. А вот попытка добавить impure-выражения испортит и expression bodied тоже. Потому что смысл в них окончательно потеряется.
S>>+ надо помнить, что expression-ы могут использоваться везде, т.е. using внутри linq — уже легальная штука. Получаем правку expression trees, костыли ко всем linq-провайдерам и невозможность компиляции кода под младшие версии фреймворка. Зашибись исправленьице, да? S>Ненене, Дэвид Блейн! Не все что можно засунуть легально в expression проглотят linq-провайдеры и это не приводит к костылям. Поэтому не аргумент.
А, ну т.е. ешё хуже решение. Теперь у нас есть выражения для expression-tree и выражения, которые не подходят для expression-tree и всё это ещё и различается для разных версий фреймворка. Как человек, писавший хоть и наколенный, но linq-провайдер — поверьте, там и без этого геммороя хватает
S>>Не, можно утвердить стандарт кодирования, втащить код-ревью и просто не допускать неправильных сценариев, но это опять-таки работа на ровном месте, из разряда "лишь бы не как раньше". S>Expression Bodied Functions потребуют утверждения стандартов кодирования. На том же ровном месте.
На сегодня нет. Т.к. ничего сложнее одного "?:" или linq-запроса туда не влазит. Т.е. правил достаточно тех же, что для любой одиночной строчки кода.
S>>К сожалению, чтобы прочувствовать всю прелесть решений "ты усложняешь, всё ж просто?" надо поработать над большим (т.е. в принципе не делается одной группой из 5-10 человек) долгоживущим (минимум 2-3 года продуктивной разработки) проектом. И вот когда три года твоей работы придётся или закопать из-за "всё-просто" решений или ценой усилий всей команды оставить свою часть в отличном состоянии — вот тогда к фигак-фигак нарабатывается очень здоровый скептицизм. S>Работал на проектах и побольше. И мне не очевидно, почему такие проекты придется закапывать из-за using-expression.
Не только из-за него. Когда у тебя на руках регулярно оказывается код, который надо поддерживать, но
1. Единственное, что с ним можно сделать — это сжечь и засыпать солью.
2. Код даже трогать нельзя, т.к. он стоил несколько человеколет разработки, а код, который от него зависит — стоит эдак на порядок больше.
3. Исправление нужно прямсейчасиписецкаксрочно
решения из разряда "лишь бы не как в гадлайнах" начинаешь очень не любить
S>Вопрос был изначально не в том, что бы на кого-то повесить головную боль, а в том, не приходило ли кому в голову, не обсуждалось ли? И только лишь.
Обсуждалось конечно, ссылки на обсужденее более общей проблемы я в первом ответе и привёл. Вы там ещё написали "Я знаю, чем отличается выражение от стейтмента"
S>pure и impure отлично смешиваются и без using-ов. да и никто не озаботился явной документацией pure и impure.
Тем не менее на сегодняшний момент в шарпе надо специально постараться, чтоб запихнуть impure-код в выражения.
S>F# как раз заточен на работу в том же рантайме и том же фреймворке, что и C#. Кейворд use в частности заточен на работу с IDisposable, сценарии использования которого в точности совпадают со сценариями его использования на C#.
Ну так и немерль и iron python заточены. Языками со своей концепцией и сценариями использования они от этого быть не перестали
В expression bodied methods уже можно запихнуть statement'ы, завернув их в immediately-invoked function expression. Я так понимаю, samius'у будет достаточно сахара, не нужны хитрые expression trees.
int Do(int x) => new Func<int, int>(y => {...}).Invoke(x);
S>Ну да, но это именно из серии "надо намеренно извратиться":)
А хотелось бы не извращаться, а чтобы компилятор просто поддерживал желаемый синтаксис.
Скажем, было:
private int Foo => ThirdPartyApi.ComputeValue();
И samius решил обмазаться using-expression'ом (в примере я его назвал with):
private int Foo => with (var sw = new StopwatchLogger()) ThirdPartyApi.ComputeValue();
Компилятор пусть просто генерит «IIFE-извращение»:
private int Foo => new Func<int>(() => { using (var sw = new StopwatchLogger()) return ThirdPartyApi.ComputeValue(); })();
или просто классический метод/свойство (не expression bodied).
S>Получаем правку expression trees, костыли ко всем linq-провайдерам и невозможность компиляции кода под младшие версии фреймворка.
Не получаем. Просто в expression tree вместо нашего выражения будет непрозрачный вызов метода.
Здравствуйте, Qbit86, Вы писали:
Q>Компилятор пусть просто генерит «IIFE-извращение»:
Ну... всё замечательно, но меня по-прежнему не отпускает мысль "но зачем???"
Что от такого изврата мы проигрываем — уже очевидно. Выигрыша нет вообще, если не считать двух сэкономленных скобок. Да и то они меняются на =>.
Не, серьёзно, это стоит того чтоб быть добавленным в язык вместо других нужных и действительно полезных вещей? Compiler team не резиновый, если они делают хотелку A, то в релиз автоматом не попадают B,C и D. Просто потому, что вместо полезной работы они искали обходы для всех дурацких последствий от A. Для всех желающих это в прямом эфире показывают. Что там с приятными мелочами типа params IEnumerable в шестом шаре?
S>>Получаем правку expression trees, костыли ко всем linq-провайдерам и невозможность компиляции кода под младшие версии фреймворка. Q>Не получаем. Просто в expression tree вместо нашего выражения будет непрозрачный вызов метода.
Тоже вариант, но это классический пример leaked abstraction: вместо относительно понятной ошибки компиляции или рантайма пользователь сообщает ошибку от провайдера "неподдерживаемый метод". Ну, или невалидный expression tree, как повезёт.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Expression Bodied Functions уже наступили на все грабли. И не я их предложил. То есть скобки и грабли с гайдлайнами не аргумент в случае Expression Bodied Functions, но почему-то аргумент в случае using...
S>Потому что exp bodied хороши для существующих выражений. А вот попытка добавить impure-выражения испортит и expression bodied тоже. Потому что смысл в них окончательно потеряется.
Не догоняю. Разве exp bodies запрещают impure-выражения? нет ведь. Все impure благополучно вставляются в exp bodies и ничего не портится. Или все что может быть испорчено, уже испорчено.
S>>Ненене, Дэвид Блейн! Не все что можно засунуть легально в expression проглотят linq-провайдеры и это не приводит к костылям. Поэтому не аргумент. S>А, ну т.е. ешё хуже решение. Теперь у нас есть выражения для expression-tree и выражения, которые не подходят для expression-tree и всё это ещё и различается для разных версий фреймворка. Как человек, писавший хоть и наколенный, но linq-провайдер — поверьте, там и без этого геммороя хватает
Наколенный и я писал. Выражения, которые не подходят для expression-tree linq-провайдера и без того есть.
Но я всеже не о выражениях ExpressionTree, а об выражениях, которые отличаются от стейтментов. Вот есть у нас стейтмент try/finally, и он ничего не ломает, ни в какие деревья выражений его совать не надо. Этот using стейтмент умеет возвращать результат. И это опять ничего не ломает (ведь существует, и никто не жалуется на это). И о ужас! Мы даже можем вставлять try/finally в лямбду!
Так вот, единственное, что сейчас отличает try/finally (using, lock) от выражения — это фактически пара внешних скобочек {}, которая придает стейтменту форму функции.
Очередное обновление языка нам позволяет записывать функции-мемберы без скобочек, но с =>, как у лямбд. Но вот то что в лямбды мы стейтменты вставлять можем, но если мы стейтменты вставим в функции-мемберы без скобочек, то сразу добавим геморроя — вот это я не понимаю.
S>>Expression Bodied Functions потребуют утверждения стандартов кодирования. На том же ровном месте. S>На сегодня нет. Т.к. ничего сложнее одного "?:" или linq-запроса туда не влазит. Т.е. правил достаточно тех же, что для любой одиночной строчки кода.
Туда не влазит, как я понимаю, ровно из-за того, что у стейтмента нет типа результата. Поправьте, если ошибаюсь.
S>>Работал на проектах и побольше. И мне не очевидно, почему такие проекты придется закапывать из-за using-expression. S>Не только из-за него. Когда у тебя на руках регулярно оказывается код, который надо поддерживать, но
S>1. Единственное, что с ним можно сделать — это сжечь и засыпать солью. S>2. Код даже трогать нельзя, т.к. он стоил несколько человеколет разработки, а код, который от него зависит — стоит эдак на порядок больше. S>3. Исправление нужно прямсейчасиписецкаксрочно
S>решения из разряда "лишь бы не как в гадлайнах" начинаешь очень не любить
Разве я предложил что-то ломать?
S>>Вопрос был изначально не в том, что бы на кого-то повесить головную боль, а в том, не приходило ли кому в голову, не обсуждалось ли? И только лишь. S>Обсуждалось конечно, ссылки на обсужденее более общей проблемы я в первом ответе и привёл. Вы там ещё написали "Я знаю, чем отличается выражение от стейтмента"
S>>pure и impure отлично смешиваются и без using-ов. да и никто не озаботился явной документацией pure и impure. S>Тем не менее на сегодняшний момент в шарпе надо специально постараться, чтоб запихнуть impure-код в выражения.
MethodCallExpression не отличит pure от impure.
S>>F# как раз заточен на работу в том же рантайме и том же фреймворке, что и C#. Кейворд use в частности заточен на работу с IDisposable, сценарии использования которого в точности совпадают со сценариями его использования на C#. S>Ну так и немерль и iron python заточены. Языками со своей концепцией и сценариями использования они от этого быть не перестали
Конечно нет, но работают они с тем же фреймворком и библиотеками, что и C#.
Здравствуйте, Qbit86, Вы писали:
Q>Здравствуйте, Sinix:
Q>В expression bodied methods уже можно запихнуть statement'ы, завернув их в immediately-invoked function expression. Я так понимаю, samius'у будет достаточно сахара, не нужны хитрые expression trees.
Верно. Мне кажется что вообще у деревьев выражений и exp bodies ничего общего кроме набора букв "expression" нет. Т.е. body expression-ы мемберов никто в linq-провайдеры совать не собирается. Могу ошибаться, конечно.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Qbit86, Вы писали:
Q>>Компилятор пусть просто генерит «IIFE-извращение»:
S>Ну... всё замечательно, но меня по-прежнему не отпускает мысль "но зачем???" S>Что от такого изврата мы проигрываем — уже очевидно. Выигрыша нет вообще, если не считать двух сэкономленных скобок. Да и то они меняются на =>.
А какой выигрыш от exp bodies, кроме двух сэкономленных скобок, которые заменились на => ???
Здравствуйте, samius, Вы писали:
S>Не догоняю. Разве exp bodies запрещают impure-выражения? нет ведь. Все impure благополучно вставляются в exp bodies и ничего не портится. Или все что может быть испорчено, уже испорчено.
Не запрещает конечно. Но impure-выражений на сегодня как таковых нет. Разве что спрятанные в методы, инкремент и присваивания. Но последние два сразу видно. А от первого в принципе не защитишься без отсечения части сценариев типа кэширования.
Добавление using expression будет провоцировать написание кода с побочными эффектами (потому что коду без побочных эффектов юзинг по определению не нужен). Т.е. размывать и без того нечёткую разницу между выражениями и стейтментами
S>Вот есть у нас стейтмент try/finally, и он ничего не ломает, ни в какие деревья выражений его совать не надо. Этот using стейтмент умеет возвращать результат. И это опять ничего не ломает (ведь существует, и никто не жалуется на это). И о ужас! Мы даже можем вставлять try/finally в лямбду!
Неа, это уже будет не expression-лямбда, а сокращённая запись для анонимного делегата. Потому что будет содержать statement block. Ну и соответственно, не может быть сконвертирована в expression, по крайней мере для текущей версии шарпа.
Т.е. синтаксис для юзинга добавить можно, но мы получим парадоксальную ситуацию: код
int Do() => using (SomeScope()) SomeValue();
выглядит как expression lambda но ей не является т.к. его нельзя сконвертить в expression tree.
Т.е. это statement lambda, но тогда её надо записать как
int Do() => { using (SomeScope()) return SomeValue(); }
что ещё длиннее, чем оригинальный
int Do() { using (SomeScope()) return SomeValue(); }
В общем, борьба с синтаксическим оверхедом не задалась
Сорри, что сразу не привёл это объяснение, неправильно понял твой вопрос
S>Очередное обновление языка нам позволяет записывать функции-мемберы без скобочек, но с =>, как у лямбд. Но вот то что в лямбды мы стейтменты вставлять можем, но если мы стейтменты вставим в функции-мемберы без скобочек, то сразу добавим геморроя — вот это я не понимаю.
Потому что мы запутаем клиента: выглядит как expression lambda, но на самом деле это statement lambda.
Хотя, на самом деле мы тут страдаем фигнёй. Нужен коммент от ув. Никова.
S>Конечно нет, но работают они с тем же фреймворком и библиотеками, что и C#.
Фигово работают, надо признать. Ибо привычное API для этих языков плохо укладывается в рамки CLS.
Здравствуйте, samius, Вы писали:
S>А какой выигрыш от exp bodies, кроме двух сэкономленных скобок, которые заменились на => ???
Если выйти за пределы сценария "сахар для геттеров/простых методов" — никакого. Если не выходить, то поддержка statement as expression как раз не нужна. Почему — смотрим всё обсуждение, уже раза три наверно писал
Здравствуйте, Sinix, Вы писали:
S>Что от такого изврата мы проигрываем — уже очевидно.
От изврата, конечно, проигрываем. И выигрываем от небольшой поддержки компилятора, которая избавит от необходимости городить изврат.
S>Выигрыша нет вообще, если не считать двух сэкономленных скобок. Да и то они меняются на =>.
Ещё и «return ...»; выражению он не нужен. Но просто взять фигурные скобки можно только в expression-bodied-методах, заменив их на обычные. Есть и другие контексты, где может встретиться выражение. Например,
var foo = Foo(...);
var bar = ThirdPartyApi.ComputeBar(foo);
var qux = Qux(bar);
Скажем, хотим померять и залогировать время вызова сторонней функции:
var foo = Foo(...);
var bar = with (new StopwatchLogger()) ThirdPartyApi.ComputeBar(foo);
var qux = Qux(bar);
Тут уже добавление фигурных скобок будет ломать scope'ы.
S>Тоже вариант, но это классический пример leaked abstraction: вместо относительно понятной ошибки компиляции или рантайма пользователь сообщает ошибку от провайдера "неподдерживаемый метод". Ну, или невалидный expression tree, как повезёт.
Ещё раз: предложенный мной подход не порождает невалидных expression trees или новых недостижимых ранее ошибок linq-провайдеров. Есть понятная семантика, которая может быть достигнута существующими средствами языка и фреймворка; то есть не требуется ничего революционного кроме ложечки сахара.
Я не говорю, что жить не могу без using-выражений; эту ветку начал samius. Эти выражения я применял бы не каждый день, наверное; но значительно чаще, чем те linq-провайдеры, которыми не пользовался уже года три.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Не догоняю. Разве exp bodies запрещают impure-выражения? нет ведь. Все impure благополучно вставляются в exp bodies и ничего не портится. Или все что может быть испорчено, уже испорчено. S>Не запрещает конечно. Но impure-выражений на сегодня как таковых нет. Разве что спрятанные в методы, инкремент и присваивания. Но последние два сразу видно. А от первого в принципе не защитишься без отсечения части сценариев типа кэширования.
+1
S>Добавление using expression будет провоцировать написание кода с побочными эффектами (потому что коду без побочных эффектов юзинг по определению не нужен). Т.е. размывать и без того нечёткую разницу между выражениями и стейтментами
Здесь по поводу побочных эффектов согласен. Но! Тот C# в отличие от F# провоцирует на побочные эффекты практически все. Точнее, в F# есть хотя бы инфраструктура, которая может позволить в некоторых сценариях обходиться без них, а в C# у нас нет даже коллекций без побочных эффектов. Тем не менее, в F# try/finally — выражение, хотя для функционального языка такая провокация как серпом по яйцам. Но она есть.
S>>Вот есть у нас стейтмент try/finally, и он ничего не ломает, ни в какие деревья выражений его совать не надо. Этот using стейтмент умеет возвращать результат. И это опять ничего не ломает (ведь существует, и никто не жалуется на это). И о ужас! Мы даже можем вставлять try/finally в лямбду!
S>Неа, это уже будет не expression-лямбда, а сокращённая запись для анонимного делегата. Потому что будет содержать statement block. Ну и соответственно, не может быть сконвертирована в expression, по крайней мере для текущей версии шарпа.
S>Т.е. синтаксис для юзинга добавить можно, но мы получим парадоксальную ситуацию: код S>
S>int Do() => using (SomeScope()) SomeValue();
S>
S>выглядит как expression lambda но ей не является т.к. его нельзя сконвертить в expression tree.
Как же? можно. Речь таки о наличии лишней пары скобочек и оператора return. Т.е. мы говорим не о семантических отличиях, а о синтаксических и только лишь.
S>Т.е. это statement lambda, но тогда её надо записать как S>
S>int Do() => { using (SomeScope()) return SomeValue(); }
S>
S>что ещё длиннее, чем оригинальный
Это длинее чем оригинальный потому как using приходится оборачивать в скобки из-за того, что он стейтмент. Был бы он експрешном — не пришлось бы вставлять скобки. S>
S>int Do() { using (SomeScope()) return SomeValue(); }
S>
S>В общем, борьба с синтаксическим оверхедом не задалась
Конечно не задалась. Она не задалась еще с саамого expr bodies, т.к. вместо скобок пришлось писать =>. S>Сорри, что сразу не привёл это объяснение, неправильно понял твой вопрос
Не страшно.
S>>Очередное обновление языка нам позволяет записывать функции-мемберы без скобочек, но с =>, как у лямбд. Но вот то что в лямбды мы стейтменты вставлять можем, но если мы стейтменты вставим в функции-мемберы без скобочек, то сразу добавим геморроя — вот это я не понимаю. S>Потому что мы запутаем клиента: выглядит как expression lambda, но на самом деле это statement lambda.
И statement оно лишь потому что using не експрешн.
S>Хотя, на самом деле мы тут страдаем фигнёй. Нужен коммент от ув. Никова.
согласен, что фигней. Тем более, что в данном случае аргументы "почему нет" интересуют меня немного более самой фичи. Ведь речь всего лишь о скобочках, а не о просовывании чего-то нового в linq-провайдеры.
S>>Конечно нет, но работают они с тем же фреймворком и библиотеками, что и C#. S>Фигово работают, надо признать. Ибо привычное API для этих языков плохо укладывается в рамки CLS.
Есть предложения, как сделать лучше?
Здравствуйте, samius, Вы писали:
S>Интересно, никому не приходило в голову что Expression Bodied Functions and Properties хорошо бы дополнить возможностью использовать using statement в качестве expression?
S>тогда уж.
S>Иначе первый же залетевший дятел одно исключение — и утёкший ресурс
S>UPD. S>P.S. Кто сказал future монада? S>
S> public static Func<TReturn> Then<TValue, TReturn>(this Func<TValue> val, Func<TValue, TReturn> callback) { return () => callback(val()); }
S>...
S> Func<string> a = () => Console.ReadLine();
S> var b = a
S> .Then(_ => int.Parse(_))
S> .Then(_ => Math.Sqrt(_))
S> .Then(_ => { Console.WriteLine(_); return _; });
S> var c = b();
S>
Давно это было, вряд ли кто уж вспомнит.
Из F# спеки
Member
Description
member Using : 'a * ('a -> M<'b>) -> M<'b> when 'a :> IDisposable
Optional member. Used to de-sugar use bindings within computation expressions.
Construct
De-sugared Form
use pat = expr in cexpr
b.Using(expr, (fun pat -> cexpr))
use! pat = expr in cexpr
b.Bind(expr, (fun x -> b.Using(x, fun pat -> cexpr))
S>P.P.S. Все вопросы "НО ЗАЧЕМ???" — к топикстартеру. Это ему нужны были юзинги в выражениях
Я такого не утверждал (что нужны). Я поинтересовался, была ли такая идея?
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, samius, Вы писали:
AVK>>>Не? S>>Да, с учетом поправки Sinix, оно самое.
IT>Про where TValue : class, IDisposable не забудте. А то надиспозите.
Возражаю, не нужен такой констрейнт. Контракт на IDisposable предполагает возможность многократного вызова метода Dispose() и только. А флаги об успешном освобождении ресурса вовсе не обязательно держать в теле структуры.
Здравствуйте, Jack128, Вы писали:
J>как тут возможна утечка ?
Thread.Abort(), и, опционально, corrupted state exceptions, например out of memory при попытке выделить память под лямбду. Тут конечно ситуация из разряда "поздно пить боржоми", но мы ж инфраструктурный код обсуждаем, а не одноразовый хелпер.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Jack128, Вы писали:
J>>как тут возможна утечка ? S>Thread.Abort(), и, опционально, corrupted state exceptions, например out of memory при попытке выделить память под лямбду. Тут конечно ситуация из разряда "поздно пить боржоми", но мы ж инфраструктурный код обсуждаем, а не одноразовый хелпер.
Как страшно жить :-D
Здравствуйте, 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) без оборачивания его в функцию. Обернуть-то и сейчас можно.