Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, Кодт, Вы писали:
К>>Эта штука называется "зависимые типы". К позиции 0 можно прибавлять смещение 7, а к позиции 1 — уже нельзя.
TB>В том же русте не так. Ты можешь сложить числа 100 и 200, но если оба аргумента имеют тип u8, то компилятор тебе ничего не скажет. Типа всё ок. Но ты получишь падающую программу, из-за чего матерясь полезешь явно кастить оба аргумента к i32. Ну и нахрена оно надо, изначально-то чего в i32 не хранится? Нахрен мне нужно ограничение, при котором предполагается, что промежуточный результат будет иметь те же ограничения, что и сами данные, если это вообще даже близко не так? И тогда зачем вообще ограничивать тип, когда проще все эти проверки делать в сеттере поля?
Ну так руст — это не идрис, он не умеет в зависимые типы.
А числовые переполнения — это штука очень дискуссионная, и в разных языках к ней разные подходы.
Почему компилятор должен догадываться, что вот здесь u8+u8 = u8, а вот здесь уже = u9? А последующий u9-u8 — это u8, u9 или i10?
Для этого и пишутся спецификации по языку, — что делается по умолчанию, а что требует рукодельщины.
В сях и плюсах есть правила продвижения — (меньше-или-равно int) + (меньше-или-равно int) = int. Это тоже дискуссионная штука, потому что результат арифметики, продвинутой до int, в попытке запихать обратно в маленький тип, может тоже быть не тем, что хотел сказать автор. Вся эта трахотня с char, например.
Если в русте договорились, что тип результата не продвигается без явных указаний, — ну, делай указания.
Если есть сущность "смещения только в пределах шахматной доски", то — возможно, автору библиотеки или тебе лично, — придётся завести и сущность "расширенные смещения без гарантии, что они влезли в доску".
Опять же, разрядность этих смещений — "мамой клянусь, i32 мне за глаза и за уши", а вдруг "возьму-ка я float64"?
К>>Те же chrono.
К>>По большому счёту, там только time_point<???> и duration<???>, и очевидно, нужно сделать всю арифметику между всеми типами time и всеми типами duration, плюс какие-то удобные приведения, — чтобы у пользователя вообще не возникало желание что-то там хакнуть, выковырять внутреннее представление и надругаться напрямую.
TB>И получаем либу, с которой невозможно работать без часового курения документации. А по факту было бы достаточно одной-единственной функции, возвращающей число наносекунд с начала эпохи в виде примитивного типа i128 (знаковый, чтоб можно было вычитать два момента и не париться). Если нужны даты и дни недели — то отдельными функциями, которые берут это самое i128 дальше сами там всё считают.
А по факту, i128 в большинстве случаев люто избыточно.
Если наносекунды с начала эпохи влезают в i64, а ты будешь буферные 64 бита всюду таскать и складывать нули с нулями.
Что касается "час курить документацию", — то в случае с временем это, к сожалению, необходимое дело. Хоть с std::chrono, хоть с сишными примитивами.
И не потому, что авторы библиотек упоролись, а потому, что предметная область упоротая, — о чём клиенты не подозревают.
Все эти универсальное время, системное, монотонное... это всё разные сущности. Физически разные.
std::chrono прямо заставляет тебя сдать экзамен по метрологии, прежде чем ты пойдёшь кодить, — это правда.
TB>А ещё с этими ограничениями я не могу написать так:
TB>TB>class C {
TB> C(int128& time): time(time) { time -= std::chrono::now(); }
TB> ~C() { time += std::chrono::now(); }
TB> int128& time;
TB>};
TB>
TB>(после работы этого кода значение time увеличится ровно на то время, когда жил класс C)
TB>Конечно это всё можно обойти, и для случая когда надо просто сложить-вычесть, легко это написать по-другому. Но операции над теми же векторами бывают посложнее.
К>>Долбаный хипстер ввёл Point, Vector и Rotation, а людям расхлёбывать, да? А может, людям за чистотой своих рук последить, прежде чем Point+Point или Point+Rotation делать, не?
TB>Point+Point это нормальная операция, не надо её запрещать. Point+Rotation конечно может привести к неприятностям, но я слабо представляю себе, как можно даже случайно так написать. В случае же разделения вектора и точки на два типа получаем код, которым очень трудно пользоваться, причём геморрой от борьбы с тараканами хипстера намного превышает вероятность потенциального бага, который к тому же легко обнаружить и исправить.
А какая физическая природа у суммы двух точек?
И как к ней, например, аффинные преобразования применять?
>> Но это ведь очень хорошо, когда размер известен на стадии компиляции, и можно проконтролировать правильность формулы.
TB>Пример с размерностями матрицы — это положительный пример внедрения гарантий времени компиляции. Полагаю, с таких примеров и начались хорошие идеи по возможности проконтролировать что-то заранее на уровне системы типов. Но заставь дурака богу молиться, и он сделает систему, в которой очень трудно написать что-то полезное.
Дурак любую вещь доведёт до греха — хоть с primitive obsession, хоть с контрактами повсюду!