Pull to refresh
40
0
Павлов Николай Александрович @ZyXI

Инженер

Send message

Ленивого исполнения аргументов в Python как‐то не завезли. Вы в этом варианте всегда вызываете func(args).

None тоже можно поместить в словарь… Если писать код не в одну строку, то всегда лучше обрабатывать KeyError.

С чего вы взяли? Транзисторы в компбинационной логике ничем не отличаются от транзисторов в памяти и точно так же могут быть уязвимы к попаданиям.

Транзисторы — да. Но событие при этом будет называться не одиночным сбоем (SEU). Кроме того, именно в процессорах, чтобы попадание в комбинационную логику привело к какой‐то проблеме, нужно попасть именно в тот момент, когда неверный выход будет защёлкнут.


А вы большой оптимист. Попробуйте например быстро обойти всю конфигурационную память в FPGA.

Во‐первых, я сказал «обычно». Во‐вторых, пример некорректен. Для диагностирования вам не нужно обходить память «быстро», вам нужно просто иметь возможность её обходить. Здесь лучше вспомнить, что не все процессоры позволяют напрямую взаимодействовать с кешами. (Возможно, правда, «обычно» не корректно: обычно нам на испытания на радиационную стойкость приходят схемы, где память посмотреть можно. Но нам приходят не все схемы.)




И ещё: судя по статье, CEE воспроизводятся, вам нужно только запустить определённую последовательность инструкций на определённом ядре при определённых условиях, несколько раз, потому что «определённые условия» нельзя легко воспроизвести с нужной точностью. SEU себя так не ведут, если только вы не посылаете специально заряженную частицу в определённое место.

Одиночные сбои — это относится к памяти и только к ней, и вызываются прилетающими из космоса заряженными частицами. Проблему можно относительно легко воспроизвести — частицы могут прилетать и из ускорителя, есть и другие методы. Проблему легко диагностировать: просто сравните то, что вы записали в память с тем, что там должно быть. Обойти всю память обычно не проблема. Есть и адекватные теории, что именно происходит, когда прилетает частица, и методы подавления (которые не ограничиваются контролем ошибок, просто так обычно дешевле сделать).


CEE — это пока что‐то, что происходит непонятно почему, непонятно где конкретно, и непонятно как диагностировать кроме как запускам одной и той же программы на двух разных процессорах и сравнением результатов. Что покажет наличие CEE в тех частях процессора, которые были задействованы, но не отсутствие.

У меня к программисткому двораку добавлены три удобных переназначения: LCtrl вместо caps (пользователи Vim туда часто ставят Esc, но Esc не так полезен, особенно вне Vim), Esc вместо LCtrl, Caps Lock вместо Esc. Правда последнее я не знаю, зачем мне нужно: обычно если я нажал Caps я просто молча ругаюсь и нажимаю его ещё раз.

Вот почему "всё ещё лучше исключений", непонятно.

Потому что не нужно держать в голове то, что функция может завершиться на любой строчке.


Я уже в вашем ответе перестал понимать — вы согласны с этим (что исключение в общем случае лучше UB) или нет?

Исключение действительно лучше.



Что из этого списка у вас конкретно вызывает возражения, почему и какие?

Из этого списка возражения не вызывает ничего, кроме того, что у Rust механизм для 3 — это Result, а не паника (если вы, конечно, хотите переключаться на обработку).


Соответственно в Rust и не используют для ошибок арифметики тот же подход, что и для ошибок открытия файлов.


Вы за то, чтобы паника была, но перехватывать её было нельзя? Тогда — почему?

Потому что в большистве случаев это баг в программе, а не ожидаемая ситуация (или «обязательная часть нормальной работы» как вы написали ниже). Если есть баг, то программа находится в неопределённом состоянии и ей лучше упасть.


В меньшинстве случаев есть checked_….


И как тогда учиться тому, что ошибки надо тоже уметь обрабатывать?

Учиться обрабатывать ошибки на других функциях? Если хочется обязательно на ошибках в арифметике — checked_….


И как учиться тому, что ошибка может быть обязательной частью нормальной работы? Например, множество программ ищут свои конфиги в порядке: ./foo.conf, ~/.config/foo.conf, ~/.foo.conf, /etc/foo.conf, и отсутствие части из них это норма для 100% случаев — что, нельзя такое вообще ловить? Где предел вашей позиции по запрету ловить ошибки?

Это другой домен. Я не вижу причин, почему ошибки в арифметике должны работать так же, как и ошибки в IO. Причин делать обработку по‐разному же полно:


  • производительность;
  • удобство — при АТД вам будет нужно делать .unwrap() или другую обработку на каждое арифметическое выражение, у исключений тут правда преимущество: вам не нужно будет делать больше телодвижений, учитывая, что вам уже нужно везде применять RAII или аналог просто по факту существования исключений;
  • разные причины их возникновения — файл может пропасть, потому что пользователь решил почистить /etc, отправил его в NFS и отвалился сервер, …, в общем если это не опечатка в названии файла, то это не баг в программе, а переполнение — это обычно либо баг в программе, либо некорректный ввод (что тоже часто баг вида «недостаточно проверили ввод»).
