Pull to refresh

Comments 65

Исправьте перевод: «фунт-сила-секунда», а не «фунт-сила в секунду»; «ньютон-секунда», а не «ньютон в секунду». В этих единицах измерения используется умножение, а не деление (ср. оригинал, где нет слова per).

По существу рассматриваемого случая: удивительно, насколько автор сосредоточен на громоздких программных костылях, однако ни слова не говорит о радикальном, очевидном и давно известном решении — повсеместном переходе на систему единиц СИ.
удивительно, насколько автор сосредоточен на громоздких программных костылях, однако ни слова не говорит о радикальном, очевидном и давно известном решении — повсеместном переходе на систему единиц СИ
Удивительно, насколько по-разному люди понимают мысль, которую пытался донести автор.
Хотя более наглядный пример предлагаемой концепции типизации можно увидеть в std::chrono в выбранном там подходе работы с разными единицами времени (все в системе СИ, что характерно).
Да не получится навязать СИ директивно.
В штатах как были мили, там и останутся ещё 200 лет.
Как и дюймы в диаметрах водопроводных труб 1/2 3/4 5/16 7/32.
Про строгость типизации — не спорю, поэтому мы тут однозначно перешли на TypeScript.
Насколько это помогло — пока сказать не могу.
Но направление правильно, особенно в отношении слаботипизованных языков, типа JS, Python, PHP.

Питон считается сильнотипизированным языком. Можете привести примеры слабости его системы типов?

UFO just landed and posted this here
Утиная типизация объектов, возможность передать объект, еще не имеющий нужного интерфейса (или просто другой объект) в метод, рассчитывающий на этот интерфейс. Иногда — в рантайме.

Это вы описали признаки динамической типизации. С сильной/слабой типизацией это никак не связано.

Я описывал примеры слабости системы типов питона. Речи о формальном определении ее строгости/слабости не шло.
Но вообще Я не уверен в том, что утиная типизация все же относится к сильной проверке типов. Ошибки с динамической типизацией в этом смысле очень похожи на ошибки некорректных данных, характерные для слабой типизации.
Замечу, что Питон — как раз таки сильно, но динамически-типизированный. Статически и сильно — например Pascal/Delphi. Вообще постепенный мировой поворот лицом к типам мне нравится.
Однако СИ навязали директивно во всём мире, кроме США и Мьянмы (странное соседство). Даже Англия ушла от футов и фунтов. А Австралия так намучилась с имперскими единицами, что теперь вообще ни в чём не отступает от СИ: мощность автомобилей у них в киловаттах, калорийность в килоджоулях, атмосферное давление в гектопаскалях.
Даже Англия ушла от футов и фунтов.

Ну, пока не очень далеко ушла. На знаках и табличках расстояния в футах частенько встречаются.

Тогда предлагаю признать, что пример с Mars Climate Orbiter действительно крайне неудачный — хотя бы потому, что полностью вымышленный и притянутый за уши. Как следует из отчёта об аварии, две части ПО, между которыми возник конфликт единиц измерения, работали совершенно независимо на разных машинах и обменивались данными через файл. Так что костыли, предложенные автором, здесь неуместны.

Может пример не совсем удачный. Представьте что у вас два поля — имя и фамилия. И оба — терминированные строки до 32 символов. С точки зрения компилятора имя можно присвоить фамилии и наоборот. С точки зрения семантики это будет ошибкой. Тесты и статический анализ такие вещи могут легко пропустить. Собственно идея которую пытались донести авторы — здорово когда система типов используемая в вашей программе отражает семантику. Тогда подобные ошибки можно отлавливать на этапе компиляции. Ну и еще делать кучу других классных штук, которые без семантической типизации либо делать трудно и дорого, либо вообще никак.


Лютое костыление — это из-за ограничений языка выбранного для примеров. В данном случае, по-моему, оправдано. Будь примеры на Скале или Хаскеле — началось бы "опять ваши монады-алгебры, ты на С попробуй!".

А также повсеместном переходе на единый формат указания путей файлов, все что есть в настройках региональных стандартов ОС тоже нужно унифицировать (как мы знаем из-за десятичных разделителей тоже аппараты бьются), всех обязать иметь имена в формате ФИО, а то выдумали двойную фамилию или без отчества, почтовые адреса обязательно с десятизначным индексом, чтобы на всех хватило, и т.д.
UFO just landed and posted this here

Да и вообще айдишники разных сущностей неплохо было бы обозначить разными типами.

Вот это самое сложное "продать" команде. На один VO Id ещ' можно как-то...

Спасаемся типизацией от чтения документации

UFO just landed and posted this here

Не везет людям, которые от своих коллег защищаются

