Здравствуйте, sqrt, Вы писали:
S>Здравствуйте, Jack128, Вы писали:
J>>https://devblogs.microsoft.com/dotnet/introducing-net-5/
J>>Основное: J>>Моно и коре унифицируют, оба будут юзать единый corefx. J>>Всерьез взялись за AOT.
S>
S>next release after .NET Core 3.0 will be .NET 5
S>Если правильно понял, то после .NET Core 3.0 больше не будет деления на .NET Core и .NET FW, а будет единый .NET 5
а Winform и WPF остаются Windows specific, их исключат из .NET5 и будут отдельные сборки через nuget подключаться ?
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, Jack128, Вы писали:
J>introducing-net-5
Они нас за идиотов держат? Причём тут ПЯТЬ вообще?! Кора — она до 3.0 еле дотянула и она же будет типа "единым дотнетом" для всех? Вы её сначала сделайте, потом уже "единьте"! Одних едрорастов мы уже знаем... От того, что к 3.0 прибавили 1 и получили 5, мне как-то пофиг, у меня .NET 4.8 и он не имеет никакого отношения к этой "параллельной Корко-вселенной". Тут явный мухлёж и подмена понятий. Следующая Кора — это 4.0 и она явно несовместима с .NET 4.8; к чему нам пудрить мозг?
J>Моно и коре унифицируют, оба будут юзать единый corefx.
Можно подумать, кого-то это волнует! Вот лет 15 назад это было бы интересно — единый .NET, линупсы всякие, хомячки красноглазые, айфоны, иОСы... была ниша и она была интересна. Сейчас у iOS свои прогеры на своём местечковом ОбжСи и Свифте, шарповодам там делать точно нечего — у них нет ни нативных контролов, ни полной интеграции в ОСь.
Ты можешь сделать кнопки, "выглядящие как настоящие", но ты никогда не сделаешь нативное ПО если ты не будешь юзать нативные же средства низлежащей системы. То же "единое меню приложений" — в .NET'е его отродясь не было, ни в WinForms, ни в WPF. Ну и кому нужны мелкомягкие потуги по имитации макакоси, когда всё равно приложение не будет иметь native feel?
J>Всерьез взялись за AOT.
Ещё более не интересно. За него нужно было браться опять же со дня зарождения .NET'а — тогда бы нам не понадобилась тупая и непроизводительная вирт.машина, а было бы "как в старь" — цэшарп, компилируемый в нативный x86. Для чего было делать "переносимую VM", которая кроме венды нигде не работала — я не знаю. Бухой Гейтс придумал, штоле?
Просто задумайтесь...
Зачем вам сегодня переносимость? Кому, что и куда переносить? ЧТО переносить и чего нет в других платформах?
iOS — как уже сказал, там своя атмосфера, свои контролы, архитектура системы, всё своё. Чужаков там обоссут и выгонят. Если пустят вообще — это ж Огрызэппл! Анально огороженая секта тщеславных нищебродов.
iPhone — намеренно выделяю отдельно, потому что МОГЛИ БЫ что-то там писать, но опять же — никто не пустит клоунов с UWP портить идилию родной системы.
Linux — там вообще трындец: стотыщ либ, десятки конфигов и оболочек, Window Managers, менеджеров пакетов, языков, версий языков, версий самого Линупса, и т.д. Сделать для всех линуксов единую Дотнетину точно не выйдет. Хуже того — сами пингвинутые на всю голову ненавидят Мелкософт, будто у них Гейтс мамку трахнул. Ну кто и что там будет писать?? Кто хотел — давно написал, особено касается интыпрайза. Приходить в полностью рабочее решение "а нате, поюзайте нашу Дотнетину" — только смешить пиджаки.
Сам Линупс на десктопах за ДЕСЯТИЛЕТИЯ не занял и 20%. Связываться с ним за его убогий 1% — вообще не впёрлось. Писать на нём "безгуёвщину серверную" — А ЗАЧЕМ? Если я умею GUI на джабах, то и серверную часть 100% сделаю на жабе тоже — зачем мне винегрет в проекте?
IoT: вот кому-кому, но не дотнету там рулить! IoT — это буквально единицы килобайт памяти, несколько мегагерц проц и может быть есть флэшка. Потому "десятка" и не лезет никуда дальше Малины, что её больше никто и не потянет! Ну и кто эту смехотворную дотнетину будет серьёзно воспринимать в мире МК??
Вот и получается, что сегодня эти унылые потуги с "многоплатформенностью" — наивный пшик, развлечение студоты (которую и набрали в M$). Она попросту никому не нужна, все ниши давно заняты и заполнены ПО. При этом "родная" же для M$ венда — позорище на копытах, которое как раз и можно было оживить, сделай M$ нормальную, микроядерную систему со встроенным дотнетом. Тогда б и дистр венды весил 100МБ!
Ну вощем, эта орда студентов ещё получит пинка под зад со своими линупсятными замашками и никчемушными амбициями. Венда — наше всё, нет никаких "воин осей", это блеф и мечты.
Здравствуйте, Kolesiki, Вы писали:
K>Они нас за идиотов держат? Причём тут ПЯТЬ вообще?! Кора — она до 3.0 еле дотянула и она же будет типа "единым дотнетом" для всех?
Есть большая надежда что это будет реально .NET 5. Обьединить лучшие аспекты существующих реализаций и устранить разрушающую сегментацию — больщой шаг вперед.
Хватит ли у них сил и мозгов сделать такую реализацию — другой вопрос.
Здравствуйте, BlackEric, Вы писали:
BE>Вывод из прочитанного: на .Net Core ничего переводить не спешим. Ждем .net 5. Вот только не понятно что будет с .Net Standard.
А на основании чего такой вывод? .NET5 — это и есть следующая версия Core. Там не будет WinForms или классического (не Core) MVC/WebApi. Так что либо вы сидите на .NET Framework 4.8, либо перелазите на корку.
Здравствуйте, Jack128, Вы писали:
J>А на основании чего такой вывод? .NET5 — это и есть следующая версия Core. Там не будет WinForms или классического (не Core) MVC/WebApi. Так что либо вы сидите на .NET Framework 4.8, либо перелазите на корку.
WinForms там как раз будет, как и в Core 3.0.
А вот насколько гладким будет переход пока не понятно. Хотя все новое длать безусловно на Core нужно.
Здравствуйте, BlackEric, Вы писали:
BE>Здравствуйте, Jack128, Вы писали:
J>>А на основании чего такой вывод? .NET5 — это и есть следующая версия Core. Там не будет WinForms или классического (не Core) MVC/WebApi. Так что либо вы сидите на .NET Framework 4.8, либо перелазите на корку.
BE>WinForms там как раз будет, как и в Core 3.0.
Опечатался, WebForms конечно.
Смысл в том, что если некая технология не поддерживает Core — то её и не будет в .NET5. Хотя как показали те же Wpf/WinForms — поддержать всё можно, было бы желание.
Здравствуйте, BlackEric, Вы писали:
BE>на .Net Core ничего переводить не спешим. Ждем .net 5
Судя по их роудмапу, ждать придётся больше года, минимум до ноября 2020. Это всё-таки большой срок в масштабе карьеры, да и жизни в целом.
BE>А вот насколько гладким будет переход пока не понятно.
Представляется вероятным, что перейти с .NET Core 3.1 будет проще, чем с .NET 4.8. Так что если интересует гладкость в далёком будущем, начинать готовиться имеет смысл уже в настоящем.
J>Смысл в том, что если некая технология не поддерживает Core — то её и не будет в .NET5. Хотя как показали те же Wpf/WinForms — поддержать всё можно, было бы желание.
Так разве Wpf/Winforms поддерживаются в .Core3.0 ? Просто не совсем понимаю что значит поддерживаются в .net core, но запускаются только под Windows.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, okon, Вы писали:
O>а Winform и WPF остаются Windows specific, их исключат из .NET5 и будут отдельные сборки через nuget подключаться ?
А зачем нужен WinForms — это не более чем порт библиотеки Delphi VCL на реалии шарпа. Во времена C#2 это было логично и понятно, но затем вышел C#3 и WPF. Уже тогда WinForms стало легаси.
Здравствуйте, Mr.Delphist, Вы писали:
MD>Здравствуйте, okon, Вы писали:
O>>а Winform и WPF остаются Windows specific, их исключат из .NET5 и будут отдельные сборки через nuget подключаться ?
MD>А зачем нужен WinForms — это не более чем порт библиотеки Delphi VCL на реалии шарпа. Во времена C#2 это было логично и понятно, но затем вышел C#3 и WPF. Уже тогда WinForms стало легаси.
Немного про другое, можно убрать Winforms, оставить WPF но вопрос остается что значит WPF поддерживается .net core, при этом работает только под Windows.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, okon, Вы писали:
O>Немного про другое, можно убрать Winforms, оставить WPF но вопрос остается что значит WPF поддерживается .net core, при этом работает только под Windows.
WPF имеет более независимую от ОС вариацию, UWP. И вот она как раз уже не завязана на Win32 API и может быть портирована по сути автоматически на любое железо где есть .NET
Здравствуйте, Mr.Delphist, Вы писали:
MD>Здравствуйте, okon, Вы писали:
O>>Немного про другое, можно убрать Winforms, оставить WPF но вопрос остается что значит WPF поддерживается .net core, при этом работает только под Windows.
MD>WPF имеет более независимую от ОС вариацию, UWP. И вот она как раз уже не завязана на Win32 API и может быть портирована по сути автоматически на любое железо где есть .NET
Возможно, но мне казалось наоборот UWP более узкое применение чем WPF, т.е. UWP это только Windows 10 + Windows 10 Mobile. Возможно конечно архитектура позволит ее проще портировать чем WPF, но в Core3.0 или .NET5 разве есть анонс что UWP теперь будет кросплатформена ?
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, okon, Вы писали:
O>что значит WPF поддерживается .net core, при этом работает только под Windows.
.NET Core под Windows лучше, чем .NET Framework под Windows. Поэтому и порт WPF с .NET Framework под Windows на .NET Core под Windows — это хорошо.
.NET Framework will get fewer of the newer platform and language features that come to .NET Core moving forward, due to the in-place update nature of .NET Framework and the desire to limit changes there that might break existing applications.
— http://rsdn.org/forum/dotnet/7287981.1
O>что значит WPF поддерживается .net core, при этом работает только под Windows.
Это значит, что хоть API и доступен на всех платформах, только реализация немного разная. А именно, выглядит как «throw new NotSupportedException();» на платформах, отличных от Windows.
O>>что значит WPF поддерживается .net core, при этом работает только под Windows. Q>Это значит, что хоть API и доступен на всех платформах, только реализация немного разная. А именно, выглядит как «throw new NotSupportedException();» на платформах, отличных от Windows.
А есть способ данный момент обеспечить WPF приложению нормальное завершение, например выдать сообщение пользователю что "В текущей ОС не поддерживается", вместо аварийного завершения.
И насколько долго оно планируется быть NotSupported интересно под Linux,MacOS.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, okon, Вы писали:
O>А есть способ данный момент обеспечить WPF приложению нормальное завершение, например выдать сообщение пользователю что "В текущей ОС не поддерживается", вместо аварийного завершения.
Я не ставил v3.0.0-preview5, не уверен даже, что на данный момент там была заявлена поддержка WPF. Помню только, что её обещали к релизу Core 3.0 осенью. Но API для проверки текущей OS есть.
O>И насколько долго оно планируется быть NotSupported интересно под Linux,MacOS.
WPF сильно завязан на Direct3D; так что с высокой вероятностью оно таким NotSupported будет всегда.
Здравствуйте, okon, Вы писали:
O>А есть способ данный момент обеспечить WPF приложению нормальное завершение, например выдать сообщение пользователю что "В текущей ОС не поддерживается", вместо аварийного завершения.
Да.
O>И насколько долго оно планируется быть NotSupported интересно под Linux,MacOS.
Здравствуйте, okon, Вы писали:
MD>>WPF имеет более независимую от ОС вариацию, UWP. И вот она как раз уже не завязана на Win32 API и может быть портирована по сути автоматически на любое железо где есть .NET O>Возможно, но мне казалось наоборот UWP более узкое применение чем WPF
Здравствуйте, BlackEric, Вы писали:
BE>Вывод из прочитанного: на .Net Core ничего переводить не спешим.
Странный вывод. Ты если еще не понял — FW мертв уже официально. Все, финита ля комедиа. Оставаться на мертвом фреймворке, который даже компилятор шарпа поддерживает не полностью? Ну, у каждого свои причуды.
BE> Ждем .net 5.
Зачем?
BE> Вот только не понятно что будет с .Net Standard.
Пока эволюционирует. Но версия 2.1 уже в FW не поддерживается, что характерно.
.NET Core пошел по пути, которым Kotlin (JRE, Native, JS) идет уже несколько лет. Суть в том, чтобы иметь на уровне исходников частично общую кодовую базу для разных устройств (например, iOS, Android и бэкенд). GUI, разумеется будет везде свой.
Здравствуйте, karbofos42, Вы писали:
K>Здравствуйте, Kolesiki, Вы писали: K>>Зачем вам сегодня переносимость? Кому, что и куда переносить? ЧТО переносить и чего нет в других платформах?
K>Под каждую платформу свою гениальную бизнес-логику переписывать отдельно на "правильном" языке?
Зависит от того, что ты пишешь и насколько твои трудозатраты на остальных платформах окупятся твоей компании!
В классе клиент-серверного ПО вообще никаких проблем нет: пишем простой вендосервис, rich-клиента под венду + пара web-страниц ограниченного клиента для ВСЕХ остальных мыслимых железяк.
Самостоятельное десктоп-приложение — я уже писал, оно по-любому будет КРИВЫМ под Макось, ГЕМОРОЙНЫМ под Линупс и незапускабельным под мобилы.
Чебурашки наивно полагают, что если в нескольких ОС есть общие вещи — типа файлы, кнопки, сокеты, окна... , то типа можно напрячься и сделать Один Большой Фрэймворк, на котором можно делать ВСЁ. Глупая ошибка зелёных подаванов! Дьявол кроется в мелочах — во всех этих tray, system-wide menu, Memory Mapped Files, task bar animation...
Так что этот говнофрэймворк .NET Core (как пример) будет лишь Наибольшим Общим Делителем всех платформ. А это уже минус юзабилити и всем тем милым сердцу уникальным штучкам, которые существуют в каждой ОС. Я могу стерпеть, если у меня не будет прогресс-бара на таск-бар кнопке, но если другой чел сделает нативное вендо-приложение, где он есть, я не буду долго размышлять: я всегда предпочту нативное ПО "универсальному". ПОТОМУ ЧТО Я — ЮЗЕР! Меня не колышат ТВОИ проблемы как программиста, что ты типа хочешь уменьшить свои личные затраты, написав "один раз для всего" — не выйдет! Любой нативный разработчик заткнёт за пояс твои программы, потому что будет использовать возможности родной ОС во весь рост. Кратко, "универсальным фрэймворком" ты уменьшаешь лишь личные затраты (до которых юзеру пофиг), автоматом проигрывая любому нативному ПО и без какой-либо гарантии успешности твоего ПО на любой из платформ. Ты готов играть в "многоплатформенность" по таким правилам?
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, BlackEric, Вы писали: BE>>Вывод из прочитанного: на .Net Core ничего переводить не спешим.
НС>Странный вывод. Ты если еще не понял — FW мертв уже официально.
Не смеши мой дисковод! Нашёл кого хоронить... FW существует СЕМНАДЦАТЬ ЛЕТ, за которые написана куча ПО и создана полная инфраструктура.
То, что сонные клоуны очнулись и удивились, что их "многоплатформенный .NET" работает только на венде — это их проблемы, у самих .NET-программистов с этим проблем нет и не было! Вот ключевой момент, почему "официальные похороны FW" — тупой фарс мелкософта, не менее смешной, чем похороны Win7
У Core есть только один вариант стать "будущим": если завтра выкатят комплект "VS + Core", которые будут 1:1 компилять всё "старое" ПО под FW, включая WPF, WinForms и даже консоль. Не будет полной совместимости — сразу посылаются в зад. Нам не нужны обещания, какие-то кривые-сырые бетты, Кошмарин (прости господи) и прочая левота. У нас есть клиенты (далёкие от ИТ люди) и им фиолетовы микрософтовы "рассуждения в воздухе" о многоплатформенности, тырнете вещей... у них есть венда и всё должно работать. На игры в Core "поработай бесплатным бета-тестером микрософта" ресурсов нет, желания — тем более. Ну и чо вы тут хороните?? смешные вы, крестьянские дети.
Здравствуйте, Kolesiki, Вы писали:
K>Не смеши мой дисковод! Нашёл кого хоронить... FW существует СЕМНАДЦАТЬ ЛЕТ, за которые написана куча ПО и создана полная инфраструктура.
Тем не менее это факт.
K>У Core есть только один вариант стать "будущим": если завтра выкатят комплект "VS + Core", которые будут 1:1 компилять всё "старое" ПО под FW, включая WPF, WinForms и даже консоль.
Оно примерно так в 3.0 и будет.
K> Не будет полной совместимости — сразу посылаются в зад.
Ну посылай, толку то. Будешь сидеть на старых фреймворках и либах. Тебе даже C#8 в полном объеме не будет доступен.
Здравствуйте, okon, Вы писали:
O>Возможно, но мне казалось наоборот UWP более узкое применение чем WPF, т.е. UWP это только Windows 10 + Windows 10 Mobile.
Молодец, отметил ключевой момент! Игры мелкософта с Core не могут проходить без настырного просовывания во все щели УбогоДесятки. Из-за этой поганой и разрушительной политики сама некрософт будет разрываться между "никто не мобирается писать сугубо под Win10" и "ну когда же мы засунем всем телеметрию по самые гланды и забудем про Win7!". И внутренние программисты M$ тоже прекрасно это понимают — кто как не прогеры лучше всех осведомлены о полном провале Win10 и вполне стабильном "мире Windows.NET".
Повангую: в Core ещё года три минимум будут портировать ГУЙню. Учитывая криворукость и низкопробность их индусов, портируют только WPF, да и тот с ошибками. А между прочим, WinForms никуда своих позиций не сдавал! Все эти три года нас будут отчаянно убеждать, что "время перелазить на Core". ...и тыкать во всякие Кошмарúны. Всё это будет проходить под продолжающимися попытками M$ похоронить себя под обломками EpicFail-10, на которую потрачено уже больше, чем на написание отдельной ОС.
Я не ретроград, я люблю "всё новое" но как программист с ответственностью перед клиентом (привет, хипстеры от .NET! ), обязан чётко понимать все риски перехода куда-либо, ОСОБЕННО в таких фундаментальных вещах, как целая платформа. Нет никакой совместимости Core и FW — это сказки. Как и сказки о "мы ща, мы все платформы накроем!" — пупок развяжется. Так что стратегия ближайших 5-10 лет: Win7, FW, WinForms/WPF. Даже MS SQL, позорно отхаченный под Win10-only, будет отрицательно влиять на продажи. Ох, мрачное же будущее ждёт этих танцоров!
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, Kolesiki, Вы писали: K>>Не смеши мой дисковод! Нашёл кого хоронить... FW существует СЕМНАДЦАТЬ ЛЕТ, за которые написана куча ПО и создана полная инфраструктура.
НС>Тем не менее это факт.
Есть серьёзные события, коренным образом влияющие на индустрию, а есть разряда "Молдавия опять взвинтила цены на укроп". Вот похороны FW — это из поледнего.
Даже если MS выгонит вообще всех из отдела разработки FW, он у нас уже есть. Что может сделать убогая M$ с моими инструментами? Да ничего, как писал — так и буду писать! И тысячи других прогеров тоже не хотят танцевать на граблях Core, работая бесплатными бета-тестерами и теряя деньги на клиентах.
K>>У Core есть только один вариант стать "будущим": если завтра выкатят комплект "VS + Core", которые будут 1:1 компилять всё "старое" ПО под FW, включая WPF, WinForms и даже консоль.
НС>Оно примерно так в 3.0 и будет.
БУДЕТ, но не сегодня же! А переходить просят уже сейчас — "вот, смотрите, мы уже сканпеляли хелловорлд!". Извини, даже не смешно. Вот когда будет полная поддержка (хотя бы WPF) — тогда можно начать разговор (не переход!) о том, "а нафик нам вообще обздались ваши идеи?".
Технологии в мире ИТ — они ж не только "смотрите, ЧТО мы изобрели!" (напр. Core), но и "а какой профит моему бизнесу от того, что мои прогеры будут тратить время на портирование ваше Core?". Можно им показывать плакаты с IoT, ML и прочей требухой, но если у бизнеса нет потребности в этой хипстоте, то и сам переход под Core как бы чуть менее, чем ненужен.
K>> Не будет полной совместимости — сразу посылаются в зад.
НС>Ну посылай, толку то. Будешь сидеть на старых фреймворках и либах.
Чем они "старые", если в них есть всё и это "всё" работает? Я ж говорю: 17 лет, Карл! Это не просто года, это развитый, стабильный фрэймворк, работая с которым мне не нужно больше думать о примитивном нижнем слое — я просто пишу бизнес-логику.
НС> Тебе даже C#8 в полном объеме не будет доступен.
А я прямо расстроился! Люди на Жабе пишут — и ничё, не тошнит! (хотя я её презрел даже после "примитивного" C# 2.0) У нас уже всё есть, остаётся только писать! Что M$ будет делать с языком — я уже убедился на примере маразматических not-null типах, так что даже если M$ ограничит улучшения C# платформой Core, я не сильно расстроюсь. Но учитывая, что прямо сейчас я сижу в VS2019 с C# 8.0, вряд ли M$ пойдёт на такой безумный шаг. Ну и не сочтите за анекдот, есть Nemerle — я до сих пор считаю, что у него есть перспективы. У него плохо с инструментами, зато отлично с развитием. "Будут зажимать C# — обидимся и уйдём на Немерлю!".
Здравствуйте, Kolesiki, Вы писали:
НС>>Тем не менее это факт. K>Есть серьёзные события, коренным образом влияющие на индустрию, а есть разряда "Молдавия опять взвинтила цены на укроп". Вот похороны FW — это из поледнего.
Тем не менее это факт.
K>>>У Core есть только один вариант стать "будущим": если завтра выкатят комплект "VS + Core", которые будут 1:1 компилять всё "старое" ПО под FW, включая WPF, WinForms и даже консоль. НС>>Оно примерно так в 3.0 и будет. K>БУДЕТ, но не сегодня же!
В сентябре.
K> А переходить просят уже сейчас — "вот, смотрите, мы уже сканпеляли хелловорлд!". Извини, даже не смешно. Вот когда будет полная поддержка (хотя бы WPF)
Да пофик на WPF, десктоп давно и планомерно дохнет.
K>Технологии в мире ИТ — они ж не только "смотрите, ЧТО мы изобрели!" (напр. Core), но и "а какой профит моему бизнесу от того, что мои прогеры будут тратить время на портирование ваше Core?".
Профит очень простой. ВМ в ажуре на линуксе стоит в 2-4 раза дешевле винды, а компьют в большинстве проектов самая крупная часть трат на инфраструктуру.
НС>>Ну посылай, толку то. Будешь сидеть на старых фреймворках и либах. K>Чем они "старые", если в них есть всё и это "всё" работает?
Тем что индустрия не стоит на месте.
K> Я ж говорю: 17 лет, Карл! Это не просто года, это развитый, стабильный фрэймворк, работая с которым мне не нужно больше думать о примитивном нижнем слое — я просто пишу бизнес-логику.
Ну пиши, чо. Тебя ж никто не заставляет. Некоторые на Коболе до сих пор пишут.
НС>> Тебе даже C#8 в полном объеме не будет доступен. K>А я прямо расстроился! Люди на Жабе пишут — и ничё, не тошнит!
Если б не тошнило, никто бы не писал на Котлине и Скале. Да и сама Джава на месте тоже не стоит.
K>Чебурашки наивно полагают, что если в нескольких ОС есть общие вещи — типа файлы, кнопки, сокеты, окна... , то типа можно напрячься и сделать Один Большой Фрэймворк, на котором можно делать ВСЁ. Глупая ошибка зелёных подаванов! Дьявол кроется в мелочах — во всех этих tray, system-wide menu, Memory Mapped Files, task bar animation...
GUI кроссплатформенный для iOS, MacOS, Win, Linux никто делать не собирается, он будет свой под каждую платформу. А вот запихать общую для бекэнда и клиента часть логики в кроссплатформенную библиотеку, чтобы не дублировать, а использовать единую кодовую базу — именно для этого и придумали Kotlin. А теперь и .NET Core 5 туда же пытается пролезть. Вот только .NET пытается пропихнуть прослойку в виде Xamarin, там где напрямую он не работает, а Kotlin такие вещи реализует через Kotlin Native.
Здравствуйте, Kolesiki, Вы писали:
K>Здравствуйте, karbofos42, Вы писали:
K>>Здравствуйте, Kolesiki, Вы писали: K>>>Зачем вам сегодня переносимость? Кому, что и куда переносить? ЧТО переносить и чего нет в других платформах?
K>>Под каждую платформу свою гениальную бизнес-логику переписывать отдельно на "правильном" языке?
K>Зависит от того, что ты пишешь и насколько твои трудозатраты на остальных платформах окупятся твоей компании!
Да что ни пиши, либо один и тот же функционал пишешь один раз или дважды. Скорее всего это будут две разные команды и вот у одного и того же функционала две версии со своими багами и привет удвоенной стоимости поддержки и т.п.
K>В классе клиент-серверного ПО вообще никаких проблем нет: пишем простой вендосервис, rich-клиента под венду + пара web-страниц ограниченного клиента для ВСЕХ остальных мыслимых железяк.
чего это под винду вдруг жирный клиент, а под какой-нибудь мак или андроид — странички?
K>Самостоятельное десктоп-приложение — я уже писал, оно по-любому будет КРИВЫМ под Макось, ГЕМОРОЙНЫМ под Линупс и незапускабельным под мобилы.
Из натива нужны View и ViewModel, доступ к данным, бизнес-логика и всё остальное прочее вполне себе может быть кроссплатформенным и никто это не заметит.
K>Чебурашки наивно полагают, что если в нескольких ОС есть общие вещи — типа файлы, кнопки, сокеты, окна... , то типа можно напрячься и сделать Один Большой Фрэймворк, на котором можно делать ВСЁ. Глупая ошибка зелёных подаванов! Дьявол кроется в мелочах — во всех этих tray, system-wide menu, Memory Mapped Files, task bar animation...
трей, меню, таск бары — это всё View и я про него ничего не говорил. Кроссплатформить UI для прикладного ПО — отвратительный подход.
Чем отличается получение данных от какой-нибудь БД в разных ОС? Подключить нужного провайдера и всё. Запросы те же, данные те же, а то и вовсе всё ORM разрулит.
K>Так что этот говнофрэймворк .NET Core (как пример) будет лишь Наибольшим Общим Делителем всех платформ. А это уже минус юзабилити и всем тем милым сердцу уникальным штучкам, которые существуют в каждой ОС. Я могу стерпеть, если у меня не будет прогресс-бара на таск-бар кнопке, но если другой чел сделает нативное вендо-приложение, где он есть, я не буду долго размышлять: я всегда предпочту нативное ПО "универсальному".
Открываю тайну: можно написать кроссплатформенный метод "СделатьВсёКруто", написать его один раз и потом баги в нём править один раз. А вот большую красную кнопку, по которой вызывается этот метод, сделать нативной.
K>ПОТОМУ ЧТО Я — ЮЗЕР! Меня не колышат ТВОИ проблемы как программиста, что ты типа хочешь уменьшить свои личные затраты, написав "один раз для всего" — не выйдет! Любой нативный разработчик заткнёт за пояс твои программы, потому что будет использовать возможности родной ОС во весь рост.
Поэтому пока пользователи вынуждены сидеть на той же платформе, что и разработчики нужного ПО. Ну, или меняют набор своего ПО, при переходе на другую платформу. Потому что мало кто может себе позволить разрабатывать несколько версий одного и того же. Если ПО существует на нескольких платформах, то там основная доля кода кроссплатформенная, а не пилится под каждую платформу отдельно.
K>Кратко, "универсальным фрэймворком" ты уменьшаешь лишь личные затраты (до которых юзеру пофиг), автоматом проигрывая любому нативному ПО и без какой-либо гарантии успешности твоего ПО на любой из платформ. Ты готов играть в "многоплатформенность" по таким правилам?
У нас есть нативный IE и кроссплатформенный Chromium. Нормальный пример?
Или игра какая-нибудь на каком-нибудь OpenGL. Что там нативщик такого может сделать, чего нельзя на кроссплатформе?
Здравствуйте, Aquilaware, Вы писали:
A>Имхо, угандошенный интерфейс. A>(Видимо исключения в детском саду, больном корью, еще не проходили, но всё ещё впереди :))) )
Даже уже в детском саду рассказывают, что исключения не надо использовать для normal control flow.
Здравствуйте, Qbit86, Вы писали:
Q>Даже уже в детском саду рассказывают, что исключения не надо использовать для normal control flow.
Исключения не являются частью нормального control flow.
Но вот что конкретно означает этот Try в TryFormat? Доки — нет. Если только из-за размера буфера, то это странно. Или намек на то, что недостаточный буфер — это нормальный control flow. Х.з. но с первого взгляда выглядит по-делитански.
Вот подобные вещи и ставят под угрозу всю концепцию .NET 5. На словах — красиво. Но если под копотом будет подобные болезни — не взлетит.
Здравствуйте, Qbit86, Вы писали:
Q>То же, что и во всех остальных API, доступных сто лет: TryGetValue, TryParse, TryGetBuffer, etc.
Обратите внимание, что все перечисленные API возвращают результат в зависимости от входных данных или текущего состояния обьекта. Что логично и очень понятно.
А в случае TryFormat подразумевается некоторое действие которое может быть выполнено или не выполнено в зависимости от? Предпологаемых выходных данных? Входных данных? Фазы луны? Текущего календаря? Времени жизни нынешнего императора Японии? Здесь нет однозначной интерпретации. И это вызывает когнитивный дисонанс, особенно тот факт что этими неуклюжими TryFormat предлагают облепить почти все базовые типы.
Здравствуйте, Qbit86, Вы писали:
Q>То же, что и во всех остальных API, доступных сто лет: TryGetValue, TryParse, TryGetBuffer, etc.
TryParse — это понятно, там неизвестный вход и потенциальная ошибка преобразования, но это может быть нормальным потоком исполнения. А TryFormat — это тупость. Если Format кидает исключение, то это ошибка в программе.
Здравствуйте, AlexRK, Вы писали:
ARK>TryParse — это понятно, там неизвестный вход и потенциальная ошибка преобразования, но это может быть нормальным потоком исполнения.
В TryFormat ровно то же самое: неизвестный вход, который может как поместиться в буфер, так и не поместиться. Оба случая — нормальный поток выполнения.
Span<char> buffer = stackalloc char[8];
if (number.TryFormat(buffer, out int charsWritten))
textWriter.WriteLine(buffer.Slice(0, charsWritten));
else
textWriter.WriteLine("Failure");
Здравствуйте, Aquilaware, Вы писали:
A>Обратите внимание, что все перечисленные API возвращают результат в зависимости от входных данных или текущего состояния обьекта. Что логично и очень понятно.
В случае TryFormat ровно то же самое, в зависимости от входных данных.
A>А в случае TryFormat подразумевается некоторое действие которое может быть выполнено или не выполнено в зависимости от? Предпологаемых выходных данных? Входных данных? Фазы луны? Текущего календаря? Времени жизни нынешнего императора Японии? Здесь нет однозначной интерпретации.
Однозначная интерпретация есть — в зависимости от входных данных. Шутка про императора Японии вообще не к месту.
Здравствуйте, Qbit86, Вы писали:
ARK>>TryParse — это понятно, там неизвестный вход и потенциальная ошибка преобразования, но это может быть нормальным потоком исполнения.
Q>В TryFormat ровно то же самое: неизвестный вход, который может как поместиться в буфер, так и не поместиться. Оба случая — нормальный поток выполнения.
Хорошо, пусть это будет нормальный поток исполнения (правда, где в таком случае String.TryFormat, Console.TryReadLine, File.TryReadContent и т.д. и т.п.). Но убожества API это не отменяет — ничто не мешает просто заигнорить результат. В данном случае соображения корректности принесены в жертву "эффективности" (для которой дотнет все равно не предназначен).
Здравствуйте, AlexRK, Вы писали:
ARK>правда, где в таком случае String.TryFormat, Console.TryReadLine, File.TryReadContent и т.д. и т.п.
Это нужно в каждом отдельном случае рассматривать, насколько это уместно и/или востребовано.
ARK>Но убожества API это не отменяет — ничто не мешает просто заигнорить результат.
У любой функции можно заигнорить результат :xz:
ARK>В данном случае соображения корректности принесены в жертву "эффективности"
Обошлось без жертв — аллоцирующие методы остались на месте.
ARK>для которой дотнет все равно не предназначен
Здравствуйте, Qbit86, Вы писали:
ARK>>Но убожества API это не отменяет — ничто не мешает просто заигнорить результат. Q>У любой функции можно заигнорить результат
Исключение заигнорить нельзя (неявно или случайно).
ARK>>В данном случае соображения корректности принесены в жертву "эффективности" Q>Обошлось без жертв — аллоцирующие методы остались на месте.
Но появилась возможность некорректно применить неаллоцирующий метод.
Span<char> buffer = stackalloc char[1];
number.TryFormat(buffer, out int charsWritten); // oops
textWriter.WriteLine(buffer.Slice(0, charsWritten));
Здравствуйте, AlexRK, Вы писали:
ARK>Исключение заигнорить нельзя (неявно или случайно).
Исключения нежелательно использовать для normal control flow. Если пофиг на аллокации или исключения (и пофиг на пользователей твоей библиотеки), то используй ToString().
ARK>Но появилась возможность некорректно применить неаллоцирующий метод. ARK>
ARK>Span<char> buffer = stackalloc char[1];
ARK>number.TryFormat(buffer, out int charsWritten); // oops
ARK>textWriter.WriteLine(buffer.Slice(0, charsWritten));
ARK>
Так а что тут некорректного? charsWritten равен 0, buffer.Slice(0, charsWritten) будет пустым, стандартные реализации TextWriter'а корректно напечатают пустую строку.
Те же рассуждения применимы и к TryGetValue в словаре. Такой код в общем случае может быть умышленным, и будет вести себя вполне ожидаемым способом.
Здравствуйте, Qbit86, Вы писали:
ARK>>Исключение заигнорить нельзя (неявно или случайно). Q>Исключения нежелательно использовать для normal control flow.
Возможность случайного игнора ошибки тоже нежелательно использовать для normal control flow.
Q>Так а что тут некорректного? charsWritten равен 0, buffer.Slice(0, charsWritten) будет пустым, стандартные реализации TextWriter'а корректно напечатают пустую строку.
Не факт, что программист ожидал именно этого. И компилятор ему не помог.
Q>Те же рассуждения применимы и к TryGetValue в словаре.
Да, верно. Тоже, я считаю, не очень хорошее API. Это бич дотнета, не имеющего алгебраических типов.
Q>Такой код в общем случае может быть умышленным, и будет вести себя вполне ожидаемым способом.
Здравствуйте, Qbit86, Вы писали:
Q>Выглядит как всегда, вообще-то. Стандартный паттерн, какое ещё «делитански».
А можно показать пример корректного использования этого нового API?
А то я как-то не могу пока вьехать, как его применять.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AlexRK, Вы писали:
Q>>Те же рассуждения применимы и к TryGetValue в словаре.
ARK>Да, верно. Тоже, я считаю, не очень хорошее API. Это бич дотнета, не имеющего алгебраических типов.
Точнее конкретных языков.
В F#, Nemerle, Scala (которая была ещё для .NET) проблем ввести АТД не было.
Здравствуйте, _NN_, Вы писали:
ARK>>Да, верно. Тоже, я считаю, не очень хорошее API. Это бич дотнета, не имеющего алгебраических типов. _NN>Точнее конкретных языков. _NN>В F#, Nemerle, Scala (которая была ещё для .NET) проблем ввести АТД не было.
Здравствуйте, Aquilaware, Вы писали:
A>Но вот что конкретно означает этот Try в TryFormat? Доки — нет. Если только из-за размера буфера, то это странно. Или намек на то, что недостаточный буфер — это нормальный control flow. Х.з. но с первого взгляда выглядит по-делитански.
Да, похоже что только из за размера буфера.
Потому что в случае других ошибок TryFormat выбрасывает исключения: Decimal.TryFormat
System.FormatException if the format is not valid for this data type.
Хотя в том же System.Text.Decoder пара Convert()/GetCharCount() позволяла реализовать какие угодно сценарии.
Convert просто декодит до тех пор пока, есть место в буфере. При следующем вызове продолжает декодить в новый буфер с точки останова.
А если хочется декодить за один раз, то можно заранее вычислить размер буфера вызовом GetCharCount().
Вариант с TryFormat() получился не самым оптимальным по производительности — метод внутри себя сначала вычисляет необходимый размер буфера — TryFormatDecimalF
И в случае недостаточного размера вынуждает делать повторный вызов и повторно выполнять все вычисления и проверки.
Здравствуйте, AlexRK, Вы писали:
Q>>Те же рассуждения применимы и к TryGetValue в словаре.
ARK>Да, верно. Тоже, я считаю, не очень хорошее API.
Это идиоматичный API. Хорошо известный разработчикам с опытом на конкртеной платформе. Тут выше писали, что к нему ещё нет документации — я этого и не знал до текущего треда. Потому что не возникало необходимости заглядывать в справку — и так всё знакомо, понятно и не вызывает удивления.
ARK>Это бич дотнета, не имеющего алгебраических типов.
Здравствуйте, Qbit86, Вы писали:
Q>Здравствуйте, Sinclair, Вы писали:
S>>А можно показать пример корректного использования этого нового API?
Q>https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/Text/StringBuilder.cs
Спасибо, я как-то так и предполагал, но хотел убедиться. То есть предполагается ровно один паттерн: пробуем втиснуться в буфер, какой бы он ни был; если не сработало — фоллбэкаемся на обычный метод с выделением.
Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, sergeya, Вы писали:
S>Да, похоже что только из за размера буфера. S>Потому что в случае других ошибок TryFormat выбрасывает исключения: S>Decimal.TryFormat
S>Вариант с TryFormat() получился не самым оптимальным по производительности — метод внутри себя сначала вычисляет необходимый размер буфера — TryFormatDecimalF S>И в случае недостаточного размера вынуждает делать повторный вызов и повторно выполнять все вычисления и проверки.
Да уж. Я ж говорил — дилетантсво. Им бы это нутро пока лучше спрятать в internal. А то получается смесь коровы и собаки, и еще так гордо покакано во все базовые типы.
Здравствуйте, Sinclair, Вы писали:
S>Спасибо, я как-то так и предполагал, но хотел убедиться. То есть предполагается ровно один паттерн: пробуем втиснуться в буфер, какой бы он ни был; если не сработало — фоллбэкаемся на обычный метод с выделением.
Отчего ж один, можно еще в бесконечном цикле долбиться, увеличивая на единицу размер буфера, пока не влезет. Производительность!
Здравствуйте, Sinclair, Вы писали:
S>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
S>Спасибо, я как-то так и предполагал, но хотел убедиться. То есть предполагается ровно один паттерн: пробуем втиснуться в буфер, какой бы он ни был; если не сработало — фоллбэкаемся на обычный метод с выделением.
Это в принципе единственный способ форматировать в буфер, а не в аллоцированную строку. Вместо фоллбэка с аллокацией можешь брать всё большие буферы из ArrayPool<char>.Shared, неважно.
Здравствуйте, Qbit86, Вы писали:
S>>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Q>Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
А где можно посмотреть на ?
Там, где я смотрел, перед форматированием всегда вычисляется вычисляется необходимый размер буфера.
Например здесь — Utf8Formatter.TimeSpan в начале три экрана вычисления размера буфера и только потом один экран непосредственно форматирования.
Здравствуйте, AlexRK, Вы писали:
A>>Есть большая надежда что это будет реально .NET 5. Обьединить лучшие аспекты существующих реализаций
...никто не обещал. Просто название .net core 4 будет путаться с .net fw 4, а потому перешли сразу к версии 5. И убрали слово core чтобы показать, что .net fw особо развиваться уже не будет.
Здравствуйте, Kolesiki, Вы писали:
K>Зачем вам сегодня переносимость? Кому, что и куда переносить? ЧТО переносить и чего нет в других платформах?
Самый наибанальнейший пример — хостить asp.net сервер под линуксом (дешевле и доступнее хостинг), а разрабатывать под виндами и спокойно его и там и там запускать.
Весьма удобно, кстати.
Здравствуйте, sergeya, Вы писали:
Q>>Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
S>Там, где я смотрел, перед форматированием всегда вычисляется вычисляется необходимый размер буфера. S>Например здесь — Utf8Formatter.TimeSpan в начале три экрана вычисления размера буфера и только потом один экран непосредственно форматирования.
Вряд ли это можно найти в TimeSpan, потому что Dragon4 и Grisu3 — это алгоритмы для печати чисел с плавающей точкой в формате IEEE 754.
Здравствуйте, fmiracle, Вы писали:
F>Просто название .net core 4 будет путаться с .net fw 4, а потому перешли сразу к версии 5. И убрали слово core чтобы показать, что .net fw особо развиваться уже не будет.
We are also taking the opportunity to simplify naming. We thought that if there is only one .NET going forward, we don’t need a clarifying term like “Core”. The shorter name is a simplification and also communicates that .NET 5 has uniform capabilities and behaviors. Feel free to continue to use the “.NET Core” name if you prefer it.
— .NET 5 = .NET Core vNext
Здравствуйте, AlexRK, Вы писали:
ARK>Отчего ж один, можно еще в бесконечном цикле долбиться, увеличивая на единицу размер буфера, пока не влезет. Производительность!
И чем это отличалось бы от просто вызова выделяющего метода?
Или предлагается увеличивать буфер через stackalloc?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Qbit86, Вы писали:
S>>>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Q>>Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер.
Если бы это было так, и Dragon4/Grisu3 сразу печатали бы в буфер назначения, то в случае неуспешного завершения буфер был бы испорчен.
Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера,
и только после этого выполняется попытка скопировать результат в буфер-приемник.
А тут уже есть вся информация о том, сколько места не хватило.
Q>src\Common\src\CoreLib\System\Number.Formatting.cs
Код из приведенного тобой исходника:
private const int CharStackBufferSize = 32;
public static bool TryFormatDouble(double value, ReadOnlySpan<char> format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
{
Span<char> stackBuffer = stackalloc char[CharStackBufferSize];
var sb = new ValueStringBuilder(stackBuffer);
string? s = FormatDouble(ref sb, value, format, info);
return s != null ?
TryCopyTo(s, destination, out charsWritten) :
sb.TryCopyTo(destination, out charsWritten);
}
Здравствуйте, sergeya, Вы писали:
S>Если бы это было так, и Dragon4/Grisu3 сразу печатали бы в буфер назначения, то в случае неуспешного завершения буфер был бы испорчен.
Я не говорил, что он сразу печатает в выходной буфер.
S>Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера,
Ок, возможно в данной имплементации так.
S>А тут уже есть вся информация о том, сколько места не хватило.
Но в общем случае какая-нибудь другая реализация TryFormat для этого или какого-то другого типа может не знать сколько места не хватило. Скажем, нет смысла продолжать рендерить какой-нибудь список после того, как стало известно, что места в целевом буфере не хватит (даже если потенциально хватит во внутреннем буфере). Такая сигнатура TryFormat достаточна в большинстве случаев.
Здравствуйте, Qbit86, Вы писали:
S>>Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера, Q>Ок, возможно в данной имплементации так.
Ну т.е. у тебя нет практического примера, иллюстрируюего причину того, что "TryFormat не даёт нам информации о том, сколько места надо"?
Здравствуйте, Sinclair, Вы писали:
ARK>>Отчего ж один, можно еще в бесконечном цикле долбиться, увеличивая на единицу размер буфера, пока не влезет. Производительность! S>И чем это отличалось бы от просто вызова выделяющего метода? S>Или предлагается увеличивать буфер через stackalloc?
Здравствуйте, sergeya, Вы писали:
S>Ну т.е. у тебя нет практического примера, иллюстрируюего причину того, что "TryFormat не даёт нам информации о том, сколько места надо"?
Ты какие-то окольные наводящие вопросы задаёшь, экзаменуешь меня что ли, лол. Вообще не очевидно, с чего ты решил, что такая твоя позиция по отношению ко мне имеет хоть какие-то основания :)
Здравствуйте, sergeya, Вы писали:
S>Может быть не в тему, но для меня было открытием узнать, что stackalloc умеет выделять память динамического размера.
Тогда, возможно, также будет новостью узнать, что в C# 7 для stackallock уже больше не требуется unsafe-контекст. Правда, для этого требуется Span<T>, который есть в .NET Core, и которого нет и не будет в .NET Legacy. (Хотя его туда бэкпортировали в NuGet-пакете.)
Здравствуйте, Qbit86, Вы писали:
Q>Здравствуйте, sergeya, Вы писали:
S>>Ну т.е. у тебя нет практического примера, иллюстрируюего причину того, что "TryFormat не даёт нам информации о том, сколько места надо"?
Q>Ты какие-то окольные наводящие вопросы задаёшь, экзаменуешь меня что ли, лол.
Обычная дискуссия. Ты привел аргумент в защиту проектировщиков TryFormat, я его опроверг.
>>> Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо. >> Это логично, оно там внутре гоняет Dragon4/Grisu3, и не доделывает вхолостую при нехватке места только чтобы посчитать размер. > сначала печать выполняется в промежуточный буфер гарантированно достаточного размера, а тут уже есть вся информация о том, сколько места не хватило.
Поскольку ты все еще считашь дизайн TryFormat удачным, я поинтересовался, нет ли у тебя других практических примеров.
Q>Вообще не очевидно, с чего ты решил, что такая твоя позиция по отношению ко мне имеет хоть какие-то основания
А вот этого пассажа я не понял.
Здравствуйте, sergeya, Вы писали:
S>нет ли у тебя других практических примеров.
Других примеров я не знаю, но мне кажется, и пример с плавающими числами вполне подходит. Текущая сигнатура API позволяет при необходимости изменить реализацию так, чтоб она останавливала работу, если превысит переданную длину — как я ранее предполагал, что оно должно быть так реализовано. Если бы API обязывал реализацию считать требуемый размер, то так было сделать бы нельзя.
S>Поскольку ты все еще считашь дизайн TryFormat удачным, я поинтересовался, нет ли у тебя других практических примеров.
Поскольку ты все еще считашь дизайн TryFormat неудачным, давай теперь ты поищи примеры другого дизайна API форматирования в буфер, который возвращал бы рассчитанный формат. В Rust, в C++, где-нибудь. Кто там не «индусы» и не «делитанты».
Я TryFormat использую, и это точно было бы неудобно, если бы он как-то возвращал (пятым параметром) ещё и ненужный мне рассчётный размер (для тех типов, для которых его можно рассчитать, а для тех, для которых нельзя — не возвращал).
var t = 1;
Span<char> s;
unsafe
{
do
{
s = new Span<char>(stackalloc char[t],t);
t++;
}
while(!number.TryFormat(s, out int written))
}
Console.WriteLine(s);
представляется не самой хорошей идеей.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, okon, Вы писали: O>а Winform и WPF остаются Windows specific, их исключат из .NET5 и будут отдельные сборки через nuget подключаться ?
With the .NET Core 3.0 release in September 2019 we think that all *new* .NET applications should be based on .NET Core. The primary application types from .NET Framework are supported, and where we did not port something over there is a recommended modern replacement. All future investment in .NET will be in .NET Core. This includes: Runtime, JIT, AOT, GC, BCL (Base Class Library), C#, VB.NET, F#, ASP.NET, Entity Framework, ML.NET, WinForms, WPF and Xamarin.
Здравствуйте, Qbit86, Вы писали:
Q>Других примеров я не знаю, но мне кажется, и пример с плавающими числами вполне подходит. Текущая сигнатура API позволяет при необходимости изменить реализацию так, чтоб она останавливала работу, если превысит переданную длину — как я ранее предполагал, что оно должно быть так реализовано. Если бы API обязывал реализацию считать требуемый размер, то так было сделать бы нельзя.
S>>Поскольку ты все еще считашь дизайн TryFormat удачным, я поинтересовался, нет ли у тебя других практических примеров. Q>Поскольку ты все еще считашь дизайн TryFormat неудачным, давай теперь ты поищи примеры другого дизайна API форматирования в буфер, который возвращал бы рассчитанный формат. В Rust, в C++, где-нибудь. Кто там не «индусы» и не «делитанты».
int size = snprintf(NULL, 0, "%d", 132);
char * a = malloc(size + 1);
sprintf(a, "%d", 132);
Но меня смущает не отсутсвие расчитанного размера, а двойная работа — если размера буфера не хватит, придется выполнять форматирование повторно с самого начала.
Я в своем первом сообщении так и написал — http://rsdn.org/forum/dotnet/7441915.1
Поэтому рассчитанный размер мне тоже не очень нужен. Мне больше нравится дизайн System.Text.Decoder.Convert(), который позволяет продолжить конвертацию с предыдущей точки остановки.
Правда, для этого надо хранить состояние между вызовами, а сделать это для stackalloc буфера будет нетривиально (но варианты придумать можно).
Отдать остатки stackalloc буфера наружу без перевыделения памяти тоже не вариант.
Тут надо думать и рассматривать варианты использования.
Конкретно тот сценарий, который ты привел — AppendSpanFormattable
я бы реализовал с помощью метода FormatTo(stringBulder). Чтобы Decimal.Format() внутри себя печатал в stackalloc буфер, а затем вызвал stringBulder.Append(Span<char> span), внутри которого была бы вся та оптимизация — быстрое копирование во внутрненний буфер, а если его размер недостаточен, то динамическое расширение.
По аллокациям и процессорным тактам получилось бы оптимальнее, чем существущее решение — логика то и типы данных те же самые, но нет необходимости в повторных вызовов.
Здравствуйте, Qbit86, Вы писали:
S>>Может быть не в тему, но для меня было открытием узнать, что stackalloc умеет выделять память динамического размера. Q>Тогда, возможно, также будет новостью узнать, что в C# 7 для stackallock уже больше не требуется unsafe-контекст. Правда, для этого требуется Span<T>...
Здравствуйте, QrystaL, Вы писали:
QL>Здравствуйте, okon, Вы писали: O>>а Winform и WPF остаются Windows specific, их исключат из .NET5 и будут отдельные сборки через nuget подключаться ?
QL>
QL>With the .NET Core 3.0 release in September 2019 we think that all *new* .NET applications should be based on .NET Core. The primary application types from .NET Framework are supported, and where we did not port something over there is a recommended modern replacement. All future investment in .NET will be in .NET Core. This includes: Runtime, JIT, AOT, GC, BCL (Base Class Library), C#, VB.NET, F#, ASP.NET, Entity Framework, ML.NET, WinForms, WPF and Xamarin.
Ответа тут нет, пока только известно что WPF например сильно зависим от платформы и не портабелен.
.NET Core же предполагает портабельность.
.NET Core is an open-source, general-purpose development platform maintained by Microsoft and the .NET community on GitHub. It's cross-platform (supporting Windows, macOS, and Linux) and can be used to build device, cloud, and IoT applications.
Поэтому крайне не понятно что означает WPF в .NET Core — отказ от "It's cross-platform" или же кроссплатформенную реализацию.
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, sergeya, Вы писали:
S>Но меня смущает не отсутсвие расчитанного размера, а двойная работа — если размера буфера не хватит, придется выполнять форматирование повторно с самого начала.
Вот смотри — для базовых типов размер буфера неизвестен заранее для чисел и енумов. В обоих случаях посчитать размер буфера сопроставимо по затратам с собственно форматированием.
С другой стороны, всегда можно сделать буфер с запасом, так чтобы его хватало либо с гарантией, либо в 99.99% случаев. Поэтому ничего страшного в повторном форматировании нет.
S>Поэтому рассчитанный размер мне тоже не очень нужен. Мне больше нравится дизайн System.Text.Decoder.Convert(), который позволяет продолжить конвертацию с предыдущей точки остановки.
Ключевое отличиче — в случае конвертера объемы могут быть очень большими, заранее непредсказуемого размера. А вот в случае с TryFormat это не так и смысла переусложнять API нет.
Здравствуйте, Ночной Смотрящий, Вы писали:
S>>Но меня смущает не отсутсвие расчитанного размера, а двойная работа — если размера буфера не хватит, придется выполнять форматирование повторно с самого начала.
НС>Вот смотри — для базовых типов размер буфера неизвестен заранее для чисел и енумов. В обоих случаях посчитать размер буфера сопроставимо по затратам с собственно форматированием. НС>С другой стороны, всегда можно сделать буфер с запасом, так чтобы его хватало либо с гарантией, либо в 99.99% случаев. Поэтому ничего страшного в повторном форматировании нет.
Это если буфер для разовой операции. А если это буфер стрингбилдера, в который последовательно добавляются подстроки, буфер будет периодически исчерпываться.
S>>Поэтому рассчитанный размер мне тоже не очень нужен. Мне больше нравится дизайн System.Text.Decoder.Convert(), который позволяет продолжить конвертацию с предыдущей точки остановки.
НС>Ключевое отличиче — в случае конвертера объемы могут быть очень большими, заранее непредсказуемого размера.
Это вряд ли. Обычно конвертируют в цикле буферами конечной длины.
НС>А вот в случае с TryFormat это не так и смысла переусложнять API нет.
Что может быть проще decimal.FormatTo(stringBuilder)?
Здравствуйте, sergeya, Вы писали:
НС>>А вот в случае с TryFormat это не так и смысла переусложнять API нет.
S>Что может быть проще decimal.FormatTo(stringBuilder)?
StringBuilder внутри аллоцирует чанки. Непубличный ValueStringBuilder хотя бы делает ротацию через ArraPool<char>.Shared.
Форматирование же в Span<T> не налагает никаких требований по выбору стратегии роста, это примитив, на основании которого можно реализовывать более высокоуровневые API по записи в StringBuilder или TextWriter.
QL>With the .NET Core 3.0 release in September 2019 we think that all *new* .NET applications should be based on .NET Core. The primary application types from .NET Framework are supported, and where we did not port something over there is a recommended modern replacement. All future investment in .NET will be in .NET Core. This includes: Runtime, JIT, AOT, GC, BCL (Base Class Library), C#, VB.NET, F#, ASP.NET, Entity Framework, ML.NET, WinForms, WPF and Xamarin.
Здравствуйте, sergeya, Вы писали:
S>Это если буфер для разовой операции. А если это буфер стрингбилдера
У стрингбилдера свой алгоритм выделения буфера, не только под TryFormat. И никто не мешает этот алгоритм написать так, чтобы промахи на примитивных типах с размером буфера были редкими.
НС>>Ключевое отличиче — в случае конвертера объемы могут быть очень большими, заранее непредсказуемого размера. S>Это вряд ли.
Это факт.
S> Обычно конвертируют в цикле буферами конечной длины.
Вопрос только в размере буфера. Одно дело полсотни байт под числеку, и другое дело мегабайты под текст.
НС>>А вот в случае с TryFormat это не так и смысла переусложнять API нет. S>Что может быть проще decimal.FormatTo(stringBuilder)?
StringBuilder прибивает гвоздями к конкретной реализации со своими особенностями.
Здравствуйте, Qbit86, Вы писали:
Q>StringBuilder внутри аллоцирует чанки. Непубличный ValueStringBuilder хотя бы делает ротацию через ArraPool<char>.Shared. Q>Форматирование же в Span<T> не налагает никаких требований по выбору стратегии роста, это примитив, на основании которого можно реализовывать более высокоуровневые API по записи в StringBuilder или TextWriter.
Да, хороший аргумент, но на моих (субьективных) весах двойное вычисление перевешивает эти плюсы.
Кстати, можно было бы сделали бы какой нибудь IStringBuilder, с возможностью выбора аллоцирующей или ротирующей реализации.
Тогда в пессимистичном сценарии будет дополнительное выделение памяти против выделения + перевычисления в исходном варианте.
Народ давно уже просить сделать ValueStringBuilder публичным.
Ну да ладно, тут можно придумывать до бесконечности ))
Нет. Не только CoreFX. Майкрософтовец (Program Manager, .NET Team) пишет первым пунктом:
Produce a single .NET runtime...
И дальше он объясняет, дескать мы в microsoft не умеем AOT-оптимизацию с помощью LLVM. Без него нас и наш сбор телеметрии Apple не пустит (шутка). Украдем ка мы это у xamarin.
Может случиться как с гитхабом — сначала интегрировались чуть чуть, а для 2019й студии так и с потрохами купили
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>У стрингбилдера свой алгоритм выделения буфера, не только под TryFormat. И никто не мешает этот алгоритм написать так, чтобы промахи на примитивных типах с размером буфера были редкими.
Голословное утверждение. Я бы поверил, если бы ты привел ссылку на алгоритм или научное исследование.
НС>>>Ключевое отличиче — в случае конвертера объемы могут быть очень большими, заранее непредсказуемого размера. S>>Это вряд ли. НС>Это факт. S>> Обычно конвертируют в цикле буферами конечной длины. НС>Вопрос только в размере буфера. Одно дело полсотни байт под числеку, и другое дело мегабайты под текст.
Я конечно не знаю, какие у вас там размеры буферов, но в исходниках asp.net mvc при конвертации используется буферы в 1024 или 4096 символа.
Это всего лишь на полпорядка больше полусотни символов и на три порядка меньше упомянутых магабайтов.
НС>>>А вот в случае с TryFormat это не так и смысла переусложнять API нет. S>>Что может быть проще decimal.FormatTo(stringBuilder)?
НС>StringBuilder прибивает гвоздями к конкретной реализации со своими особенностями.
Span тоже прибивает гвоздями.
Теперь классу, вызывающему чужой TryFormat надо знать детали реализации чужого класса, чтобы выделить буфер нужного размера.
Плюс не забыть реализовать фолбэк.
Здравствуйте, Sinclair, Вы писали:
Q>>https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/Text/StringBuilder.cs S>Спасибо, я как-то так и предполагал, но хотел убедиться. То есть предполагается ровно один паттерн: пробуем втиснуться в буфер, какой бы он ни был; если не сработало — фоллбэкаемся на обычный метод с выделением. S>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Это что-то типа TrySort? Если программист допустил ошибку в более сложном алгоритме быстрой сортировки и он падает, тогда запускается алгоритм пузырьковой сортировки, в нем меньше вероятность бага?
Здравствуйте, Sinclair, Вы писали:
Q>>https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/Text/StringBuilder.cs S>Спасибо, я как-то так и предполагал, но хотел убедиться. То есть предполагается ровно один паттерн: пробуем втиснуться в буфер, какой бы он ни был; если не сработало — фоллбэкаемся на обычный метод с выделением. S>Варианта "скорректировать размер буфера" у нас нету, т.к. TryFormat не даёт нам информации о том, сколько места надо.
Здравствуйте, Silver_S, Вы писали:
S_S> Это что-то типа TrySort? Если программист допустил ошибку в более сложном алгоритме быстрой сортировки и он падает, тогда запускается алгоритм пузырьковой сортировки, в нем меньше вероятность бага?
Ну, кстати, подобное делают — сперва запускают квиксорт, и, если он не отработал за некоторое время, прерывают и запускают более стабильный алгоритм, типа мерж сорта.
Здравствуйте, sergeya, Вы писали:
S>Да, хороший аргумент, но на моих (субьективных) весах двойное вычисление перевешивает эти плюсы.
И? Предлагаешь обсудить твои внутренние весы?
S>Кстати, можно было бы сделали бы какой нибудь IStringBuilder, с возможностью выбора аллоцирующей или ротирующей реализации.
Ты в своих проектах тоже никогда не заморачиваешься сложностью полученного на ровном месте решения?
S>Тогда в пессимистичном сценарии будет дополнительное выделение памяти против выделения + перевычисления в исходном варианте.
А заодно двойная косвенность на вызове метода интерфейса вместо прямого вызова невиртуальных методов. Ну и боксинг, если про ValueStringBuilder.
S>Ну да ладно, тут можно придумывать до бесконечности ))
Здравствуйте, sergeya, Вы писали:
НС>>У стрингбилдера свой алгоритм выделения буфера, не только под TryFormat. И никто не мешает этот алгоритм написать так, чтобы промахи на примитивных типах с размером буфера были редкими. S>Голословное утверждение. Я бы поверил, если бы ты привел ссылку на алгоритм или научное исследование.
Не не не. Голословное, это когда ты настаиваешь на том что это обязательно будет проблемой.
НС>>Вопрос только в размере буфера. Одно дело полсотни байт под числеку, и другое дело мегабайты под текст. S>Я конечно не знаю, какие у вас там размеры буферов S>, но в исходниках asp.net mvc при конвертации используется буферы в 1024 или 4096 символа.
И? Я в том же asp.net видел буфера на 1-2М.
НС>>>>А вот в случае с TryFormat это не так и смысла переусложнять API нет. S>>>Что может быть проще decimal.FormatTo(stringBuilder)? НС>>StringBuilder прибивает гвоздями к конкретной реализации со своими особенностями. S>Span тоже прибивает гвоздями.
Нет. Это, фактически, кусок базовой платформы, очень низкоуровневое API, к нему и так все прибито гвоздями, без вариантов.
S>Теперь классу, вызывающему чужой TryFormat надо знать детали реализации чужого класса, чтобы выделить буфер нужного размера.
Зачем? Тебе не детали реализации нужны, а размер результата.
S>Плюс не забыть реализовать фолбэк.
Это нормально для низкоуровнего API. Не хочешь возиться с микрооптимизациями — используй обычный Format.
Здравствуйте, Ночной Смотрящий, Вы писали:
S>>Да, хороший аргумент, но на моих (субьективных) весах двойное вычисление перевешивает эти плюсы.
НС>И? Предлагаешь обсудить твои внутренние весы?
Нет, предлагаю на этом остановиться. Потому что в отличии от тебя, предпочитаю в дискуссии опираться на конкретные факты и ссылки. А здесь у меня нет подкрепленного аргумента, кроме своего опыта, что я и подчеркнул.
Здравствуйте, sergeya, Вы писали:
НС>>А вот в случае с TryFormat это не так и смысла переусложнять API нет. S>Что может быть проще decimal.FormatTo(stringBuilder)?
Унутре decimal форматируется в буфер некоей фиксированной длины as is, т.к. самое длинное представление decimal заранее известно.
Затем берется заданная извне точность и по ней округляется (укорачивается или дополняется 0-ми в дроби) результат.
На выходе — само представление плюс получившееся кол-во символов этого представления.
После этого символы копируются в целевой буфер, но их кол-во уже известно.
Здравствуйте, sergeya, Вы писали:
S>Поэтому похоже что сначала печать выполняется в промежуточный буфер гарантированно достаточного размера, S>и только после этого выполняется попытка скопировать результат в буфер-приемник.
Так и есть.
Единственно, чего не хватает в этом АПИ — это выставить наружу такой промежуточный буфер.
Надеюсь, когда-нить сподобятся...
А сейчас у меня в либах самописные вообще все форматтеры под все числовые типы и большинство представлений даты.
S>А тут уже есть вся информация о том, сколько места не хватило.
В текущем АПИ тут не избежать повторного форматирования, если места не хватило, поэтому всё еще лажа.
S>Код из приведенного тобой исходника:
Походу, еще не GC-free для double.
Если экспонента небольшая, ИМХО, стоит переводить в decimal и форматировать уже его, там GC-free реализация.
Здравствуйте, Ночной Смотрящий, Вы писали:
S>>Но меня смущает не отсутсвие расчитанного размера, а двойная работа — если размера буфера не хватит, придется выполнять форматирование повторно с самого начала. НС>Вот смотри — для базовых типов размер буфера неизвестен заранее для чисел и енумов.
Для числовых данных и дат известен максимальный размер.
И там в любом случае происходит форматирование сначала в промежуточный буфер.
НС>В обоих случаях посчитать размер буфера сопроставимо по затратам с собственно форматированием.
Ес-но.
Т.е. достаточно выставить уже имеющийся унутре буфер наружу, чтобы юзать его как-то так.
internal ref struct NumberBuffer {
public int Scale;
public bool IsNegative;
private byte _b0;
private byte _b1;
...
}
НС>Ключевое отличиче — в случае конвертера объемы могут быть очень большими, заранее непредсказуемого размера. А вот в случае с TryFormat это не так и смысла переусложнять API нет.
Переусложнение АПИ vs переусложнение сценариев. ))
На сейчас сценарий вокруг TryFormat не просто переусложнён, он де-факто на грани невостребованности.
Здравствуйте, vdimas, Вы писали: V>Но к чему тогда относилось твоё "теперь да", если ты там Span инициализировал?
Ну, мне показалось, что поддержку инициализации Span из stackalloc прикрутили в 7.3, а сам Span появился в 7.0.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
V>>Но к чему тогда относилось твоё "теперь да", если ты там Span инициализировал? S>Ну, мне показалось, что поддержку инициализации Span из stackalloc прикрутили в 7.3, а сам Span появился в 7.0.
Я подключился к проекту на .Net Core в актуальность C# версии 7.2, и сразу "подсел" на эту конструкцию и всё вокруг Span.
Здравствуйте, Sinclair, Вы писали:
V>>А где ты видел Span до версии 7.2? S>В основном в блогах. Его же начали прикручивать ещё до поддержки ref struct.
Я тебе более того скажу. Его бэкпортировали в NuGet-пакет System.Memory ещё до того, как сам тип появился в .NET Core 2.1 и языковая поддержка ref struct появилась в C# 7.2 (трёхкомпонентный Slow Span vs. двухкомпонентный Fast Span).
Собственно, его и сейчас приходится оттуда брать, потому что в .NET Standard-то его ещё не завезли. И использовать его можно хоть на C# 2.0 даже под netstandard1.1 или net45.
Здравствуйте, Sinclair, Вы писали:
V>>А где ты видел Span до версии 7.2? S>В основном в блогах. Его же начали прикручивать ещё до поддержки ref struct.
А у тебя вообще такая конструкция компиллируется?
Span<byte> s = new Span<char>(stackalloc char[42], 42);
error CS1525: Invalid expression term 'stackalloc'
А такая?
Span<byte> s;
s = stackalloc byte[42];
error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
Из доки:
The keyword is valid only in local variable initializers.
Например, в тернарных операторах работает чудесно, если результат тернарных операторов инициализирует переменную.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
V>>>А где ты видел Span до версии 7.2? S>>В основном в блогах. Его же начали прикручивать ещё до поддержки ref struct.
V>А у тебя вообще такая конструкция компиллируется? V>
V>Span<byte> s = new Span<char>(stackalloc char[42], 42);
V>
Неа Я от неё ожидал просто возврата char*, авотхрен.
Можно как-то так
V>А такая? V>
V>Span<byte> s;
V>s = stackalloc byte[42];
V>
V>
V>error CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method
error CS8352: Cannot use local 's' in this context because it may expose referenced variables outside of their declaration scope
V>Из доки: V>
V>The keyword is valid only in local variable initializers.
V>Например, в тернарных операторах работает чудесно, если результат тернарных операторов инициализирует переменную.
Я так понял, это by design.
Вот так работает:
unsafe private static Span<char> Test(int number)
{
Span<char> s;
if (number < 100)
{
char* t = stackalloc char[number];
s = new Span<char>(pointer: t, number);
}
else
s = new char[number];
return s;
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Вот так работает: S> char* t = stackalloc char[number]; S> s = new Span<char>(pointer: t, number);
Ес-но, "встроенная защита" обходится одной строкой кода.
С другой стороны, требует явный unsafe, т.е. кое-какой смысл в этом, наверное, есть.
Мол, специально стрелять в ногу запретить не можем, но хоть подстрахуем от случайных самострелов.
Здравствуйте, fmiracle, Вы писали:
F>Здравствуйте, Kolesiki, Вы писали:
K>>Зачем вам сегодня переносимость? Кому, что и куда переносить? ЧТО переносить и чего нет в других платформах?
F>Самый наибанальнейший пример — хостить asp.net сервер под линуксом (дешевле и доступнее хостинг), а разрабатывать под виндами и спокойно его и там и там запускать. F>Весьма удобно, кстати.
Пикус в том, что сам Линукс — пародия на то, чем должна быть ОС. Бегают все с линуксом, будто это панацея какая-то! А на деле — то же решето, причём состав ОС — полный бардак и анархия. Администрировани Линупса — вообще отдельный дзен, постигаемый ГОДАМИ. Мне в пень не упёрлись траханья с "just for fun" системой, я хочу "интыпрайз" и более-менее обкатанную систему + ВСЕ привычные программы, написанные для венды за 20 лет существования. Мне не нужны недописанные, недоотлаженные куски говна, которые кто-то собирает в один дистр и гордо продаёт. Поэтому категорически не понимаю этого "облинупсятивания" ИТ: запомните — "не винда" — это не одно и то же, что "линукс". Можете ненавидеть венду, но ничего ЛУЧШЕ вы(мамкины хэйтеры) всё равно предложить не можете. Даже сами сознаётесь — "а разрабатывать под виндами" — это с чего бы?? Да с того, что и писать, и запускать, надо на одной системе. Бонус такого подхода — что потенциальные грабли ловятся легче в подобных системах, а не винегрете "венда-линупс".
Core — оно как бы пытается решать проблемы "одновендового дотнета", но проблемы — они не в том, что слишком "обвендузятили рантайм", а в самом подходе к переносимости. переносим должен быть ИСХОДНЫЙ КОД. Всё. А то, что вместо этого сгенерили "нигде не исполнимый псевдокод" — это уже провал горе-архитекторов. К тому же, Core вылезает слишком поздно, имея на плечах давящий груз совместимости. Только вот беда — нельзя сделать "хорошо" и "совместимо" одновременно. В этом плане D не побоялся иметь breaking changes — он просто отмёл весь шлак и ввёл фичи без оглядки на старьё. Зато теперь это неплохой, развитый язык, причём имеющий и вендовый, и линуксовый компилятор (прикинь!). Кодеры Core просто взвыли от зависти.