То есть вы за принуждение к обработке ошибок на месте, я правильно понял?

Пока к принуждению прикладывают синтаксический сахар вроде ? — да. Если не прикладывают, то я считаю, что это всё ещё лучше исключений, но работать уже не удобно.


Я вообще-то говорил немного о другом. Тот же случай открытия каталога на запись в обычном Unix* libc вернёт -1, и дальше уже обязанность программиста проверить (может, сгенерировать исключение, если хочет), но по крайней мере не пустит сделать диверсию.

А обязанность языка — сделать так, чтобы программист не смог забыть проверить.


С тем, что ошибки случаются вроде никто не спорил. Ранее спорили с тем, что считать ошибкой конкретно при перемножении целых. А тот ваш комментарий, на который ранее в этой ветке ответил я, был ответом на комментарий с содержанием примерно «при исключениях непонятно, что происходит» без продолжения спора о том, что считать ошибкой при использовании целых. Логично, что ответ вида «ошибки случаются, нужно ли при возникновении ошибки воспринимать её как UB» на комментарий «исключения непонятны» воспринимается как «ошибки случаются[, значит, нужно выбросить исключение, потому что UB это плохо]».


Если вы намекаете на то, что практики из домена взаимодействия с внешним миром нужно применить к домену математических вычислений, то об этом хорошо бы написать явно. Я лично с идеей не согласен: от перехватываемой ошибки тут толку намного меньше, выбрасывание паники с понятным сообщением вполне подойдёт для обучения (и можно даже не упоминать про возможность её перехвата — ни наличие такой возможности, ни проход по стеку с вызовом Drop::drop всё равно не гарантируются).


(А в реальных программах мне кажется лучше иметь, на выбор, возможность использования * как panicing_mul/checked_mul/wrapping_mul/…, или способ доказать компилятору, что здесь переполнения не может произойти — с ошибкой компиляции, если доказательство некорректно. У Rust пока есть только первый вариант в не слишком удобном виде (но, возможно, кто‐то сделал более удобный макрос).)

Во‐первых, warn_unused_result в стандарте нет. И в заголовочных файлах libc я его что‐то тоже не особо вижу. Не знаю, как в других libc, но ag -i unused $(qlist glibc | grep include) нашёл мне кучу комментариев, несколько идентификаторов, определение атрибута и целых две функции, которые им всё же аннотировали.


Во‐вторых, если функция в случае ошибки возвращает NULL, а без неё — указатель на что‐то, то warn_unused_result ни разу не поможет: вы же результат используете! А то, что fwrite не может записать строку в NULL, полученный от провалившегося fopen компилятор не знает. (Вообще, есть атрибут nonnull, но он вроде не заставит вас доказать компилятору, что вы не передаёте NULL в функцию, он просто не даст его молча передать в явном виде.) Ошибки, возвращаемые в виде специальных значений используемого типа ещё хуже: под них даже атрибутов нет.

Не "рука помощи от бога", а опознание ошибок и репорт их. Вот, например, вы открываете файл по некоторому пути на запись, а он оказался каталогом. Все ОС скажут "иди нафиг". А надо было заранее проверить, а иначе ОС накидает туда кучу мусора, так? Или чтобы писалось в пустоту?

Надо, чтобы вы не могли использовать открытый файл при наличии ошибки. Этого добиваются и исключения, и алгебраические типы данных вида Result<File, IOError>, но из этих двух альтернатив только одна показывает, что ошибка может возникнуть именно здесь и заставит обработать её программиста, а не компилятор.


Для объяснения для того, кто только учится программировать, достаточно, что управление безвозвратно (вот это я в 96-м или около того, когда читал про исключения, понял ой не сразу) передаётся в ближайший адекватный catch (местами except).

Только оно передаётся не туда, точнее, не сразу. В C++ есть деструкторы. В Python есть finally и __exit__ (который, кстати, ещё может отменить исключение, так что до «ближайшего адекватного except» дело не дойдёт). Объяснить RAII или использование with придётся, если вы хотите, чтобы программы могли адекватно обрабатывать исключения, а не просто падали с другим сообщением об ошибке.

А в чём смысл запускать [ --… ] (с закрывающей скобкой) и test --…? В статье же написано, что второе работать и не должно (точнее, должно, но только как проверка пустоты строки), а второе может показывать help/version только потому что без закрывающей скобки команда некорректна.

В моей Gentoo округлённые до КиБ размеры совпадают с вашими. Должно быть связано либо с версией coreutils (у меня — 8.32), либо с разрядностью системы (64).

Если вы не испарите часть корпуса самолёта одним коротким импульсом, то тепло просто рассеется сначала по корпусу, потом в атмосфере. Мелкий космический мусор же можно сравнительно медленно нагреть до испарения — скидывать тепло он может лишь медленно излучением и побыстрее — испаряя вещество с поверхности, что собственно и нужно. Я не думаю, что для такой цели будут использовать мощные импульсные лазеры, если можно обойтись чем‐то попроще. С птицами примерно то же самое, только с охлаждением у них похуже.


