Я не знаю, зачем это нужно в этом конкретном случае. Но, в принципе, такое может быть нужно, чтобы иметь возможность вернуть ссылку на буфер, которая живёт дольше, чем адаптер. Если время унифицировать, то знание о том, что буфер, вообще говоря, может пережить адаптер потеряется.
Это действительно возможно. Но перед этим нужно явно совершить действие с отходом от стандартных практик. Вот тот человек, который явно пропишет var вместо рекмендованного val или вложит внутрь изменяемую коллекцию, предварительно импортировав ее - именно он во время этих действий и должен осознавать данные вещи. А я не знаю, кстати, в хаскеле или расте компилятор умеет такую вложенность проверять?
Ну вот буквально на днях встречал вот такую проблему: Заведём мутабельный case class: case class Counter (var count: Int) {def inc: Unit = {count = count +1; }} После этого неправильно воспользуемся List.fill: val t = Counter(0) val l = List.fill(5)(t) Ну, а после этого попробуем инкрементировать каждый независимо: l.foreach(_.inc) И мы, внезапно, получили в каждом из каунтеров 5 (и это, на самом деле, даже один каунтер).
Раст такое отлавливает - либо нужно явно дуплицировать объекты перед складыванием в массив, либо борроу чекер скажет, что вы пытаетесь взять на редактирование ссылку, которая не уникальна.
Спарк и потоковая обработка. Хотя в batch обработке уже можно уверенно сказать, что по сути победил питон со своим pyspark'ом, но вот в потоковой еще пока нет
У меня есть задача обработки данных батчем, и от скалы (или какого-нибудь другого jvm) особо не уйдёшь в user-defined функциях - у меня получилось отличие примерно на треть общего времени (не времени одного шага, а вот прямо всего - с вычитыванием данных вначале и последующей довольно тяжелой агрегацией и т.п.) в пользу нативной скалы.
Не бесконечно-далёкая система типов есть в Скале. Там есть родовые травмы, связанные с Java (а именно проблема с null'ами, от которой полностью не получается уйти), но типизацию с трейтами она позволяет (и проверяет в compile-time)
Может. Мало того, что иммунитет не стерилизующий, ещё и эффективность вакцины не 100% (с небольшой вероятностью, вакцинированный даже тяжело переболеть может).
Только в случае ветрохода, с точки зрения неподвижного наблюдателя, получается другая история: винт замедляет ветер, а отобранную энергию передаёт на колёса.
Посмотрите на версию без дополнительной аллокации: там kind является объединением ioErrorKind и IntErrorKind . И динамически ничего не резолвится (и ошибка AppError{"asd", "asd"} уже не возникает).
Ну и, поздравляю, вы сделали тот самый dyn. А если там будет не только строка - там будет ещё и box. А ну и ещё поглумились над двумя базовыми раст-методичками. Это "тайпсейфити при result" и "неявные преобразования типов - зло".
Преобразование типа явное - см. описание оператора ? "? is used at the end of an expression returning a Result, and is equivalent to a match expression, where the Err(err) branch expands to an early Err(From::from(err)), and the Ok(ok) branch expands to an ok expression"
В языке с исключениями я просто пишу throw. Без всего этого страха.
А потом ловите не то исключение, которое ожидали.
Кстати, расскажу интересную историю. Буквально недавно я практически один отстаивал тезис ~"обрабатывать null их malloc не имеет смысла". И очень много популярный раст-адептов со мною спорили, доказывали мне обратное.
Обрабатывать null в malloc имеет смысл, чтобы сразу упасть и не перепелить случайно память от момента получения этого null до падения (и не закрывать ресурсы с распиленной памятью). Или вы обсуждали что-то другое?
Никак. Весь раст существует на фейковом БЧ. Если бы они могли хоть каким-то образом сделать хоть какой-нибудь шаринг - они бы его сделали.
RO шаринг в расте есть и хорошо работает. RW тоже есть, но там появляется оверхед в рантайме.
Как мне получить этот баг на уровне языка. Показывайте пример.
В тикете есть пример. Берёте внешнюю библиотеку (тоже написанную на безопасном питоне) и получаете неправильный результат работы, если собирать на конкретную архитектуру.
А может не давать. Показывайте, где в стандарте описана связь УБ с какой-то оптимизацией.
Вы ищете пример кода, который с O2 и с O0 даёт разные результаты на большинстве современных компиляторов?
Полнейшая чушь нелепая. Кстати, а почему адепт данной чуши не является программистом на rust10.2.0? Ведь для его кода так же ничто не гарантирует тот же результат на следующей версии?
Так же как с с++ какой-то редакциии есть гарантия, что если код корректен (и не попал на какую-то ошибку компилятора), то смена версии компилятора он продолжит компилироваться в программу, дающий тот же результат. Гарантии, что он скомпилируется в ту же самую программу - нету.
Кстати, открою тайну - никто в мире С++ не пишет под стандарт - все пишут под компилятор
Видимо, мы наблюдаем разные миры. В С++ рядом со мной пишут как раз под 11 стандарт. И подготовка тестовой сборки на clang (для тестов производительности, боевая у нас на gcc) заняла пару дней (для того, чтобы поменять скрипты сборки). После этого сборка прошла все тесты.
Я бы в этом месте ожидал разделение библиотек. Если есть высокоуровневая бизнес-логика, то, вроде бы, catch почти никогда не нужен (с практической точки зрения) - если у тебя нет памяти и try_push вернулся с ошибкой из-за нехватки памяти, то у тебя очень ограниченное пространство вариантов (по большому счёту, ровно упасть). А вот если ты что-то делаешь на более низком уровне - Result оказывается хорошим вариантом, я бы ожидал, что там станет больше функций вида try_something.
Мимо - это не баг питона. Это баг в какой-то либе. К языку не имеет никакого отншения.
Прочитали бы внимательно. Это баг в PyModule_AddIntConstant(), которая часть ядра питона.
Ога, любой баг не критичный. Особенно в том, о чём на каждом шагу орём "гарантирует".
Там ещё 70 таких багов. Их постепенно закрывают. Учитывая, что вот этот похожий пометили high, есть довольно хорошие шансы, что наконец пофиксят (оба сразу).
Undefined никаким образом не связан с оптимизациями и прочей чушью. Undefined это полностью неспецифицированное поведение.
Ага, и поэтому программа с UB может давать разный результат, если скомпилированна с -O0 и -O3? И ключ с -fno-strict-aliasing (с которым нужно собирать ядро линукса) выключен по-умолчанию для причин не связанных с оптимизациями компилятора?
Во-первых, выше доказано, что поведение раста может зависеть зависеть от версии компилятора
Может. Например, часть некорректного кода компилируется старым компилятором, но не компилируется новым (потому что пофиксили ошибку, которая разрешала некорректный код, с трейтом fake-static случится именно это). Часть корректного кода компилируется новым компилятором, но не компилируется новым (потому что какие-то проверки в safe делают менее жёсткими). Отдельно, код, содержащий некорректный unsafe, может тоже собираться по-разному, даже минорными версиями (как и код содержащий некорректный с++).
Во-вторых С++ не обязательно должен быть стандартным. Поэтому все эти истории "C++ может предполагать, что Вы (как программист) гарантировали" так же являются чушью, в том числе и по этой причине.
Поэтому, как С++-программист я могу ссать на стандарт. И ссал. Потому что мир С++ не ограничивается стандартом. А если ограничивается, то никакого раста не существует.
И это действие превращает Вас из C++ программиста в программиста на gcc10.2.0 , гарантий, что код написанный вами, скомпилированный 10.2.1 даст тот же результат уже никто не даёт.
Если же мы говорим об реализации и её поведения, то это поведение определяется реализацией, очевидно. И никакого УБ в ней существовать не может. Всё зависит от того, что мы используем в качестве источника истины. Поэтому я без проблем могу выкинуть стандарт, а значит УБ для меня перестали существовать.
Выкидывание стандарта привязывает вас к минорной версии (см. выше или ниже).
Во-первых срочно стоит обновить методичку - в С++ знаковое переполнение не является УБ.
Про оптимизации и прочую чушь я писал выше. Ни к каким оптимизациями УБ отношения не имеет.
Ответил тоже выше - имеет отношение к оптимизациям кода, которые делает компилятор.
С чего вдруг минорной? Чем это обусловлено?
Изменение поведения кода, содержащего UB не является ломающим изменением.
Так сравнивать нужно не "зарегистрированные смерти от ковида на 100 000 человек", а "избыточную смертность на 100 000 человек". Как минимум по прошлому году статистика сильно не в пользу России.
А почему не починен этот пятилетний баг питона? Потому что про баг решили, что он не критичный (в том смысле, что проявляется довольно редко и случайно его вызвать довольно сложно).
уб - это не фича. Уб это просто отсутствие спецификации на поведение. Оно может быть обусловлено чем угодно, в том числе и багом.
Нет. В стандарте C++ разделены unspecified и undefined behavior. Undefined behavior - это именно о том, что компилятор в рамках оптимизации Вашей программы на C++ может предполагать, что Вы (как программист) гарантировали, что оно не случится.
Если говорить о рассуждениях выше про "использовать уб", что нам запрещает использовать одни баги для реализации логики базирующейся на баге?
То, что поведение программы начинает зависеть от фазы луны минорной версии компилятора и уровня оптимизации при сборке? Не говоря о том, что перестановка каких-нибудь гарантированно не-зависимых вызовов может приводить к изменению поведения?
Ещё раз, если проще. Без проблем можно сказать, что "поведение при знаковом переполненении просто забыли специфицировать и влепили УБ". Всё будет точно так же работать.
Ну нет же. Сегодня компилятор C++ имеет полное право заменить for(int i = 0; i > 0; i++) на while(true) с целью оптимизации (если, конечно, i не используется в теле цикла). А пользуется он этим правом или не пользуется - это его решение (и для сохранения поведения нужно привязываться к gcc/clang одной конкретной минорной версии)
Я не знаю, зачем это нужно в этом конкретном случае.
Но, в принципе, такое может быть нужно, чтобы иметь возможность вернуть ссылку на буфер, которая живёт дольше, чем адаптер. Если время унифицировать, то знание о том, что буфер, вообще говоря, может пережить адаптер потеряется.
Да 'socket должно быть больше, чем оба времени, и 'buf, и 'adapter .
В принципе, может быть строго больше, чем они оба.
Вы биномиальный множитель забыли.
Плотность выглядит примерно вот так
(я использовал https://keisan.casio.com/exec/system/1180573198 чтобы нарисовать эту картинку).
Т.е. вероятность получить ровно 6 - это целые 15%, а 6 или более - почти 40%, даже 10 и более - почти 3%.
Ну вот буквально на днях встречал вот такую проблему:
Заведём мутабельный case class: case class Counter (var count: Int) {def inc: Unit = {count = count +1; }}
После этого неправильно воспользуемся List.fill:
val t = Counter(0)
val l = List.fill(5)(t)
Ну, а после этого попробуем инкрементировать каждый независимо:
l.foreach(_.inc)
И мы, внезапно, получили в каждом из каунтеров 5 (и это, на самом деле, даже один каунтер).
Раст такое отлавливает - либо нужно явно дуплицировать объекты перед складыванием в массив, либо борроу чекер скажет, что вы пытаетесь взять на редактирование ссылку, которая не уникальна.
У меня есть задача обработки данных батчем, и от скалы (или какого-нибудь другого jvm) особо не уйдёшь в user-defined функциях - у меня получилось отличие примерно на треть общего времени (не времени одного шага, а вот прямо всего - с вычитыванием данных вначале и последующей довольно тяжелой агрегацией и т.п.) в пользу нативной скалы.
Не бесконечно-далёкая система типов есть в Скале.
Там есть родовые травмы, связанные с Java (а именно проблема с null'ами, от которой полностью не получается уйти), но типизацию с трейтами она позволяет (и проверяет в compile-time)
Некоторый аналог (достаточно близкий) - это ?-нотация.
Она требует явного приведения типа в конце к результату, но, с другой стороны, умеет правые части приводить к одному типу.
Может.
Мало того, что иммунитет не стерилизующий, ещё и эффективность вакцины не 100% (с небольшой вероятностью, вакцинированный даже тяжело переболеть может).
Только в случае ветрохода, с точки зрения неподвижного наблюдателя, получается другая история: винт замедляет ветер, а отобранную энергию передаёт на колёса.
Ещё сопоставляются все буквы. Например, регулярке a* строка aaa удовлетворяет, а строка bbb (той же длинны) - нет.
Есть хороший разбор не по Британской, а по Израильской статистике. Думаю, что в Британии ситуация близкая: https://www.covid-datascience.com/post/israeli-data-how-can-efficacy-vs-severe-disease-be-strong-when-60-of-hospitalized-are-vaccinated "сырая" эффективность получается 66%, а в каждой возрастной группе больше 80% (и почти во всех выше 85%).
Называется парадокс Симпсона.
Посмотрите на версию без дополнительной аллокации: там kind является объединением ioErrorKind и IntErrorKind . И динамически ничего не резолвится (и ошибка AppError{"asd", "asd"} уже не возникает).
Пожалуйста: https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=5d2ff84acad55af5c852bda8b5761018
Да, там arc, но это safe-костыль (альтернативно можно сделать этот mutex глобальным).
Нету там dyn. Вот вариант без дополнительной аллокации (конкретно в этом случае есть строка от io::Error): https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=149154ed96e5e151ab48c3e52c200640
Преобразование типа явное - см. описание оператора ? "
?
is used at the end of an expression returning aResult
, and is equivalent to a match expression, where theErr(err)
branch expands to an earlyErr(From::from(err))
, and theOk(ok)
branch expands to anok
expression"А потом ловите не то исключение, которое ожидали.
Обрабатывать null в malloc имеет смысл, чтобы сразу упасть и не перепелить случайно память от момента получения этого null до падения (и не закрывать ресурсы с распиленной памятью). Или вы обсуждали что-то другое?
RO шаринг в расте есть и хорошо работает. RW тоже есть, но там появляется оверхед в рантайме.
В тикете есть пример. Берёте внешнюю библиотеку (тоже написанную на безопасном питоне) и получаете неправильный результат работы, если собирать на конкретную архитектуру.
Вы ищете пример кода, который с O2 и с O0 даёт разные результаты на большинстве современных компиляторов?
Так же как с с++ какой-то редакциии есть гарантия, что если код корректен (и не попал на какую-то ошибку компилятора), то смена версии компилятора он продолжит компилироваться в программу, дающий тот же результат. Гарантии, что он скомпилируется в ту же самую программу - нету.
Видимо, мы наблюдаем разные миры. В С++ рядом со мной пишут как раз под 11 стандарт. И подготовка тестовой сборки на clang (для тестов производительности, боевая у нас на gcc) заняла пару дней (для того, чтобы поменять скрипты сборки). После этого сборка прошла все тесты.
Я бы в этом месте ожидал разделение библиотек. Если есть высокоуровневая бизнес-логика, то, вроде бы, catch почти никогда не нужен (с практической точки зрения) - если у тебя нет памяти и try_push вернулся с ошибкой из-за нехватки памяти, то у тебя очень ограниченное пространство вариантов (по большому счёту, ровно упасть). А вот если ты что-то делаешь на более низком уровне - Result оказывается хорошим вариантом, я бы ожидал, что там станет больше функций вида try_something.
Прочитали бы внимательно. Это баг в PyModule_AddIntConstant(), которая часть ядра питона.
Там ещё 70 таких багов. Их постепенно закрывают. Учитывая, что вот этот похожий пометили high, есть довольно хорошие шансы, что наконец пофиксят (оба сразу).
Ага, и поэтому программа с UB может давать разный результат, если скомпилированна с -O0 и -O3? И ключ с -fno-strict-aliasing (с которым нужно собирать ядро линукса) выключен по-умолчанию для причин не связанных с оптимизациями компилятора?
Может. Например, часть некорректного кода компилируется старым компилятором, но не компилируется новым (потому что пофиксили ошибку, которая разрешала некорректный код, с трейтом fake-static случится именно это). Часть корректного кода компилируется новым компилятором, но не компилируется новым (потому что какие-то проверки в safe делают менее жёсткими). Отдельно, код, содержащий некорректный unsafe, может тоже собираться по-разному, даже минорными версиями (как и код содержащий некорректный с++).
И это действие превращает Вас из C++ программиста в программиста на gcc10.2.0 , гарантий, что код написанный вами, скомпилированный 10.2.1 даст тот же результат уже никто не даёт.
Выкидывание стандарта привязывает вас к минорной версии (см. выше или ниже).
Ответил тоже выше - имеет отношение к оптимизациям кода, которые делает компилятор.
Изменение поведения кода, содержащего UB не является ломающим изменением.
Так сравнивать нужно не "зарегистрированные смерти от ковида на 100 000 человек", а "избыточную смертность на 100 000 человек". Как минимум по прошлому году статистика сильно не в пользу России.
А почему не починен этот пятилетний баг питона? Потому что про баг решили, что он не критичный (в том смысле, что проявляется довольно редко и случайно его вызвать довольно сложно).
Нет. В стандарте C++ разделены unspecified и undefined behavior.
Undefined behavior - это именно о том, что компилятор в рамках оптимизации Вашей программы на C++ может предполагать, что Вы (как программист) гарантировали, что оно не случится.
То, что поведение программы начинает зависеть от
фазы луныминорной версии компилятора и уровня оптимизации при сборке? Не говоря о том, что перестановка каких-нибудь гарантированно не-зависимых вызовов может приводить к изменению поведения?Ну нет же. Сегодня компилятор C++ имеет полное право заменить for(int i = 0; i > 0; i++) на while(true) с целью оптимизации (если, конечно, i не используется в теле цикла). А пользуется он этим правом или не пользуется - это его решение (и для сохранения поведения нужно привязываться к gcc/clang одной конкретной минорной версии)
Периодически оказывается -1 новый комментарий в колокольчике:
mark all as read помогает на некоторое время, но это уже третий раз так.