Comments 65
По существу рассматриваемого случая: удивительно, насколько автор сосредоточен на громоздких программных костылях, однако ни слова не говорит о радикальном, очевидном и давно известном решении — повсеместном переходе на систему единиц СИ.
удивительно, насколько автор сосредоточен на громоздких программных костылях, однако ни слова не говорит о радикальном, очевидном и давно известном решении — повсеместном переходе на систему единиц СИУдивительно, насколько по-разному люди понимают мысль, которую пытался донести автор.
Хотя более наглядный пример предлагаемой концепции типизации можно увидеть в std::chrono в выбранном там подходе работы с разными единицами времени (все в системе СИ, что характерно).
В штатах как были мили, там и останутся ещё 200 лет.
Как и дюймы в диаметрах водопроводных труб 1/2 3/4 5/16 7/32.
Насколько это помогло — пока сказать не могу.
Но направление правильно, особенно в отношении слаботипизованных языков, типа JS, Python, PHP.
Питон считается сильнотипизированным языком. Можете привести примеры слабости его системы типов?
Это вы описали признаки динамической типизации. С сильной/слабой типизацией это никак не связано.
Но вообще Я не уверен в том, что утиная типизация все же относится к сильной проверке типов. Ошибки с динамической типизацией в этом смысле очень похожи на ошибки некорректных данных, характерные для слабой типизации.
Может пример не совсем удачный. Представьте что у вас два поля — имя и фамилия. И оба — терминированные строки до 32 символов. С точки зрения компилятора имя можно присвоить фамилии и наоборот. С точки зрения семантики это будет ошибкой. Тесты и статический анализ такие вещи могут легко пропустить. Собственно идея которую пытались донести авторы — здорово когда система типов используемая в вашей программе отражает семантику. Тогда подобные ошибки можно отлавливать на этапе компиляции. Ну и еще делать кучу других классных штук, которые без семантической типизации либо делать трудно и дорого, либо вообще никак.
Лютое костыление — это из-за ограничений языка выбранного для примеров. В данном случае, по-моему, оправдано. Будь примеры на Скале или Хаскеле — началось бы "опять ваши монады-алгебры, ты на С попробуй!".
Спасаемся типизацией от чтения документации
Не везет людям, которые от своих коллег защищаются
delay(1000);
sleep(1);
Sleep(1000);
Сколько граблей было поломано об лбы разработчиков по всему миру, страшно представить. Просто они плохо читали документацию и были иногда невнимательны, а значит сами виноваты, очевидно же.
в Haskell
, Rust
и некоторых других языках есть конструкт newtype
специально для таких ситуаций, чтоб не складывали попугаев с удавами
как можно говорить про безопасность программы, в которой UB — это нормально и не вызывает возражений компилятора?
Прикрутить статанализ, который UB не пропустит?
Это невозможно. Было бы возможно — давно бы в язык вошло.
Вот честно, не понимаю что в этом невозможного, если о нём известно. По опыту обычно UB не стандартизируют, когда очень много софта завязано на разные варианты UB. Грубо, если определим одно поведение, то сломается половина софта, а если другое, то вторая половина.
Ну вот вам пример UB: знаковое переполнение.
Как вы определите его стат. анализом?
Отсутствием проверки на переполнение там, где статанализом мы не можем гарантированно сказать, что его нет. Грубо, в случае int a = 1 + 1, мы можем сказать, что переполнения не будет (ведь нет платформ, где int — 1 бит? )
Как вы собрались выключать и без того выключенную проверку?
Я имею в виду явную проверку в коде. Типа тайпгварда.
И что дальше-то? Вы предлагаете ругаться на каждое место, где нет проверки на переполнение, и не удалось доказать что она избыточна?
Эдак можно сразу на каждую строчку ругаться...
Если нам важна безопасность, то почему не ругаться на каждую небезопасную строчку?
Так это же вы предложили использовать статанализ для избегания UB. Я все еще жду подробностей как это сделать для знакового переполнения.
Выявляем переполнение в рантайме (вероятно платформозависимым макросом или типа того) после каждой операции, а если не выявили, то статанализатор ругается, если он на 100% не уверен, что переполнения нет.
А вы не можете выявить переполнение после операции, только до. При этом код получается некрасивым, и современными компиляторами нормально не оптимизируется.
По-моему, ровно наоборот, до операции нельзя выявить не выполняя операцию. Ну, не то чтобы совсем нельзя, можно реализовать алгоритм сложеня двоичных числе самостоятельно на основе побитовых операций и бросить ошибку, если вылезли в знаковый бит. Но тогда уже операция не нужна.
А вот после можно проверять, навскидку (не беру все форматы возможные представления знаковых чисел, да и вообще пока отрицательные слагаемые не рассматриваю): если сумма меньше одного из слагаемых (напомню, положительных), то произошло переполнение.
А некрасивость и тормознутость — плата за безопасность.
если сумма меньше одного из слагаемых (напомню, положительных), то произошло переполнение.
Нет, так нельзя проверять — хороший компилятор заметит что получилось false и выкинет проверку.
Это общее свойство всех UB — его никогда нельзя заметить уже после того как оно произошло.
А некрасивость и тормознутость — плата за безопасность.
Проще использовать другой язык программирования, в котором сложение чисел никогда не даёт UB.
Вот только не так-то просто "уговорить" компилятор этот битик проверить.
Ох, сколько копий поломано мною в попытках убедить коллег, что ValueObject с жёсткими инвариантами вместо скаляров и эпизодических валидаций — очень разумный подход, особенно если использовать средства типизации. Обычно безуспешно :(
«Сложно-сложно, непонятно», — коллеги отвечали?
В основном другое: много кода писать для простейших вещей. И тормозить будет, наверное (бенчмарки почти никто не делал, или очень-очень синтетические типа создаём 1000000 объектов User где поле name простая строка и где это ValueObject с инвариантами длина больше ноля и меньше 256, не имеет пробельных символов кроме пробела и те не на концах и не более двух подряд.
Хех, а следующий шаг это зависимые типы?
А как легко сделать по простому операторы +-><*/ для пользовательских типов?
А то для фунтов ньютонов и т.п. каждый раз писать лень.
Child_type унаследует операции от Parent_Type, но не будет с ним совместим по присваиванию и арифметическим операциям.
//сарказм//
Правильная типизация: недооцененный аспект чистого кода