Комментарии 187
public override int GetHashCode()
{
return (Damage.GetHashCode() * 17 + Durability.GetHashCode());
}
А почему умножение именно на 17? А что будет если параметров три? Четыре?
// RyuJIT optimizes this to use the ROL instruction
// Related GitHub pull request: dotnet/coreclr#1830
uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
return ((int)rol5 + h1) ^ h2;
Рекорды, nullable reference и switch как выражение — огонь, в Котлин очень удобно использовать )
Все же дефолтные реализации в интерфейсах это спорный момент. В Java-мире, например, не очень вводушевленно приняли это фичу (хотя пример так себе, там и с var боролись).
Так не обязательно же эту фичу всюду сувать. Есть место где она очень даже нужна — это LINQ. Просто посмотрите что там сейчас творится.
Раз: https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs#L38
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) {
if (source == null) throw Error.ArgumentNull("source");
if (selector == null) throw Error.ArgumentNull("selector");
if (source is Iterator<TSource>)
return ((Iterator<TSource>)source).Select(selector);
if (source is TSource[])
return new WhereSelectArrayIterator<TSource, TResult>((TSource[])source, null, selector);
if (source is List<TSource>)
return new WhereSelectListIterator<TSource, TResult>((List<TSource>)source, null, selector);
return new WhereSelectEnumerableIterator<TSource, TResult>(source, null, selector);
}
Два: https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs#L1314
public static int Count<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
ICollection<TSource> collectionoft = source as ICollection<TSource>;
if (collectionoft != null) return collectionoft.Count;
ICollection collection = source as ICollection;
if (collection != null) return collection.Count;
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator()) {
checked {
while (e.MoveNext()) count++;
}
}
return count;
}
Метод Count, кстати, является наглядным примером основного недостатка такого подхода: туда автор кода не включил проверку на IReadOnlyCollection, и теперь всем остальным можно с этим только смириться, расширяемость-то нулевая.
Все эти методы изначально должны были быть методами интерфейса с реализацией по умолчанию.
static string M(Person person)
{
return person switch
{
Professor p => $"Dr. {p.LastName}, Professor of {p.Subject}",
Student s => $"{s.FirstName}, Student of {s.Advisor.LastName}",
Person p when p.LastName == "Campbell" => $"Hi, {p.FirstName}",
_ => "Come back next year!"
}
}
Но у C# есть хорошая база – Common Language Infrastructure (CLI). CLI дает возможность написать новый язык с чистого листа, оставив при этом возможность работы со старым кодом, который еще долго может оставаться в рабочем состоянии. В качестве ближайшего аналога можно рассмотреть ситуацию с Java/Kotlin. Возможно, Майкрософт пойдет таким путем?
Наверное несбыточная мечта, но очень хотелось бы, чтобы Майкрософт взялись за развитие Nemerle, он был разработан 15 лет назад и до сих пор уделывает по фичам почти все современные языки.
Но с тех пор ничего интересного это сотрудничество для .Net комьюнити не принесло.
Сейчас разработка Нитры продолжается, в основном на энтузиазме отдельных людей. Судя из тех материалов, что мне попадались (обсуждений и докладов на конференции) одна из проблем сейчас у них (помимо нехватки финансирования) — это неумение преподнести проект и заинтересовать как инвесторов, так и потенциальных пользователей. Доклады от главного разработчика языка несколько сумбурны и не очень наглядно демонстрируют все возможности, которые дает немерле.
Меня очень впечатлил вот этот доклад на дотнексте по АОП в дотнете (собственно, там я впервые услышал о немерле). Там, где сейчас используются фреймворки типа PostSharp, оказывается можно обойтись встроенными средствами языка. Вот если будет больше таких хороших примеров использования немерле, которые показывают реальную практическую пользу — то у языка есть шансы добиться признания.
Выглядит это направление (макросы + DSL без всяких костылей) очень интересным и хочется, чтобы это это вылилось в нечто завершенное.
Так Нитра сравнивается с Решарпером? Или с Котлином? Или MPS? Или со всем тремя? Как бы то ни было, Нитре надо было обосновать свою значимость с теми проектами, что у компании уже есть.
Сравнивалась. И с MPS сравнивалась. Как раз опыт применения и «продажи» MPS сыграл плохую службу. Многие в конторе были разочарованы в MPS. Ранее MPS применяли для внутренней разработки, но получили от его применения больше пролем, чем пользы. В итоге в некоторых частях от его использования отказались и остались довольны этим. Так как концептуально с MPS у Нитры много общего было, скепсис по отношению к MPS перекинулся и на Нитру. Я обращался к тому кто придумал и поддерживает MPS (это один из владельцев фирмы), но он даже не ответил на мое письмо. И это при том, что программисты из группы MPS были очень заинтересованы нашим докладом и очень печалились по поводу принятого решения.
Все еще не решено, будет ли оператор диапазона включающим или исключающим, т.е., будет ли результирующий диапазон включать значение конец. Возможно, будут доступны оба синтаксиса
Мне казалось, что вот тут (55 минута)
довольно доходчиво рассказали про System.Index
.
Например, 5..8
эквивалентно последовательности 5, 6, 7
, т.е. аналогично стандартному индексированию zero-based массивов.
1..^1
индесирует элементы с 1 по n-2
, т.е. выкидывает один в начале и один в конце. 0..^0
эквивалентно последовательности с 0 по n (не включая n), т.е. индексирует всю коллекцию. ^0
по сути эквивалентен длинне последовательности.
Доступны также варианты n..
, ..m
и ..
, которые эквивалентны чему-то вроде n..^0
, 0..m
, 0..^0
, если я ничего не напутал.
Источник (кроме видео) здесь, на гитхабе
Nullable Reference Types
IWeapon? canBeNull;
IWeapon cantBeNull;
Отличная идея — сломать обратную совместимость по синтаксису.
Похожа на идею — значение True равно 0. Во где был фееричный треш на унаследованном коде.
Default Interface Methods
Отличная идея, только кофеварку забыли приделать и пемзу для пяток…
В отличие от множественного наследования, данный функционал позволяет избежать проблемы ромбовидного наследования, при которой метод с одним и тем же именем определен в нескольких интерфейсах. Для этого C# 8.0 требует, чтобы каждый класс и интерфейс имели наиболее специфическое переопределение каждого унаследованного члена:
В С++ уже лет 16 назад это не было проблемой. А в .Net это объяили «Злом», предали анафеме, а сейчас впихивают обратно. Правда почему-то ректально…
P.S.
Что они курят…
А насчет методов в интерфейсах — пример приведен явно неудачный, и в видео с build 2018 в последних 6 минутах более адекватный пример:
interface ILogger
{
void Log(LogLevel level,string message);
void Log(Exception ex)=> Log(LogLevel.Error, ex.ToString());
}
т.е. добавив вторую строчку мы меняем интерфейс, но в добавляемом методе лишь переопределяем его через существующий, вместо того, чтобы заставлять всех имплементирующих явно указывать новую имплементацию метода, т.к. это повлечет за собой множество не слишком нужных правок во всем проекте.
Тут можно парировать тем, что вдруг мы на логирование исключений захотим делать какие-то дополнительные действия, но конкретно в этом случае это звучит все равно странно, потому что делать что-то ещё — явно не зона ответственности логера.
Ну в C# постоянно синтаксис изменяется и обратно он несовместим, странно иметь новые языковые фичи которые в зависимости от версии окружения по разному бы читались.
Всегда декларировалось, что интерфейс это декларация-контракт взаимодействия. Реализация — этим занимаются другие сущности.
А тут предлагают «улучшить» эти соглашения, только потому что кто-то «убил» множественное наследование классов, потому что это «будет сложно».
Может просто разрешить множественно наследование классов, чем так извращаться, причем ломая привычные соглашения?
или это очередной Vendor lock в исполнении M$?
Отличная идея — сломать обратную совместимость по синтаксису.
А где конкретно она ломается-то, если учесть, что это opt-in?
IWeapon cantBeNull;
…
Проблема такого изменения в том, что мы прерываем совместимость со старой кодовой базой: Здесь предполагается, что все переменные в старом коде по умолчанию не могут содержать null. Чтобы справиться с этой ситуацией, статические анализаторы компилятора на null-безопасность должны быть выборочно включены в зависимости от проекта.
У вас 15-летний код, и тут вдруг «Ай, ваш код шлак, у вас может быть null значение, срочно нужно переколбасить ваш код (вы же идиот и до сих пор об этом не подумали) или выключите нафиг наши предупреждения».
Нормальная адекватная логика.
Да и логика «не могут содержать null» подразумевает, что чем-то должна быть инициализирована переменная по умолчанию? Чем?
У вас 15-летний код, и тут вдруг «Ай, ваш код шлак, у вас может быть null значение, срочно нужно переколбасить ваш код (вы же идиот и до сих пор об этом не подумали) или выключите нафиг наши предупреждения».
Подождите, но зачем вы включали эти предупреждения?
Да и логика «не могут содержать null» подразумевает, что чем-то должна быть инициализирована переменная по умолчанию? Чем?
Допустимым значением.
Подождите, но зачем вы включали эти предупреждения?
Открываем исходник и фиг понимем «оно null или не null? А opt включена или нет ?»
Это же «очевидно»… или нет?
Допустимым значением.
Это каким например?
Создаем экземпляр класса, в конструкторе по умолчанию «ничего нет», можно провести «ленивую инициализацию» — но у нас же «null» не может быть? А что тогда? Создавать по всему коду экземпляры классов только что бы «ублажить» компилятор?
Сама по себе фича полезная. Code contracts отлично ловили такие ошибки на этапе компиляции. Но реализация — выглядит более чем сомнительно.
По стандарту языка — ссылочный тип или null или «что-то есть».
Нафига городить на уровне языка проверку «рук от бедер», тем более что сейчас компилятор не пропускает не проинициализированные переменные?
Открываем исходник и фиг понимем «оно null или не null? А opt включена или нет ?»
Ну да, печаль. Но это уже не проблема обратной совместимости.
Это каким например?
Допустимым.
Создаем экземпляр класса, в конструкторе по умолчанию «ничего нет», можно провести «ленивую инициализацию» — но у нас же «null» не может быть? А что тогда?
А тогда размечаем поле как nullable, в чем проблема-то?
тем более что сейчас компилятор не пропускает не проинициализированные переменные?
Куда не пропускает? То, что поля автоматически инициализируются, вы помните?
Куда не пропускает? То, что поля автоматически инициализируются, вы помните?
Я то помню, а вот компилятор похоже забыл об этом :)
...
ITest interfaceXXX;
...
interfaceXXX.FN();
Error CS0165 Use of unassigned local variable 'interfaceXXX'
Это каким например?
Допустимым.
А конкретнее? null? a default для ссылочных типов случаем не null ?!
Или сделаем еще один тип nullnull или IAmSureNull? :)
Я то помню, а вот компилятор похоже забыл об этом
Не надо путать переменные и поля.
...
Warning CS0649 Field 'Program._interfaceXXX' is never assigned to, and will always have its default value null.
Смысл то не в полях /переменных, а в том, что уже достаточно инструментальных средств что бы не выстрелить себе в ногу.
На мой взгляд.
Создаем экземпляр класса, в конструкторе по умолчанию «ничего нет», можно провести «ленивую инициализацию» — но у нас же «null» не может быть? А что тогда?
Это вообще как? Можете привести пример кода?
Вот как раз в "типовом DI" вам не могут прийти снаружи null
-значения сервисов, и поля с ними тоже после конструктора не могут быть null
. И в чем проблема?
Вот как раз в «типовом DI» вам не могут прийти снаружи null-значения сервисов, и поля с ними тоже после конструктора не могут быть null.
В идеале да, не должны.
ITest _testXXX;
class ZZZ(ITest value)
{
_testXXX.Fn(); <-- банальная опечатка
_testXXX = value;
}
А между созданием и инициализацией в каком состоянии будет? какая-то религия мне запрещает написать кривой код и в конструкторе накосячить, дернув не проинициализированый интерфейс?
Ну вот кстати в этом сценарии проблема действительно есть, но она как раз в том, что warning не показывается, хотя и должен бы.
Что забавно, если поле объявить как nullable, warning — и правильный! — показывается.
Подождите, но зачем вы включали эти предупреждения?
А ты наивно думаешь, что это так и останется опцией?? Такой смелый, но бестолковый шаг, как ломка совместимости (причём фундаментальная такая), не пройдёт на уровне опций — она вывернет наизнанку всю работу, где старые проекты сосуществуют с новыми — поди, разберись, где там «новый C#», а где опции не нужны! Чувствуешь, попахивает говнецом? Вот-вот! И всё ради одной ничтожной цели — чтобы каждая обезьяна из Индии сразу получала по лапам, используя ссылки. Ну так может не коверкать язык, а нанять специального же индуса, который это будет делать физически????
12 лет я пишу на C# и ловил NRE не раз, но не настолько раз, чтобы похабить язык, да ещё и мой код проверками «а не null ли вы мне подсунули?». Идиотизм чистой воды. Для(против) NRE есть статические анализаторы и голова. Если головы нет — никакие крючкотворства с языком не помогут.
Lofer прав, ТАКИЕ изменения в языке нафик не нужны! От этих «благих намерений» тошнит.
PS
Почему бы индусне не сделать собственный язык, с песнями и танцами?!!! Вот там пусть хоть утыкают всё проверками! Basic Indian edition! :))
Для(против) NRE есть статические анализаторы и голова.
- Зачем решать самому задачи, которые прекрасно решаются автоматически, учитывая, что человеческое время дороже машинного?
- Система типов — это и есть статический анализатор, встроенный язык. В чем проблема?
- Если ваш код и так правильный, то и варнингов не будет. А если неправильный — то ворнинг укажет место бага, которое надо будет исправить. Что тут плохого?
И всё ради одной ничтожной цели
Это не ничтожная цель, а исправление (пусть и запоздалое) billion dollar mistake. Впрочем, куда там безголовой обезьянке Энтони Хоару до хаброикспертов!
А ты наивно думаешь, что это так и останется опцией?
В ближайшей мажорной версии — да.
12 лет я пишу на C# и ловил NRE не раз, но не настолько раз, чтобы похабить язык, да ещё и мой код проверками «а не null ли вы мне подсунули?»
То есть вы null guards не используете?
Для(против) NRE есть статические анализаторы и голова.
Ну так C# 8 и добавляет такой анализатор.
Lofer прав, ТАКИЕ изменения в языке нафик не нужны!
Прекрасно. Не нужны — не используйте. Оставайтесь на C# 7, или более ранних версиях, или вообще уходите на другой язык.
Что мешало дать расставить атрибут [Notnull] там, где он адекватен, и посмотреть уровень его использования?
То, что он по дефолту должен стоять практически везде, за редким исключением. Логично, что квалификатор должен стоять в случае исключительной ситуации а не наоборот.
Зависит от задачи. В моих null в какой-то ссылке это очень типичная ситуация, а где жёстко не допускается — гарантируется, например, тем, что метод объекта нельзя вызвать без самого объекта.
> Логично, что квалификатор должен стоять в случае исключительной ситуации а не наоборот.
Логично, что столь радикальное воздействие лучше делать плавно. Комбинация атрибута уровня входного файла (с дефолтом nullable) в первой версии и атрибутов отдельных переменных дала бы достаточно средств для плавного введения там, где оно действительно нужно.
Зависит от задачи.
Да нет, не зависит. null практически никогда не нужен. 90% случаев его использования — либо code smell из-за лени, либо ошибка.
В моих null в какой-то ссылке это очень типичная ситуация,
И вы везде аргументы на нулл проверяете, ведь правда?
Логично, что столь радикальное воздействие лучше делать плавно.
Они и делают плавно, начиная с ворнингов. Кроме того, ваше предложение точно так же ломает обратную совместимость, т.к. вы не сможете засунуть ваш дефолтный nullable в ф-ю, которая ждет non-nullable аргумент (и, понятно, стандартная библиотека будет переписана так, что все ф-и, кроме тех, где это необходимо, будут принимать non-nullable).
Вообще это все не проблема. Реальная проблема — отсутствие фильтров в системе типов. Но вот это почему-то не обсуждается.
И вы везде аргументы на нулл проверяете, ведь правда?
Надеюсь это был сарказм? :)
Да в общем-то в ISO 2700х, в части разработки безопасного и качественного, кода проверка аргументов это обязательное действие. Иначе с аудитом качества могут быть проблемы.
Медленно, но хорошо работающий код, лучше быстрого, но не работающего.
P.S.
Недавно приятель рассказывал историю что с ним произошла.
Пошел сдавать анализы. По результатам анализов на принудительно лечение его там же чуть не отправили. Хорошо у врача хватило мозгов сравнить с предыдущими анализами, и понять что программа глюконула.
Не удивлюсь, если кто-то сэкономил на проверке аргументов.
Не удивлюсь, если кто-то сэкономил на проверке аргументов.
Вот чтобы такого не было, и нужны non-nullable типы :)
Мозги нужны и руки не от бедер. .Net и делали «безопасным». Уже 15 лет все безопаснее и безопаснее. Глядя на последние улучшения, так и хочется спросить «И сильно помогло? перебороли идиотизм ?» Похоже что нет, а вот порог вхождения понизили значительно.
Такое впечатление, что больше «безопастности» — больше говнокода — …
Будут пихать туда всякую дрянь, как и пихали, без всяких проверок.
Ну так если напихают — то будет ворнинг. А потом и вовсе ошибка компиляции, когда-нибудь.
Глядя на последние улучшения, так и хочется спросить «И сильно помогло? перебороли идиотизм ?»
Как часто у вас в .net segmenation fault возникал? А за границу массива с попаданием в соседний объект сколько раз выходили?
Ну вообще-то, если для поступающего аргумента ссылочного типа рантайм гарантирует, что ссылка не null, потому что это проверено где-то раньше, то такая явная проверка ещё раз просто не нужна.
В этом действительно смысл всех ограничений системы типов: где-то это явный notnull, где-то умолчательный notnull при возможности делать Nullable или Optional, где-то возможность писать «type Temperature = new Integer range -273..+300», как в Ada, и ещё много разных вариантов.
И если ограничение выполнено на «входе» в соответствующий тип раньше данной функции, блока кода или конкретного предложения — то проверять ещё раз на месте… по-моему, смысла мало — это уже super-defensive programming получается.
Но вот что мне не нравится — это то, что с одним единственным вариантом nullable ссылок носятся, как с писаной торбой, а множество других — например, а не подсунули ли хрень не того типа просто потому, что null нельзя передавать — не делается. А это, в отличие от NPE, не даст исключение.
2. Может быть и того же типа, просто не ту, что надо. Нельзя передавать null — подсунем new T(), неважно, что его пытаются под что-то использовать. Я уже такое наблюдал в реале, и ловить ошибки после этого было в разы сложнее, чем при явном NPE.
Как вообще можно подсунуть что-то не того типа?
Интерфейсов хватит и кривой инициализации.
Были прецеденты, насчет типа Object, после чего сделали generics & where, что бы отловить хотя бы что-то на уровне компилятора.
Дурное дело не хитрое.
Жду доказательств. Причём универсальных, не зависящих от специфики задачи.
> Кроме того, ваше предложение точно так же ломает обратную совместимость, т.к. вы не сможете засунуть ваш дефолтный nullable в ф-ю, которая ждет non-nullable аргумент
Смогу. Явно проверив, что он не null. Слава богам, опознать, что в данной ветке исполнения эта проверка выполнена, компиляторы в состоянии уже лет 20. А можно попросить и сам компилятор вставлять явные проверки. Есть места, где это уже сделано.
> Они и делают плавно, начиная с ворнингов.
Плавно — это если бы они в первой версии по умолчанию не включались.
> Кроме того, ваше предложение точно так же ломает обратную совместимость, т.к. вы не сможете засунуть ваш дефолтный nullable в ф-ю, которая ждет non-nullable аргумент
Если я установлю на функции notnull на аргумент, это будет, да, само по себе переломом обратной совместимости.
> (и, понятно, стандартная библиотека будет переписана так, что все ф-и, кроме тех, где это необходимо, будут принимать non-nullable)
Понятно, что будет сломана совместимость? Радикально, да.
> Реальная проблема — отсутствие фильтров в системе типов. Но вот это почему-то не обсуждается.
Тут не обсуждается, или и в профильных форумах тоже?
Плавно — это если бы они в первой версии по умолчанию не включались.
А что, включаются? Это для меня новость.
Жду доказательств.
Необходимость использования nullable типа на самом деле очень легко проверяется — оно действительно необходимо только тогда, если при получении null ваш метод корректно отрабатывает, возвращая осмысленный результат. У вас это действительно так, или все же большей частью при получении null — либо эксцепшен, либо возврат из метода того же null/null object?
Причём универсальных, не зависящих от специфики задачи.
От специфики задачи это зависеть не может, потому что использование или не использование nullable — фактически, способ оформления кода, а не свойство алгоритма. Можно что угодно написать лдибо так, либо эдак.
Смогу. Явно проверив, что он не null.
Да, но вам для этого надо проверяющий код написать. Что заведомо больше, чем проставить? у типа.
Слава богам, опознать, что в данной ветке исполнения эта проверка выполнена, компиляторы в состоянии уже лет 20.
Ну, какие-то компиляторы, действительно, могут. Вопрос в том еще — насколько хорошо. Вот компилятор c# будет с этой задачей справляться не слишком хорошо.
Плавно — это если бы они в первой версии по умолчанию не включались.
Это же ворнинги, а не ошибки. В чем проблема? И задача ведь именно стимулировать разработчиков переходить на nullable. Так что выключение ворнингов должно доставлять неудобства, иначе все просто забьют. Так что тут я за, и хорошо что включаются. Я б еще убрал возможность выключения в довесок :)
Понятно, что будет сломана совместимость? Радикально, да.
Да, будет.
Да.
> Вот компилятор c# будет с этой задачей справляться не слишком хорошо.
Почему? Это ведь простейший тип анализа.
> Это же ворнинги, а не ошибки. В чем проблема?
Поломка билда везде, где выставлено «не более K варнингов на компиляцию данной хери». Засорение выдачи, причём негранулируемое.
Почему? Это ведь простейший тип анализа.
Он простейший в простейших кейзах, когда вы просто делаете тест на налл в условии. Что, если у вас кастомная ф-я, проверяющая налл или подтип внутри себя? Что, если проверка на налл происходит внутри лямбды при фильтрации коллекции?
Поломка билда везде, где выставлено «не более K варнингов на компиляцию данной хери». Засорение выдачи, причём негранулируемое.
Ну и хорошо, как по мне.
Такую проверку он не обязан выполнять.
> Что, если проверка на налл происходит внутри лямбды при фильтрации коллекции?
Это вопрос notnull/nullable на элементах коллекции. Его решить сложнее, да.
Что мешало дать расставить атрибут [Notnull] там, где он адекватен, и посмотреть уровень его использования?
То, что его придется ставить практически везде (если посмотреть на количество null guards на аргументах), а это бессмысленная работа. И то, что это будет неконсистентно с int?
.
Не воспроизводится.
> И то, что это будет неконсистентно с int?..
Можно подробнее?
Можно подробнее?
Ну int у вас по дефолту non-nullable и чтобы он был nullable вы ставите?.. Почему для reference-типов должно быть все наоборот?
Не воспроизводится.
У меня воспроизводится.
Можно подробнее?
int someInt; //non-nullable
int? someOtherInt; //nullable
object! someOtherObject; //non-nullable?
object someObject; //nullable, WTF?!
Выглядит красиво, пока мы не вспоминаем про многозадачное окружение – как быть там в случае, если кто-то вклинился между проверкой и использованием?
Каким образом эта фича отменяет использование примитивов синхронизации? Как быть — писать корректный код, использовав один множества инструментов языка и фреймворка.
Когда же добавят Extended Properties…
Выглядит красиво, пока мы не вспоминаем про многозадачное окружение – как быть там в случае, если кто-то вклинился между проверкой и использованием?
Вот тут с переводчиком не соглашусь. Это вовсе не та проблема, которую пытаются решать. Этот синтаксис должен решать только проблему контракта, и какой-никакой автоматической его проверки (точнее это должны делать анализаторы). Этот синтаксис не будет сам осуществлять никаких проверок и он не защитит вас от NRE, в откомпилированном коде вообще не будет разницы, писали вы «MyClass?» или «MyClass» (возможно только метаинформация с аттрибутами).
using var recource = CreateDisposable();
Которая бы автоматически открывала using и закрывала его при уходе переменной из области видимости — было бы великолепно. Кажется, когда-то на гитхабе в репозитории Roslyn видел в issues подобный proposal, но с ним что-то было не так. Хотя в C++/CLI такой синтаксис есть и все проблемы решить смогли.
Кажется, когда-то на гитхабе в репозитории Roslyn видел в issues подобный proposal, но с ним что-то было не так. Хотя в C++/CLI такой синтаксис есть и все проблемы решить смогли.
В F# так и сделано, так что C# просто тормозит.
Можно "как на стеке", можно явно скоупы задавать:
; аргумент — в EAX
bsr ecx, eax
И вы удивитесь насколько хуже ваше решение. А зачем такое делать спросите вы? У меня была практическая задача, делать предварительную оценку сбалансированности ветки двоичного дерева по количеству элементов, и делать это надо было для каждого узла.
Я ценю ваш юмор, когда у вас в солюшене два десятка проектов C#, как вы будете внедрять туда Rust?
Ну вообще есть больше одного решения.
И то что C# не имеет возможности их решать, говорит о том, что это опасный язык, с точки зрения рисков.
Это верно для любого языка. Вообще проект, в котором появляются задачи, на которые не рассчитывали при его проектировании (простите), находится в зоне риска по определению.
Вот чего мне не понять, так это зачем натягивать решения на инструменты, которые для них не предназначены, а потом обвинять инструменты, а не натягивающего.
Ну вообще есть больше одного решения.
А можно пример решения производительность которого не умрет на маршаллинге?
P/Invoke формата "все вычисление внутри". Да, и данные либо компактные, либо тоже достаются внутри.
Перенести все дерево в неуправляемый код.
Смотреть уже надо, так сложно сказать.
И, да, я видел больше одного проекта на дотнете где это важно и при этом использование дотнета оправдано. И видел задачи, где fine grained il-код может что-то решить.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
Но я полностью с вами согласен. К тому что вы сказали, можно еще добавить это. От C# cкладывается впечатление, что кто то изначально посчитал всех кодеров даунами, у них забрали многие возможности, все ради благих целей и в ущерб производительности. Как то устал от этого, наверно пора менять работу :).
Это общий принцип, который одинаково хорошо работает как с P/Invoke, так и с доменами приложений или сетевым взаимодействием.
… собственно, почему это вообще проблема языка? Вы какой язык не возьмите, вам CLR не позволит это сделать.
Это же банальный P/Invoke (со всеми его накладными расходами). Если вам так надо, то вы прекрасно можете это сделать из C#.
То это договор определяющий порядок следования параметров на стеке вызываемой функции. Если сомневаетесь, то сделайте замер производительности вызова через P/Invoke и напрямую ;).
… а что же там в дизассемблере за .method assembly static pinvokeimpl int32 ... foo(int32 ...)
тогда?
Managed to Native
In the case where a managed function calls into a native function standard P/Invoke is used. The compiler just defines a P/Invoke signature for the native function in MSIL
Для всех и не надо, но упомянутые вполне относятся к типовым и базовым.
> Как решение частной задачи оно идеально, но в реальных проектах задачи стоят шире.
При полном отсутствии развития в этой области — подобная позиция переводится как «Чтобы не ошибиться, я просто буду ничего не делать».
(Я знаю как минимум два проекта, где отсутствие названных возможностей привело к тому, что они реализованы на Java, а не C#, это при том, что Windows — одна из целевых платформ. Но, конечно, в общей массе всяких WPF это даже меньше копеек, не спорю.)
Чтобы не ошибиться, я просто буду ничего не делатьЕсли честно, я не вижу в этом проблемы. Представьте, вы выбираете стек для реализации некоторого приложения и знаете, что вам понадобятся высокопроизводительные вычисления. Выбрать .NET на расплывчатом знании о том, что там «есть что-то базовое», а потом внезапно напороться на отсутствующий функционал и оказаться вынужденным переписывать часть на C — куда более рисковая ситуация для проекта, чем изначально поделить задачу на (условно говоря) интерфейсную и вычислительную части и реализовать их специализированных технологиях.
Пишите на плюсах сразу, кто же вам мешает. Риски использования managed языков следует учитывать сразу.
И это удручает, учитывая, что C# как язык таки заметно прогрессивнее, и частично это так для инфраструктуры разработки.
Уточню сразу специфику: разная сетевая активность системы «специализированные демоны/серверы/прокси/etc.», практически всегда под unix-like.
bsr ecx, eax
А как вы это собираетесь сделать на IL?
следовательно надо сделать и ассемблерные вставки
Ассемблерные вставки? В управляемой среде? Просто нет.
язык должен делать меня свободным от узости применения.
Язык вам ничего не должен.
Для этих задач использование .net в целом неэффективно.
Тем не менее решение некоторых задач, гораздо эффективнее находясь ближе к реальному железу, а не к идеалам. И это факт.
Решение подавляющего большинства задач гораздо эффективнее если находиться как можно дальше от железа. В идеале бы иметь одну кнопку — "сделай хорошо", но пока приходится общаться с машиной на языках программирования и редко-редко опускаться на уровень железа для числодробилок.
А для тех редких случаев когда нужна прям мега оптимизация как на асме — C/C++
Почему в C++/CLI можно свободно управляться с указателями, с шансом разломать к чертям управляемую кучу, а если ассемблерные вставки так сразу нет? По последствиям это одно и то же.
(Специфика управляемой среды тут заметна, да, но не фатальна.)
Здрасьте! А что по-вашему Marshal.AllocHGlobal
и Marshal.FreeHGlobal
делают если не явно выделяют/удаляют в неуправляемой куче? И тот IntPtr
который возвращает AllocHGlobal
можно преобразовывать к указателю через ToPointer()
и использовать без всяких fixed.
Что же до stackalloc — это не костыль, а аналог функции alloca.
Я бы предпочел, чтобы и указателей не было.
Нужен bsr? Integer, Long знают numberOf{Leading,Trailing}Zeros(), bitCount() и прочие аналогичные вкусности, которые переводятся в одну команду. Безо всяких ассемблерных вставок.
Или вот: BigInteger там же знает про bitLength(), который реализовать тривиально и дёшево. Аналог C# не знает такого, зато зачем-то дал IsPowerOfTwo, который дорог и тупо бессмысленен. И таких моментов много — непонятно, то ли намеренно зарезали возможности, которые облегчают работу на .NET, чтобы гнать людей на C++/CLI или чистый C++, то ли у авторов этого в принципе потеряна обратная связь с пользователями.
Будущего у C# нет, его похабят с каждой версией команда индусни, нанятая непонятно зачем.
По-моему, сейчас самое время заняться Nemerle-2 (не Нитрой!) — грамотно спроектированный язык просто размажет всю эту C# team со всеми их поделками и сахарочками.
Всхлипперт — он может и умный, но у него не хватает совести признать, что язык был непроработан
Если что, главный по C# вот этот парень
По-моему, сейчас самое время заняться Nemerle-2
Какую проблему решит Nemerle-2 по сравнению с C#, F# (и чо уж там, Nemerle-1)?
Если что, главный по C# вот этот парень
Он сейчас по TypeScript. Шарпом занимается Mads Torgersen. Тут они оба: https://channel9.msdn.com/Events/Build/2018/C9L05
Какую проблему решит Nemerle-2
Немерля (для начала) решает одну главную проблему — вот эти узколобые Хайлсберги во главе. Что бы ты ни делал, куда б не писал, всё сходится к кучке так называемых «разработчиков языка», через кость которых к мозгу пробиться невозможно. Немерля — открытый проект: хочешь — форкай, хочешь — пиши патчи, И ЭТО КОМПИЛИРУЕТСЯ! Причём вплоть до .NET 2.0; Казалось бы, с какого перепоя вдруг Roslyn'у понадобились все эти .NET 4.6, Core, PowerShell… да всё просто — язык внаглую похабят так, чтобы кроме как в вендюшной десяточке он нигде не канпелялся! Вот не скоты?..
А далее без остановок: свой синтаксис, свои идеи, DSLи всякие… Влад много об этом рассказывал. Как-то глупо даже спрашивать, «что решит Немерле», зная (если зная!) о его возможностях — это язык на порядок выше любой сегодняшней сишарпщины. А Немерле-2 решит проблему «не очень проработанной» базы Немерли-1, только и всего — сам язык менять почти не надо.
Скалашарп
Шестая версия EF такого точно не «прожует»:
db.Swords
.Select(s => new Sword(s.Damage, s.Durability))
.OrderBy(s => s.Damage).First(); // ошибка: неизвестное свойство "Damage"
db.Swords
.Select(s => new Sword { Damage = s.Damage, Durability = s.Durability))
.OrderBy(s => s.Damage).First(); // а так нормально
должно соблюдаться typeof(T?) != typeof(T)
Угу, а еще должно соблюдаться typeof(T?).IsAssignableFrom(typeof(T))
, правда же?
Вот только я не знаю, как и какой ценой. Количество кода, которое мне приходится писать для работы с Nullable
каждый раз, меня радикально выбешивает.
Атрибуты как раз решают: они позволяют сделать эту фичу на уровне языка, а не фреймворка.
Атрибуты как раз решают: они позволяют сделать эту фичу на уровне языка, а не фреймворка.
Атрибуты — это же не языковая конструкция. Это добавляет управляющего кода для исполнения. Обслуживается средой исполнения, ну, или можно кодогнерацией управлять. Так что получается на уровне фреймворка.
Это добавляет управляющего кода для исполнения.
Нет, это добавляет метаданных для анализа.
Обслуживается средой исполнения, ну, или можно кодогнерацией управлять. Так что получается на уровне фреймворка.
Насколько я помню текущую реализацию, CLR никак не использует расставляемые C# 8 атрибуты, они используются только при анализе времени компиляции.
CodeAccessSecurityAttribute
DnsPermissionAttribute
SocketPermissionAttribute
или
ThreadStaticAttribute
и еще куча разных интересных атрибутов?
Кто как не CLR их использует?
using System;
public class C {
class Foo{
}
struct Bar{
}
public static void Main() {
Console.WriteLine(typeof(Foo) == typeof(Foo?) );
Console.WriteLine(typeof(Bar) == typeof(Bar?) );
}
}
Получаем:
True
False
По-моему, это ужасно. Да, там действительно атрибут. Надеюсь, в релизе такого поведения не будет.
Вы, вероятно, не узнали синтаксис, использованный в последнем методе класса
Те кто пишет на Kotlin легко поняли всю декларацию )
Запланированные новые возможности C# 8.0