Операторы лазера, правда, могут попытаться попасть в глаза птице, пилоту или пассажирам (птице легче — их не защищает стекло, тем самым требуя использовать оптические системы наведения, и меньше вероятность, что между лазером и глазом будет корпус). Их даже испарять не потребуется.

Версию не помню, но это KiCAD-5* не более, чем двухмесячной давности. Но проверять лучше на последней ночной сборке, может там всё же сделали сортировку перед сохранением, тем более что это некритично, а 5* должны заменить на 6*, надеюсь, скоро.

И результат будет отдельным файлом, при этом решающим только задачу «получить список файлов в архиве без распаковки». Смещения начала файлов в нём не указаны, так что достать один файл он вам не поможет, даже если вы используете несжатый архив. Во всяком случае, именно так выглядит результат создания index‐файла с помощью --index-file.


Вообще некоторой доработкой формата можно было бы добиться нужного эффекта: просто научите tar дописывать этот index‐файл в конец архива (для совместимости: не в виде файла, а просто в виде некорректных данных после конца архива) и передавать xz параметр --block-list с такими значениями, чтобы один файл соответствовал одному блоку. Но это мало кому нужно, и вызывает необходимость что‐то делать с разными особыми случаями вроде «что делать, если файл обрезали после того, как tar передал --block-list но до того, как он начал запаковывать файл» (вопрос, в принципе, решаемый, если вы засунете xz внутрь tar или сделаете так, чтобы xz принимал на вход поток команд, а не просто поток данных).

А в PCB вы добавили на плату что‐то — KiCAD вам всё остальное, что вы не трогали, сохранил в другом порядке. Иногда даже работает, когда вы ничего не изменили, но перезаполнили все полигоны (т.е. запустили DRC с соответствующей галочкой).


Не удивлюсь, если в шестой версии он также будет всё переупорядочивать в schematic: там теперь более читаемые s-expr вместо того, что вы написали выше.

Символическая ссылка — это технически обычный файл, содержащий путь к тому файлу, на который он ссылается и имеющий атрибут, указывающий, что это символическая ссылка. Чтобы сохранять их вам нужно просто иметь возможность считывать и сохранять этот атрибут и читать содержимое файла‐ссылки вместо содержимого того файла, куда она указывает. Замечу, что вас при этом вообще никак не интересует, куда указывает символическая ссылка.


Сохранения информации вида «этот файл имеет тот же inode, что и файл X за пределами архива» (т.е. сохранения «жёстких ссылок») от архиватора не ожидают и, наоборот, все сильно расстроятся, если архиватор будет это делать (поскольку это либо уязвимость, либо бесполезная информация, либо повреждение распакованного файла). Сохранять информацию вида «это тот же файл, что и файл Y в архиве» можно, распаковывать потом с использованием жёстких ссылок — тоже, но обычно никто не заморачивается, поскольку жёсткие ссылки используются сильно реже.

А ещё присваивание там не statement, просто оно возвращает (), а не присвоенное значение. Playground

Для динамически типизированных языков расширение типа не представляет только технической проблемы. Вам всё ещё нужно понять, как это отразится на реальных программах: будет ли при этом легче/сложнее программисту допустить ошибку, будет ли легче/сложнее понимать программу, …


Расширение типа на usize | T вместо чего‐то вроде бросания исключения или завершения программы означает, что если программист ошибочно пропустил 0 в индекс, то ошибка обнаружится не в месте возникновения, а там, где вы попытаетесь использовать usize как T и не сможете. Более того, большинство новичков будут с непривычки читать array[0] как получение первого элемента. Хуже пожалуй только LabVIEW’шная выдача значения по‐умолчанию при выходе за границы: тут, скорее всего, при ошибке программа просто станет работать в режиме «мусор на входе — мусор на выходе», а вы будете долго думать, откуда на входе появился мусор.

Это плюс одно сравнение, если n не константа, и, что намного важнее, тип выражения a[0] для массива [T] внезапно становится usize | T вместо просто T. Это абсолютно никому не нужно, даже выдавать «значение по‐умолчанию» как делает LabVIEW со всеми выходами за границы массива и то лучше.


Поправьте меня если я неправ, но зная про Pascal и его строки только разные слухи я могу предположить, что


  1. Это относится только к строкам.
  2. Если в Pascal есть тип строки, позволяющий строки длиннее 255 байт, то у этого типа длину строки таким образом получить не получится.

CMake — это ещё ничего. Я вот для своих проектов по привычке использую пути, безопасные (не требующие экранирования) для bash, а коллеги используют пути вида D:\Испытания 2020\…. Обычно всё работает, но иногда вылезает что‐то вроде «openssh не может открыть указанный ему в командной строке конфиг» или «LabVIEW внезапно решил начать падать при открытии именно этого моего проекта именно из этого пути». Не буду говорить про LabVIEW, но OpenSSH — тоже весьма значимый проект. И, в отличие от CMake, теперь поставляется вместе с Windows.

Information

Rating
5,723-rd
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity