Информация об изменениях

Сообщение Re[7]: Антипаттерн, противоположный Primitive Obsession от 24.03.2023 19:23

Изменено 24.03.2023 19:30 T4r4sB

Re[7]: Антипаттерн, противоположный Primitive Obsession
Здравствуйте, netch80, Вы писали:

N>А почему ты тут думаешь именно про i32? А вдруг и его переполнит, тогда оно должно было святым духом догадаться, что надо было конвертить всё к i64? Или как?


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

N>Перемножаем. Первое произведение int64_t, второе int96_t, третье int128_t... Астанавитесь(c), Вите надо выйти!


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

N>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.


Ещё раз с самого начала — если у тебя шахматная доска 256х256, то для координат фигуры нормальный человек конечно же будет использовать int. Но с точки зрения хипстера, обдолдавшегося доменно-ориентированной хренотой, использовать int это неправильно, надо использовать тип, который в принципе не может содержать некорректных значений. И тогда типа в функции figure.place(u8 x, u8 y) мы на этапе компиляции знаем что значения валидны! При этом хипстеру насрать, что код валидации просто будет вынесен из сеттера во все места, где мы вычисляем эти координаты и никакого выигрыша мы не получим, более того, мы создаём грабли, если напишем figure1.x — figure2.y, случайно забыв скастовать в инт. Кулхацкеры конечно же никогда (на словах) не забывают сделать лишшний каст, ведь они думают, что забыть сделать каст можно только если человек не знает, что u8 не позволяет вычитать большее из меньшего, но я сомневаюсь, что у них есть хоть какой-то опыт.

N>Но тут другое. С какой именно эпохи? Юниксовой (начало 1970 года) или виндовой (1601)?

N>А может, с "юлианского дня" номер 1, как сделали в Delphi?

Да чесс слово — наплевать. Если в той же либе будет nanoseconds_to_year, которая консистентна с выбором начала эпохи.

N>Чем дальше в лес, тем толще партизаны код, тем сложнее следить за его качеством, включая 100500 аспектов, которые могут на него повлиять, и тем дороже каждое изменение. Поэтому средства поддержки в виде запрета некорректных операций — бесценны.


А вот и нет. Лишние запреты со стороны компилятора почему-то воспринимаются как абсолютное добро, но это не так. Во-первых, не все пишут прошивки для ядерных реакторов, я б сказал, что подавляющее большинство пишет код, в котором не требуется абсолютная надёжность. От падения программы просто завершится один процесс и в документ не попадут изменения за последнюю минуту. Память других программ не попортится, это не ДОС с убогим реальным режимом. Ещё со времён 386 процессора с его менеджером памяти уже есть абстракция, в которой любая программа, работающая с правами пользователя, уже является безопасной.
И если время, затрачиваемое на борьбу с компилятором больше, чем время, затрачиваемое на обнаружение и устранение бага — то лишние сложности в написании кода не только создают лишний гемор при написании и особенно рефакторинге, но и просто увеличат время создания работающего продукта. К сожалению, эпоха, когда средства повышения надёжности кода повышали и удобство программера, прошла. Да, придумали типы, структуры, функции, контрольные блоки, ифы, циклы всякие, гото стал не нужен, потом шаблоны, деструкторы. Это всё реально повышало и надёжность, и удобство. Но потенциал удобных способов повысить надёжность уже исчерпался. Теперь всё так: по умолчанию бери С++, если нужно чуть больше надёжности, бери Руст или жабошарп, если прямо угораешь по 100%-доказанности, то бери Идрис, но что-то полезное на них написать сложно.

Во-вторых, не все, что якобы повышает надёжность, действительно её повышает.
Вот те же вектора-точки. Допустим, я использую старпёрскую идеологически невыдержанную библиотеку, где вектор и точка это одно и то же.
Есть точка V. А есть плоскость, заданная уравнением V*N+C=0. И чтоб понять, с какой стороны точка находится от плоскости, я блин беру, и смотрю на знак этого самого V*N+C.
Как выглядит эта ситуация, если векторы и точки это разные сущности?! Я вижу два варианта:
1. Плоскость задаётся уравнением (P+C)*N=0, где P,C это точки, а N это вектор. Но тогда вычисление этой фигни как минимум требует лишние два вычитания.
2. Плоскость задаётся уравнением V*N+C=0, а чтоб понять, с какой стороны от этой плоскости находится точка, надо вычислить
(P-ZeroPoint)*N+C. И тут я боюсь, что любая мало-мальски сложная формула сведётся к бесконечным (P-ZeroPoint) вместо V, ну и в итоге формула будет содержать те же самые выражения, и при этом ошибиться в наборе формулы можно будет ровно в тех же местах. Более того, из-за ухудшившейся читаемости пропустить опечатку станет даже проще, и компилятор ничего не скажет.
Поэтому я просто не понимаю, от каких ошибок меня защитит разделение на точку и вектор, кроме опечаток вида (a+b)*0.6, которые легко обнаруживаются и исправляются. Все, кто реально пользовался такой либой, отмечают крайнее неудобство, ну и обычно характеризуют их авторов как "сумасшедших фанатиков, оторванных от реальности".

> Для архива оставлю ссылку. (ты там активно участвовал)

Спасибо, добавлю ещё это: https://internals.rust-lang.org/t/subscripts-and-sizes-should-be-signed/17699
К сожалению, мой низкий уровень инглиша и фанатизм сообщества не позволили обратить внимание на проблему(
Re[7]: Антипаттерн, противоположный Primitive Obsession
Здравствуйте, netch80, Вы писали:

N>А почему ты тут думаешь именно про i32? А вдруг и его переполнит, тогда оно должно было святым духом догадаться, что надо было конвертить всё к i64? Или как?


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

N>Перемножаем. Первое произведение int64_t, второе int96_t, третье int128_t... Астанавитесь(c), Вите надо выйти!


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

N>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.


Ещё раз с самого начала — если у тебя шахматная доска 256х256, то для координат фигуры нормальный человек конечно же будет использовать int. Но с точки зрения хипстера, обдолбавшегося доменно-ориентированной хренотой, использовать int это неправильно, надо использовать тип, который в принципе не может содержать некорректных значений. Не знаю зачем ему это надо, но он считает, что это круто. Ну типа в функции figure.place(u8 x, u8 y) мы на этапе компиляции знаем что значения валидны! При этом хипстеру насрать, что код валидации просто будет вынесен из сеттера во все места, где мы вычисляем эти координаты и никакого выигрыша мы не получим, более того, мы создаём грабли, если напишем figure1.x — figure2.y, случайно забыв скастовать в инт. Кулхацкеры конечно же никогда (на словах) не забывают сделать лишний каст, ведь они думают, что забыть сделать каст можно только если человек не знает, что u8 не позволяет вычитать большее из меньшего, но я сомневаюсь, что у них есть хоть какой-то опыт.

N>Но тут другое. С какой именно эпохи? Юниксовой (начало 1970 года) или виндовой (1601)?

N>А может, с "юлианского дня" номер 1, как сделали в Delphi?

Да чесс слово — наплевать. Если в той же либе будет nanoseconds_to_year, которая консистентна с выбором начала эпохи.

N>Чем дальше в лес, тем толще партизаны код, тем сложнее следить за его качеством, включая 100500 аспектов, которые могут на него повлиять, и тем дороже каждое изменение. Поэтому средства поддержки в виде запрета некорректных операций — бесценны.


А вот и нет. Лишние запреты со стороны компилятора почему-то воспринимаются как абсолютное добро, но это не так. Во-первых, не все пишут прошивки для ядерных реакторов, я б сказал, что подавляющее большинство пишет код, в котором не требуется абсолютная надёжность. От падения программы просто завершится один процесс и в документ не попадут изменения за последнюю минуту. Память других программ не попортится, это не ДОС с убогим реальным режимом. Ещё со времён 386 процессора с его менеджером памяти уже есть абстракция, в которой любая программа, работающая с правами пользователя, уже является безопасной.
И если время, затрачиваемое на борьбу с компилятором больше, чем время, затрачиваемое на обнаружение и устранение бага — то лишние сложности в написании кода не только создают лишний гемор при написании и особенно рефакторинге, но и просто увеличат время создания работающего продукта. К сожалению, эпоха, когда средства повышения надёжности кода повышали и удобство программера, прошла. Да, придумали типы, структуры, функции, контрольные блоки, ифы, циклы всякие, гото стал не нужен, потом шаблоны, деструкторы. Это всё реально повышало и надёжность, и удобство. Но потенциал удобных способов повысить надёжность уже исчерпался. Теперь всё так: по умолчанию бери С++, если нужно чуть больше надёжности, бери Руст или жабошарп, если прямо угораешь по 100%-доказанности, то бери Идрис, но что-то полезное на них написать сложно.

Во-вторых, не все, что якобы повышает надёжность, действительно её повышает.
Вот те же вектора-точки. Допустим, я использую старпёрскую идеологически невыдержанную библиотеку, где вектор и точка это одно и то же.
Есть точка V. А есть плоскость, заданная уравнением V*N+C=0. И чтоб понять, с какой стороны точка находится от плоскости, я блин беру, и смотрю на знак этого самого V*N+C.
Как выглядит эта ситуация, если векторы и точки это разные сущности?! Я вижу два варианта:
1. Плоскость задаётся уравнением (P+C)*N=0, где P,C это точки, а N это вектор. Но тогда вычисление этой фигни как минимум требует лишние два вычитания.
2. Плоскость задаётся уравнением V*N+C=0, а чтоб понять, с какой стороны от этой плоскости находится точка, надо вычислить
(P-ZeroPoint)*N+C. И тут я боюсь, что любая мало-мальски сложная формула сведётся к бесконечным (P-ZeroPoint) вместо V, ну и в итоге формула будет содержать те же самые выражения, и при этом ошибиться в наборе формулы можно будет ровно в тех же местах. Более того, из-за ухудшившейся читаемости пропустить опечатку станет даже проще, и компилятор ничего не скажет.
Поэтому я просто не понимаю, от каких ошибок меня защитит разделение на точку и вектор, кроме опечаток вида (a+b)*0.6, которые легко обнаруживаются и исправляются. Все, кто реально пользовался такой либой, отмечают крайнее неудобство, ну и обычно характеризуют их авторов как "сумасшедших фанатиков, оторванных от реальности".

> Для архива оставлю ссылку. (ты там активно участвовал)

Спасибо, добавлю ещё это: https://internals.rust-lang.org/t/subscripts-and-sizes-should-be-signed/17699
К сожалению, мой низкий уровень инглиша и фанатизм сообщества не позволили обратить внимание на проблему(