Мне кажется, что при проектировании кода нужно регулярно думать даже о защите от самого себя в будущем, что уж говорить о коллегах.
Дело не в доверии к коллегам, все ошибаются, входящие данные врут, нужно пытаться обеспечивать отказоустойчивость на всех возможных уровнях, насколько это возможно.
документация — это слабость. если полезли в документацию, значит что-то сделано плохо или не очевидно. сильно лучше, когда самой возможности ошибки не будет в принципе.
Приведенный в статье косяк, был очень давно, вроде бы был написан на фортране. Там не было обыденных для нас классов, структур, опшионалы вообще только только стали появляться. Доки были единственным выходом
UFO just landed and posted this here
Моё любимое, задержки в разных платформах/фреймворках:
delay(1000);
sleep(1);
Sleep(1000);

Сколько граблей было поломано об лбы разработчиков по всему миру, страшно представить. Просто они плохо читали документацию и были иногда невнимательны, а значит сами виноваты, очевидно же.
У нас в практике был прекрасный случай, когда одинаковый метод отложенного запуска, переопределенный, принимал в int — миллисекунды, а во float — секунды.
WaitUntil(1) и WaitUntil(1f) имели разное в 1000 раз поведение.
UFO just landed and posted this here

в Haskell, Rust и некоторых других языках есть конструкт newtype специально для таких ситуаций, чтоб не складывали попугаев с удавами

В С++ для этого вроде как можно использовать пользовательские литералы.

как можно говорить про безопасность программы, в которой UB — это нормально и не вызывает возражений компилятора?

Прикрутить статанализ, который UB не пропустит?

Это невозможно. Было бы возможно — давно бы в язык вошло.

Вот честно, не понимаю что в этом невозможного, если о нём известно. По опыту обычно UB не стандартизируют, когда очень много софта завязано на разные варианты UB. Грубо, если определим одно поведение, то сломается половина софта, а если другое, то вторая половина.

Ну вот вам пример UB: знаковое переполнение.


Как вы определите его стат. анализом?

Отсутствием проверки на переполнение там, где статанализом мы не можем гарантированно сказать, что его нет. Грубо, в случае int a = 1 + 1, мы можем сказать, что переполнения не будет (ведь нет платформ, где int — 1 бит? )

Как вы собрались выключать и без того выключенную проверку?

Я имею в виду явную проверку в коде. Типа тайпгварда.

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


Эдак можно сразу на каждую строчку ругаться...

Если нам важна безопасность, то почему не ругаться на каждую небезопасную строчку?

Так это же вы предложили использовать статанализ для избегания UB. Я все еще жду подробностей как это сделать для знакового переполнения.

Выявляем переполнение в рантайме (вероятно платформозависимым макросом или типа того) после каждой операции, а если не выявили, то статанализатор ругается, если он на 100% не уверен, что переполнения нет.

А вы не можете выявить переполнение после операции, только до. При этом код получается некрасивым, и современными компиляторами нормально не оптимизируется.

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


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


А некрасивость и тормознутость — плата за безопасность.

если сумма меньше одного из слагаемых (напомню, положительных), то произошло переполнение.

Нет, так нельзя проверять — хороший компилятор заметит что получилось false и выкинет проверку.


Это общее свойство всех UB — его никогда нельзя заметить уже после того как оно произошло.


А некрасивость и тормознутость — плата за безопасность.

Проще использовать другой язык программирования, в котором сложение чисел никогда не даёт UB.

насколько я помню во всех процах, есть фича, что при переполнении при мат. операции выставляется специальный битик, что было переполнение.

Вот только не так-то просто "уговорить" компилятор этот битик проверить.

Сейчас открыл настройки проекта и нашёл там флаг «Проверки: Переполнения (-Co)». Как минимум в режиме отладки как минимум некоторые компиляторы проверяют переполнение. Но я не вдавался в подробности как.

Так это нестандартное расширение языка, зависящее от компилятора. И появилось оно как раз из-за того, что это UB никаким стат. анализом не найти, вот и приходится выкручиваться...

UFO just landed and posted this here

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

«Сложно-сложно, непонятно», — коллеги отвечали?

В основном другое: много кода писать для простейших вещей. И тормозить будет, наверное (бенчмарки почти никто не делал, или очень-очень синтетические типа создаём 1000000 объектов User где поле name простая строка и где это ValueObject с инвариантами длина больше ноля и меньше 256, не имеет пробельных символов кроме пробела и те не на концах и не более двух подряд.

Конечно поддержки VO в мейнстрим-языках не хватает. В F#, например, с record type коротенько получается

Учитывая тенденции — «А пусть компилятор думает...», я думаю книжка полезная. Я бы купил.
UFO just landed and posted this here
Так то да… Но потом получается, что «мордочка» для драйвера мыши весит ~200 Мб, запускается минуту, и жрёт процессор, как будто биткойны майнит…

примерно так и есть. достаточно посмотреть на современный браузер.

А как легко сделать по простому операторы +-><*/ для пользовательских типов?
А то для фунтов ньютонов и т.п. каждый раз писать лень.

type Child_Type is new Parent_Type;

Child_type унаследует операции от Parent_Type, но не будет с ним совместим по присваиванию и арифметическим операциям.

//сарказм//

А почему сарказм в rust есть derive а в плюсах метаклассы будут ждал об этом подробнее в статье

Потому что этот кусок кода написан на Аде 83-го года.
Sign up to leave a comment.