Ну короче тут наверное многие знают, и любой может нагуглить, что такое Primitive Obsession — это когда везде используются инты и строки, и из-за этого иногда случается фигня, когда секунды складываются с килограммами, а в емейл записывается заведомо невалидная строка.
А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию, из-за которой даже нельзя блин сложить два вектора, потому что складывать можно только вектор и точку, а если таки надо сложить два вектора, то надо после получаса попыток заставить компилятор собрать код таки узнать, что надо использовать my_vector_lib::my_vector::point_cast<my_vector_lib::my_vector::point<std::ratio<1, 1000000000>>> на одном из них? Причём даже если для этой абракадабры есть простой алиас типа my_vector_lib::my_vector::millimeter_cast, то из сообщений компилятора это узнать невозможно, и это надо обязательно зазубрить.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию, из-за которой даже нельзя блин сложить два вектора, потому что складывать можно только вектор и точку...
Здравствуйте, ononim, Вы писали:
TB>>А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию O>звучит как std::chrono
Тема действительно вдохновлена этой либой, но дело ж не только в ней. Пример, когда векторы и точки — это разные типы — придумал не я, такая дичь реально есть, и пользоваться ей просто невозможно.
Ну и подобная одержимость каждую хрень завернуть в свою обёртку свойственна в сообществе языка rust. Я просто не знаю, есть ли научное объяснение, почему так делать во многих случаях плохо, особенно если ты не пишешь прошивку ядерного реактора, пассажирского самолёта или медицинского аппарата.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, T4r4sB, Вы писали:
TB>>А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию, из-за которой даже нельзя блин сложить два вектора, потому что складывать можно только вектор и точку...
G>Это называется DDD
Domain Driven Design?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>>>А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию
Очень жаль, что в былые времена стал столь популярен язык си от пары телефонистов. Дали же людям Аду с newtype — так нет, они продолжили упорствовать, халтурщики.
TB>Тема действительно вдохновлена этой либой, но дело ж не только в ней. Пример, когда векторы и точки — это разные типы — придумал не я, такая дичь реально есть, и пользоваться ей просто невозможно. TB>Ну и подобная одержимость каждую хрень завернуть в свою обёртку свойственна в сообществе языка rust. Я просто не знаю, есть ли научное объяснение, почему так делать во многих случаях плохо, особенно если ты не пишешь прошивку ядерного реактора, пассажирского самолёта или медицинского аппарата.
Это хорошо. Особеннно чтобы "нужды бизнеса" не удовлеторялись столь быстро. Потому что пока идёт разработка, можно будет подумать, а нужны ли вообще эти нужды.
Здравствуйте, T4r4sB, Вы писали:
TB>Ну короче тут наверное многие знают, и любой может нагуглить, что такое Primitive Obsession — это когда везде используются инты и строки, и из-за этого иногда случается фигня, когда секунды складываются с килограммами, а в емейл записывается заведомо невалидная строка. TB>А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию, из-за которой даже нельзя блин сложить два вектора, потому что складывать можно только вектор и точку, а если таки надо сложить два вектора, то надо после получаса попыток заставить компилятор собрать код таки узнать, что надо использовать my_vector_lib::my_vector::point_cast<my_vector_lib::my_vector::point<std::ratio<1, 1000000000>>> на одном из них? Причём даже если для этой абракадабры есть простой алиас типа my_vector_lib::my_vector::millimeter_cast, то из сообщений компилятора это узнать невозможно, и это надо обязательно зазубрить.
Здравствуйте, gandjustas, Вы писали:
G>а потом с подачи товарища Волшина идею "make illegal states unrepresentable"
А как этот долбаный фанатик собирается писать банальную задачу "прибавить к позиции шахматной фигуры смещение и проверить валидность результата"? Ведь согласно его идеям позиция шахматной фигуры должна иметь тип [0..8), а смещение должно иметь тип [-7 ..7], и складывать их нельзя, и любая попытка скастить одно к другому вызовет исключение в некоторых случаях.
То есть он предлагает что-то типа
try_cast_or_throw<Position>((position as int) + (offset as int))
?
Чем его, сцуко, изначально не устраивает хранить всё в обычных интах? Пошёл он нахер со своими паттернами!
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Слава, Вы писали:
С>Очень жаль, что в былые времена стал столь популярен язык си от пары телефонистов. Дали же людям Аду с newtype — так нет, они продолжили упорствовать, халтурщики.
Потому что если отладить все баги быстрее, чем разгадать все загадки компилятора, то быстрее отладить все баги. К тому же в них логику часто проще найти.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>А как этот долбаный фанатик собирается писать банальную задачу "прибавить к позиции шахматной фигуры смещение и проверить валидность результата"? Ведь согласно его идеям позиция шахматной фигуры должна иметь тип [0..8), а смещение должно иметь тип [-7 ..7], и складывать их нельзя, и любая попытка скастить одно к другому вызовет исключение в некоторых случаях. TB>То есть он предлагает что-то типа
TB>
TB>try_cast_or_throw<Position>((position as int) + (offset as int))
TB>
TB>?
Не знаю, что там Волшин, а в нормальных языках и библиотеках оператор + просто определяется для (position, offset)->position и (offset, offset)->offset.
Зачем городить преобразования туда-обратно мне решительно непонятно. Задача отличается от алгебры поверх DateTime / TimeSpan исключительно дополнительными ограничениями на диапазон валидных значений.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, T4r4sB, Вы писали:
TB>А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию, из-за которой даже нельзя блин сложить два вектора, потому что складывать можно только вектор и точку
Это называется "плохой дизайн". Когда автор определенные операции либо не предусмотрел, либо предусмотрел так, что без документации их не найти.
Еще это называется "синдром четырех бандитов" или "синдром Александреску", когда неопытный разработчик прочитал умную книгу и принял её за серебряную пулю.
Здравствуйте, Sinclair, Вы писали:
S>Не знаю, что там Волшин, а в нормальных языках и библиотеках оператор + просто определяется для (position, offset)->position и (offset, offset)->offset.
Ну ок, у тебя есть position, который [0..8) и offset который [-7..7]. Если ты применишь оператор (position, offset)->position к паре (5,5), то у тебя будет паника и прога упадёт.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Здравствуйте, Sinclair, Вы писали:
S>>Не знаю, что там Волшин, а в нормальных языках и библиотеках оператор + просто определяется для (position, offset)->position и (offset, offset)->offset.
TB>Ну ок, у тебя есть position, который [0..8) и offset который [-7..7]. Если ты применишь оператор (position, offset)->position к паре (5,5), то у тебя будет паника и прога упадёт.
Здравствуйте, Sinclair, Вы писали:
TB>>А как этот долбаный фанатик собирается писать банальную задачу "прибавить к позиции шахматной фигуры смещение и проверить валидность результата"? Ведь согласно его идеям позиция шахматной фигуры должна иметь тип [0..8), а смещение должно иметь тип [-7 ..7], и складывать их нельзя, и любая попытка скастить одно к другому вызовет исключение в некоторых случаях. TB>>То есть он предлагает что-то типа
TB>>
TB>>try_cast_or_throw<Position>((position as int) + (offset as int))
TB>>
TB>>? S>Не знаю, что там Волшин, а в нормальных языках и библиотеках оператор + просто определяется для (position, offset)->position и (offset, offset)->offset. S>Зачем городить преобразования туда-обратно мне решительно непонятно. Задача отличается от алгебры поверх DateTime / TimeSpan исключительно дополнительными ограничениями на диапазон валидных значений.
И как предлагается этим пользоваться? На каждый чих писать отдельный тип с кучей операторов? Ещё тип для смещений этого типа. Не очень понятно. Звучит как маразм или я что-то не понимаю.
Здравствуйте, T4r4sB, Вы писали: TB>Ну ок, у тебя есть position, который [0..8) и offset который [-7..7]. Если ты применишь оператор (position, offset)->position к паре (5,5), то у тебя будет паника и прога упадёт.
Ну почему же упадёт? Надо просто ловить соответствующее исключение. Типичный пример checked arithmetics.
Опять же, в приличных языках есть возможности отдельно описать поведение операторов с включенными проверками и без них, и дать пользователю выбор.
Тогда
var a = (position)5 + (offset)5 - (offset)3;
даст a == (position)8, а
checked
{
var a = (position)5 + (offset)5 - (offset)3;
}
— выбросит исключение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vsb, Вы писали: vsb>И как предлагается этим пользоваться? На каждый чих писать отдельный тип с кучей операторов? Ещё тип для смещений этого типа. Не очень понятно. Звучит как маразм или я что-то не понимаю.
На каждый чих — нет, не надо. А насколько часто у вас встречаются диапазонные типы? Ну, так, если по-честному?
Если нас интересует не диапазон, а размерность, то есть вполне себе простой способ описывать типы обобщённым образом, по некоторому шаблону.
Не сложнее пишется и шаблон для пары типов "база, смещение", т.к. арифметика у них ведёт себя весьма предсказуемо.
В чём проблема-то?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vsb, Вы писали:
vsb>И как предлагается этим пользоваться? На каждый чих писать отдельный тип с кучей операторов? Ещё тип для смещений этого типа. Не очень понятно. Звучит как маразм или я что-то не понимаю.
Добро пожаловать в Раст Коммьюнити!
Ах, да, ты ничего не понимаешь, потому что у тебя Primitive Obsession. Писать простой код, который тупо складывает два числа — это Primitive Obsession. Надо обмазываться кастами и чекед методами, при этом чем длиннее и непонятнее выглядит код, тем лучше.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Забыл сказать, что разные числовые типы складывать нельзя.
А ещё если ты скастишь только одно слагаемое к типу другого, то получишь панику, потому что тип другого не вмещает в себя все значения типа первого. То есть тебе надо не забывать всё кастить именно к более широкому типу. Напонимаю, что изначально всё хранить в широком типе — это Primitive Obsession, хипстота из раст коммьюнити тебя засмеёт за такое.
А ещё если тебе надо сложить два разных смещения, то тебе надо заранее учесть, что 7+7 не влезает в тип смещения, и если ты забудешь заранее скастить к инту, то компилятор тебе ничего не скажет, но ты получишь панику в рантайме.
Короче вместо a+b тебе придётся писать (a as int).checked_add(b as int).
И даже если частный случай сложения позиции и смещения ты инкапсулируешь в виде специального случая, то такую хрень тебе придётся прописывать каждый раз когда тебе нужна хоть какая-то арифметика, не предусмотренная всеми частными случаями, которые ты описал до этого. Маразматики из Раст коммьюнити говорят "воспринимай этот как чёрный ящик и пиши отдельный приватный метод для каждого случая, когда нужны вычисления с промежуточным кастом в более широкий тип".
При этом гораздо более простое, очевидное и менее склонное к внезапным паникам решение "хранить всё в инте изначально" считается антипаттерном Primitive Obsession.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Sinclair, Вы писали:
S>А насколько часто у вас встречаются диапазонные типы? Ну, так, если по-честному?
На Русте какой-то идиот ввёл для размера массива тип usize, мотивируя это тем, что ограничение >=0 "соответствует специфике домена", при этом на вопрос что делать если надо вычитать два размера, мне сказали "мне никогда это не надо было делать". Дальше разгорелся срач, я привёл пример с шахматной доской 256х256, и спросил, реально ли они ради дебильной идеи сраных доменов будут использовать u8, понимая, что тривиальные операции будет делать крайне геморройно, и они сказали что да.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>На Русте какой-то идиот ввёл для размера массива тип u32, мотивируя это тем, что ограничение >=0 "соответствует специфике домена"
А что не так? Лимит в 32 бита конечно неправильно, надо size_t
TB> при этом на вопрос что делать если надо вычитать два размера
И в чём проблема?
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Проблема в том, что я должен вручную отдельно разбирать случай, когда a<b. Если я забуду это сделать, то получу некорректно работающий код, то есть либо сразу программа свалится в дебаге, либо будет неверное значение в релизе. Никакой проблемы бы не было, если бы изначально был знаковый isize. Когда я спросил, нахрена создавать программистам проблемы, мне сказали что это потому что usize это более "домменно-ориентированный тип". Ок, я тоже подрочил на это красивое слово, но ненужный геморрой не исчез.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>А как этот долбаный фанатик собирается писать банальную задачу "прибавить к позиции шахматной фигуры смещение и проверить валидность результата"? Ведь согласно его идеям позиция шахматной фигуры должна иметь тип [0..8), а смещение должно иметь тип [-7 ..7], и складывать их нельзя, и любая попытка скастить одно к другому вызовет исключение в некоторых случаях.
Эта штука называется "зависимые типы". К позиции 0 можно прибавлять смещение 7, а к позиции 1 — уже нельзя.
Ну, некоторые языки такую штуку поддерживают. Но это хардкор функциональщина.
Либо её можно попытаться протащить в вычисления времени компиляции — например, в плюсах это всякие constexpr и магия на шаблонах.
Либо её можно протащить ограниченно. Размерности, роли, иногда — флажки (конечный набор состояний), — вот это всё делается через фантомные типы.
Практика распространённая, и ничего ужасного в ней нет. Кроме одного: от разработчика требуется написать исчерпывающую обвязку, если компилятор не умеет делать её сам, или делает неправильно.
Те же chrono.
По большому счёту, там только time_point<???> и duration<???>, и очевидно, нужно сделать всю арифметику между всеми типами time и всеми типами duration, плюс какие-то удобные приведения, — чтобы у пользователя вообще не возникало желание что-то там хакнуть, выковырять внутреннее представление и надругаться напрямую.
А в статье по фа-диезу как раз создаются фантомные типы "контакт недозаполненный", "контакт с емейлом", "контакт с адресом"...
Это, скорее, демонстратор технологии, а не то, что обязательно надо тащить в продакшен. Но тащить в продакшен вполне можно.
Библиотеки линейной алгебры, к примеру, могут оперировать матрицами или тензорами произвольного размера, и больше того, внутри они смотрят на размер в рантайме.
Но это ведь очень хорошо, когда размер известен на стадии компиляции, и можно проконтролировать правильность формулы.
Или библиотеки геометрических преобразований, у которых есть как минимум три сущности, записанные 3-мерным (или 4-мерным) вектором: точка (три реальных координаты / плюс фиктивная 1 в четвёртой компоненте), расстояние (фиктивный 0) и поворот (эйлеровы углы / кватернион).
Долбаный хипстер ввёл Point, Vector и Rotation, а людям расхлёбывать, да? А может, людям за чистотой своих рук последить, прежде чем Point+Point или Point+Rotation делать, не?
Здравствуйте, Кодт, Вы писали:
К>Эта штука называется "зависимые типы". К позиции 0 можно прибавлять смещение 7, а к позиции 1 — уже нельзя.
В том же русте не так. Ты можешь сложить числа 100 и 200, но если оба аргумента имеют тип u8, то компилятор тебе ничего не скажет. Типа всё ок. Но ты получишь падающую программу, из-за чего матерясь полезешь явно кастить оба аргумента к i32. Ну и нахрена оно надо, изначально-то чего в i32 не хранится? Нахрен мне нужно ограничение, при котором предполагается, что промежуточный результат будет иметь те же ограничения, что и сами данные, если это вообще даже близко не так? И тогда зачем вообще ограничивать тип, когда проще все эти проверки делать в сеттере поля?
К>Те же chrono. К>По большому счёту, там только time_point<???> и duration<???>, и очевидно, нужно сделать всю арифметику между всеми типами time и всеми типами duration, плюс какие-то удобные приведения, — чтобы у пользователя вообще не возникало желание что-то там хакнуть, выковырять внутреннее представление и надругаться напрямую.
И получаем либу, с которой невозможно работать без часового курения документации. А по факту было бы достаточно одной-единственной функции, возвращающей число наносекунд с начала эпохи в виде примитивного типа i128 (знаковый, чтоб можно было вычитать два момента и не париться). Если нужны даты и дни недели — то отдельными функциями, которые берут это самое i128 дальше сами там всё считают.
А ещё с этими ограничениями я не могу написать так:
class C {
C(int128& time): time(time) { time -= std::chrono::now(); }
~C() { time += std::chrono::now(); }
int128& time;
};
(после работы этого кода значение time увеличится ровно на то время, когда жил класс C)
Конечно это всё можно обойти, и для случая когда надо просто сложить-вычесть, легко это написать по-другому. Но операции над теми же векторами бывают посложнее.
К>Долбаный хипстер ввёл Point, Vector и Rotation, а людям расхлёбывать, да? А может, людям за чистотой своих рук последить, прежде чем Point+Point или Point+Rotation делать, не?
Point+Point это нормальная операция, не надо её запрещать. Point+Rotation конечно может привести к неприятностям, но я слабо представляю себе, как можно даже случайно так написать. В случае же разделения вектора и точки на два типа получаем код, которым очень трудно пользоваться, причём геморрой от борьбы с тараканами хипстера намного превышает вероятность потенциального бага, который к тому же легко обнаружить и исправить.
> Но это ведь очень хорошо, когда размер известен на стадии компиляции, и можно проконтролировать правильность формулы.
Пример с размерностями матрицы — это положительный пример внедрения гарантий времени компиляции. Полагаю, с таких примеров и начались хорошие идеи по возможности проконтролировать что-то заранее на уровне системы типов. Но заставь дурака богу молиться, и он сделает систему, в которой очень трудно написать что-то полезное.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Мысль Страуструпа — в том, что "давайте делать неопределённое поведение более понятным".
Если мы пытаемся создать вектор отрицательного размера или обратиться по отрицательному смещению — это уже плохо, но мы, хотя бы, получим внятную диагностику. Вместо того, чтобы улететь в гигантские значения.
Ну извините. Секретное знание о том, что на входе конструктора или субскрипта должно быть заведомо неотрицательное число — с одной стороны, позволяет делать более агрессивную оптимизацию, а с другой стороны — позволяет стрелять в ногу. Так весь Си и С++ на этом построен.
Здравствуйте, Кодт, Вы писали:
К>Мысль Страуструпа — в том, что "давайте делать неопределённое поведение более понятным". К>Если мы пытаемся создать вектор отрицательного размера или обратиться по отрицательному смещению — это уже плохо, но мы, хотя бы, получим внятную диагностику. Вместо того, чтобы улететь в гигантские значения.
В Расте ещё интереснее. В С++ при вычитании двух индексов ты с вероятностью 1/2 получишь очень большое число. А в Расте с вероятностью 1/2 программа просто упадёт.
К>Ну извините. Секретное знание о том, что на входе конструктора или субскрипта должно быть заведомо неотрицательное число — с одной стороны, позволяет делать более агрессивную оптимизацию
Это секретное знание можно дать компилятору в виде ассертов, которое в релизе превращается в ассьюм.
К>Кстати, целочисленные переполнения — это отдельный котёл ада. Вот, можно почитать и поужасаться. https://github.com/Nekrolm/ubbook/blob/master/numeric/overflow.md
Я конечно в курсе про то, что компилятор вправе предполагать, что программист никогда не переполняет результат, и из-за этого иногда выкидывает довольно важные вычисления. Но точно так же компилятор вправе навтыкать и отладочные проверки, что действительно нет переполнения, и для этого есть санитайзеры.
К>Так что переделать API векторов на знаковые размеры и смещения — это просто сместить проблему немножко вперёд-назад по клиентскому коду.
Это передвинет её из "регулярно огребаю" в "огребаю раз в сто лет на экзотическом наборе данных", вроде не это называется повышением надёжности? Разумеется, я не говорю о случае, когда программа пытается как можно дольше скрывать ошибку, вызванную заведомо некорректными данными. Проблема в том, что беззнаковые числа любят валить программу на валидных данных. в Расте сразу, в С++ попозже.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Ой, я опечатался. Короче, там ввели usize, а должно быть isize.
Схренали размер объекта должен быть isize? Он не бывает отрицательным никогда.
TB> Страуструп тоже так считает: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1428r0.pdf
И? Это не имеет физического смысла. Ещё дробным сделайте, вообще офигенно будет.
У нас такие идиоты тоже сделали LBA знаковым в протоколе. Столько гемору вылезло из за этого потом — вбыв бы!
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, 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, хоть с контрактами повсюду!
Здравствуйте, T4r4sB, Вы писали:
TB>Это передвинет её из "регулярно огребаю" в "огребаю раз в сто лет на экзотическом наборе данных", вроде не это называется повышением надёжности? Разумеется, я не говорю о случае, когда программа пытается как можно дольше скрывать ошибку, вызванную заведомо некорректными данными. Проблема в том, что беззнаковые числа любят валить программу на валидных данных. в Расте сразу, в С++ попозже.
C++ никогда не обещал повышать надёжность. А наоборот, расширенно трактует неопределённое поведение, — кроме тех случаев, которые успели войти в повседневную практику на старом добром си, и теперь вроде как стыдно ломать код, который всегда работал.
Поэтому надо следить за чистотой рук, и не только с целыми числами, а вообще везде.
Здравствуйте, T4r4sB, Вы писали:
TB>Добро пожаловать в Раст Коммьюнити! TB>Ах, да, ты ничего не понимаешь, потому что у тебя Primitive Obsession. Писать простой код, который тупо складывает два числа — это Primitive Obsession. Надо обмазываться кастами и чекед методами, при этом чем длиннее и непонятнее выглядит код, тем лучше.
Ну я так никогда не делал, поэтому мне сложно оценить осмысленность этой идеи.
Вообще я всегда, когда вижу, как люди увлекаются перекладыванием на систему типов всё большего функционала, вспоминаю, что рядом есть люди, которые пишут на JS и питоне. И пишут вполне себе серьёзные проекты, приносящие пользу и зарабатывающие деньги. И также вспоминаю, что уже лет 30 есть хаскель, который, несмотря на всю его типизированную мощь, так и не нашёл отклика в сердце массового программиста.
Поэтому тут в любом случае нужен баланс между этими крайностями. Где он в этом примере с числовыми типами я пока не знаю. Если я могу сказать type Money = Decimal, получить автоматом тип для Money.offset, Money.power(2) (деньги в квадрате), со всеми автоматом выведенными и корректно работающими операторами, так, чтобы преобразования между числами и деньгами были только на входе и выходе из алгоритма, грубо говоря, 3 строчки на 1000, тогда может и нормально будет. А если мне надо написать 100 строк вспомогательного кода, только чтобы потом написать 20 строк основного, ну это не очень.
Здравствуйте, T4r4sB, Вы писали:
S>>А насколько часто у вас встречаются диапазонные типы? Ну, так, если по-честному?
TB>На Русте какой-то идиот ввёл для размера массива тип usize, мотивируя это тем, что ограничение >=0 "соответствует специфике домена", при этом на вопрос что делать если надо вычитать два размера, мне сказали "мне никогда это не надо было делать". Дальше разгорелся срач, я привёл пример с шахматной доской 256х256, и спросил, реально ли они ради дебильной идеи сраных доменов будут использовать u8, понимая, что тривиальные операции будет делать крайне геморройно, и они сказали что да.
Моё имхо: для указателя/размера массива нужно использовать некий спец тип 0 .. 2^63 — 1 (для 64 битов). Можно назвать его u63. При этом при вычитании должен получаться i64. Ну и можно складывать u63 + i64 = u63. Это почти все проблемы бы решило, как мне кажется. То бишь тот самый offset. А адреса 2^63 .. 2^64 — 1 пометить как невалидные, чтобы при попытке обращения к ним всё падало (в идеале вообще добавить в процессор специальные операции, которые будут вызывать прерывание сразу после вычисления неправильного адреса).
CC>Схренали размер объекта должен быть isize? Он не бывает отрицательным никогда.
Против подобных идиотских мыслей я и борюсь. А на два шага вперед посмотреть?. Если он сам по себе не бывает меньше нуля, то это не значит что тебе не понадобятся промежуточные представления с отрицательным результатом. И если понадобятся то у тебя программа упадет. И придется код засирать кастами. И всего этого бы не было если бы изначально был знаковый размер.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, T4r4sB, Вы писали:
TB>>А как этот долбаный фанатик собирается писать банальную задачу "прибавить к позиции шахматной фигуры смещение и проверить валидность результата"? Ведь согласно его идеям позиция шахматной фигуры должна иметь тип [0..8), а смещение должно иметь тип [-7 ..7], и складывать их нельзя, и любая попытка скастить одно к другому вызовет исключение в некоторых случаях.
К>Эта штука называется "зависимые типы". К позиции 0 можно прибавлять смещение 7, а к позиции 1 — уже нельзя. К>Ну, некоторые языки такую штуку поддерживают. Но это хардкор функциональщина. К>Либо её можно попытаться протащить в вычисления времени компиляции — например, в плюсах это всякие constexpr и магия на шаблонах.
Все это хорошо про "зависимые типы", Lof Type Theory, но, получается парадокс.
Т.е. внизу у нас Тюринг-комплит система, скажем, C или там С++, и сверху мы начинаем
сильной типизацией городить Тюринг-комплит метауровень.
В успешном случае у нас тогда каждая программа может быть представлена как
своей версией на голом С, так и версией делающей то же самое средствами "зависимой типизации".
Для хардкорного доказательства теорем это может быть круто. А для сложения-умножения точек
в каком-нибудь GDI кажется будет перебором.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, T4r4sB, Вы писали:
TB>>Здравствуйте, Кодт, Вы писали:
К>А числовые переполнения — это штука очень дискуссионная, и в разных языках к ней разные подходы. К>Почему компилятор должен догадываться, что вот здесь u8+u8 = u8, а вот здесь уже = u9? А последующий u9-u8 — это u8, u9 или i10?
Ну ок, компилятор не должен догадываться. Пусть будет результат u8. А я возьму инт и не буду про это думать? Можно? Нет, нельзя.
К>Если в русте договорились, что тип результата не продвигается без явных указаний, — ну, делай указания.
Проблема в том что в раст коммьюнити считается нормой изнасиловать разработчика этой необходимостью делать указания. И по надежности при этом никакого профита по сравнению с простым хранением интов.
К>Если есть сущность "смещения только в пределах шахматной доски", то — возможно, автору библиотеки или тебе лично, — придётся завести и сущность "расширенные смещения без гарантии, что они влезли в доску".
Да можно. Только эти хипстеры забыли что не надо плодить сущности без необходимости. А необходимости нет — на простых интах жилось ьы намного проще.
К>Опять же, разрядность этих смещений — "мамой клянусь, i32 мне за глаза и за уши", а вдруг "возьму-ка я float64"?
Переход на плавающие числа это уже радикальное изменение которое требует переписать почти все.
К>А по факту, i128 в большинстве случаев люто избыточно. К>Если наносекунды с начала эпохи влезают в i64, а ты будешь буферные 64 бита всюду таскать и складывать нули с нулями.
А я не знаю, влезают ли в i64? Там запаса почти нет вродь. Ну если и его хватит то можно и его. Зато голову морочить не надо.
К>Все эти универсальное время, системное, монотонное... это всё разные сущности. Физически разные. К>std::chrono прямо заставляет тебя сдать экзамен по метрологии, прежде чем ты пойдёшь кодить, — это правда.
Когда я пользовалсяGetTickCount(), time(), rdtsc() и QueryPerformanceCounter() то как то обходился без экзамена. Правда один раз огреб с GetTickCount когда у компа аптайм превысил ограничения типа
К>А какая физическая природа у суммы двух точек? К>И как к ней, например, аффинные преобразования применять?
Сумма это промежуточный результвт операции "полусумма" у которой есть смысл.
Конечно можно записать это в виде a+(b-a)*0.5, но не всегда. Например тебе надо миллион точек прополусуммировать с данной. Тогда заранее вычислить a*0.5 было бы проще.
А пользы от данной идеи не вижу. Защииа он неверных значений не имеющих физического смысла типа (a+b)*0.6? Ну так если я напишу a+(b-a)*0.6, то мне станет не легче от того что результат сиал гдето примерно посередине a и b
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, vsb, Вы писали:
vsb>Вообще я всегда, когда вижу, как люди увлекаются перекладыванием на систему типов всё большего функционала, вспоминаю, что рядом есть люди, которые пишут на JS и питоне.
не стоит еще забывать что для JS придумали TS, на который и стараются переползать по возможности.
а для питона появились аннотации типов, которые тоже активно применяют.
Здравствуйте, T4r4sB, Вы писали:
TB>Ну ок, у тебя есть position, который [0..8) и offset который [-7..7]. Если ты применишь оператор (position, offset)->position к паре (5,5), то у тебя будет паника и прога упадёт.
Возмущение понятно. Не очень понятно что именно предлагается взамен. Отсутствие какого-либо контроля на уровне типов? Т.е. пусть все представляется int-ами, а если к position=5 добавят offset=-7, то что? Пользователь обязан проверить результаты своих операций перед тем, как эти результаты как-то использовать? Делать какие-то проверки на входе в функции, которые ожидают position?
Т.е. могли бы вы описать как вам бы хотелось работать с подобными значениями?
Здравствуйте, so5team, Вы писали:
S>Т.е. могли бы вы описать как вам бы хотелось работать с подобными значениями?
Как с интами. Ну и валидацию только в самом конце когда ставим фигуру на доску.
Опционально валидацаю в сеттере set_coords. Вроде это намного проще чем кастовать на каждый чих.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
вот так сразу взять и здоровую идею назвать антипаттерном.
Во-первых, если операция сложения векторов не определена, но валидна для данной области, то это очевидно проблема разработчика, а не подхода. Определяем операцию и всё.
Во-вторых, смотрим на С++ с его "прекрасными" сообщениями об ошибках и делаем выводы для всей идеи. Возьмём другой инструмент и овертипизация уже не будет казаться такой уж овер.
Здравствуйте, vsb, Вы писали:
vsb>Вообще я всегда, когда вижу, как люди увлекаются перекладыванием на систему типов всё большего функционала, вспоминаю, что рядом есть люди, которые пишут на JS и питоне. И пишут вполне себе серьёзные проекты, приносящие пользу и зарабатывающие деньги. И также вспоминаю, что уже лет 30 есть хаскель, который, несмотря на всю его типизированную мощь, так и не нашёл отклика в сердце массового программиста.
Это ты зря. Многие идеи с монадами, типизацией, ленивостью, иммутабельностью и прочей функциональщиной перекочевали в массовые ЯП типа c#/java/typescript и даже js с питонами.
Из хаскеля получился отличный полигон для испытаний.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, T4r4sB, Вы писали:
TB>Против подобных идиотских мыслей я и борюсь. А на два шага вперед посмотреть?
Смотрю на куда больше чем на два.
Никакого signed там быть не должно.
TB>И придется код засирать кастами. И всего этого бы не было если бы изначально был знаковый размер.
И ради этой мелочи ты готов посеять далеко растущую проблему?
Что там насчёт "больше чем на два шага?"
Этот срач уже был, мне не интересно его заново начинать.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, vsb, Вы писали:
vsb>А адреса 2^63 .. 2^64 — 1 пометить как невалидные, чтобы при попытке обращения к ним всё падало (в идеале вообще добавить в процессор специальные операции, которые будут вызывать прерывание сразу после вычисления неправильного адреса).
А ничо что весь kernel живёт в этих адресах?
Рука так и тянется к шотгану...
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, sergii.p, Вы писали:
SP>Во-вторых, смотрим на С++ с его "прекрасными" сообщениями об ошибках
О чём ты вообще?
Или ты кроме микрософтовского компилера ничем другим не пользовался?
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
vsb>>А адреса 2^63 .. 2^64 — 1 пометить как невалидные, чтобы при попытке обращения к ним всё падало (в идеале вообще добавить в процессор специальные операции, которые будут вызывать прерывание сразу после вычисления неправильного адреса).
CC> CC>А ничо что весь kernel живёт в этих адресах? CC>Рука так и тянется к шотгану...
Здравствуйте, T4r4sB, Вы писали:
S>>Т.е. могли бы вы описать как вам бы хотелось работать с подобными значениями?
TB>Как с интами. Ну и валидацию только в самом конце когда ставим фигуру на доску. TB>Опционально валидацаю в сеттере set_coords. Вроде это намного проще чем кастовать на каждый чих.
Т.е., условно такой вариант вас устроил бы (в варианте C++, в Rust-овом синтаксисе могу напутать)?
class Position {
int v_;
public:
Position(int v); // Здесь контроль за корректностью v. Исключение если некорректно.
[[nodiscard]] int value() const noexcept { return v_; }
};
class Offset {
int v_;
public:
Offset(int v); // Здесь контроль за корректностью v. Исключение если некорректно.
[[nodiscard]] int value() const noexcept { return v_; }
};
void MakeMove(Position from, Offset to) { // На вход могут прийти только корректные значения.
...
}
Внутри же MakeMove для проведения вычисления новой позиции нужно будет оперировать "голыми" int-ами, которые получаются из исходных "оберток" посредством методов value().
Здравствуйте, CreatorCray, Вы писали:
CC>Смотрю на куда больше чем на два. CC>Никакого signed там быть не должно.
Да хоть на 10. Я использовал знаковые размеры в других языках — жить стало лишь легче. Доменная ориентированность оказалась ненужным словом, чисто чтоб хипсторам порадоваться
TB>>И придется код засирать кастами. И всего этого бы не было если бы изначально был знаковый размер. CC>И ради этой мелочи ты готов посеять далеко растущую проблему?
Да нет никакой далеко растущей проблемы
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, sergii.p, Вы писали:
SP>>Во-вторых, смотрим на С++ с его "прекрасными" сообщениями об ошибках CC>О чём ты вообще? CC>Или ты кроме микрософтовского компилера ничем другим не пользовался?
То ли дело сообщения об ошибках в гцц , да?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, so5team, Вы писали:
S>Т.е., условно такой вариант вас устроил бы (в варианте C++, в Rust-овом синтаксисе могу напутать)?
Ну вроде выглядит здраво. Конечно если MakeMove это единственное место где нужны числовые значения, то тогда наличие методов value становится бессмысленным, и если его убрать то и получилось бы что-то в стиле адептов ddd.
Но когда таких методов становится овердофига и постоянно пишешь новые, то лучше использовать этот самый value
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Ну вроде выглядит здраво. Конечно если MakeMove это единственное место где нужны числовые значения, то тогда наличие методов value становится бессмысленным, и если его убрать то и получилось бы что-то в стиле адептов ddd.
В C++ (как и в Rust-е, емнип) нет read-only свойств (aka properties). Поэтому если хочется, чтобы типы Position и Offset представляли только корректные значения, то приходится само значение прятать, а доступ к нему делать через getter.
Если же таких гарантий от Position и Offset не нужно, то можно вообще вот так в C++ после C++11:
struct Position { int v_; };
struct Offset{ int v_; };
Собственно, это удобно когда приходится работать с функциями/методами, в которых подряд идет много однотипных аргументов (вроде трех int-ов подряд, или четырех bool-ов подряд).
Но это уже частности. Как бы суть такого подхода, что типы вводятся только для хранения значений, отдельных операторов для манипулирования значениями не делается. Из-за чего со значениями можно работать как хочешь, приводя к нужным рамкам только там, где ожидается финальный результат.
Здравствуйте, T4r4sB, Вы писали:
CC>>А что не так? Лимит в 32 бита конечно неправильно, надо size_t TB>Ой, я опечатался. Короче, там ввели usize, а должно быть isize.
Разве не очевидно, что разница двух usize должна давать isize?
Здравствуйте, B0FEE664, Вы писали:
BFE>Разве не очевидно, что разница двух usize должна давать isize?
Мне очевидно, что разница двух чисел из диапазона [0 .. 2**64-1] должна лежать в диапазоне [1-2**64 .. 2**64-1], но такое в реальности не сделать с приемлемой производительностью. Теория обосралась при встрече с практикой.
Во всех известных мне языках разница двух usize это usize. И всем пофиг что это падает на данных из самого часто используемого на практике диапазона.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, no_ise, Вы писали:
_>Для хардкорного доказательства теорем это может быть круто. А для сложения-умножения точек _>в каком-нибудь GDI кажется будет перебором.
А потом к вам прилетает спецтекст, который при открытии в Блокноте вызывает выполнение произвольного кода.
Здравствуйте, T4r4sB, Вы писали:
BFE>>Разве не очевидно, что разница двух usize должна давать isize? TB> Мне очевидно, что разница двух чисел из диапазона [0 .. 2**64-1] должна лежать в диапазоне [1-2**64 .. 2**64-1],
А причём тут числа? TB>но такое в реальности не сделать с приемлемой производительностью.
откуда вы взяли степень 64? зачем 64?
TB>Во всех известных мне языках разница двух usize это usize. И всем пофиг что это падает на данных из самого часто используемого на практике диапазона.
Есть принципиальная разница между порядковым числом и числом выражающим количество. А то, что большинство их всё время путает — ну это проблемы большинства. У меня есть код в котором индекс — это unsigned int по модулю размера массива. И никаких проблем с выходом за пределы массива.
Здравствуйте, T4r4sB, Вы писали:
G>>а потом с подачи товарища Волшина идею "make illegal states unrepresentable"
TB>А как этот долбаный фанатик собирается писать банальную задачу "прибавить к позиции шахматной фигуры смещение и проверить валидность результата"?
Позиция шахматной фигуры — это беззаконное целое по модулю 8.
Здравствуйте, B0FEE664, Вы писали:
TB>> Мне очевидно, что разница двух чисел из диапазона [0 .. 2**64-1] должна лежать в диапазоне [1-2**64 .. 2**64-1], BFE>А причём тут числа?
Действительно, какое же отношение тип имеет к числам.
BFE>откуда вы взяли степень 64? зачем 64?
Интересно, и сколько же битов у usize на большинстве современных компов.
BFE>Есть принципиальная разница между порядковым числом и числом выражающим количество. А то, что большинство их всё время путает — ну это проблемы большинства. У меня есть код в котором индекс — это unsigned int по модулю размера массива. И никаких проблем с выходом за пределы массива.
И как ты в своём коде выполняешь операцию "циклически перейти к предыдущему элементу"?
Здравствуйте, B0FEE664, Вы писали:
BFE>Позиция шахматной фигуры — это беззаконное целое по модулю 8.
Я ж не про шахматы на торе
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, so5team, Вы писали:
S>Собственно, это удобно когда приходится работать с функциями/методами, в которых подряд идет много однотипных аргументов (вроде трех int-ов подряд, или четырех bool-ов подряд).
Кстати, как это помогает, когда 4 була подряд? Типа позволяет выдать аргументам имена в точке вызова, типа не просто
Здравствуйте, T4r4sB, Вы писали:
TB>>> Мне очевидно, что разница двух чисел из диапазона [0 .. 2**64-1] должна лежать в диапазоне [1-2**64 .. 2**64-1], BFE>>А причём тут числа? TB>Действительно, какое же отношение тип имеет к числам.
Вот правильный вопрос. Ответ — опосредованное.
BFE>>откуда вы взяли степень 64? зачем 64? TB>Интересно, и сколько же битов у usize на большинстве современных компов.
А ещё интересно сколько памяти на большинстве современных компов.
BFE>>Есть принципиальная разница между порядковым числом и числом выражающим количество. А то, что большинство их всё время путает — ну это проблемы большинства. У меня есть код в котором индекс — это unsigned int по модулю размера массива. И никаких проблем с выходом за пределы массива. TB>И как ты в своём коде выполняешь операцию "циклически перейти к предыдущему элементу"?
Как обычно, с помощью итераторов. Для этого индексы вообще не нужны.
Если же в общем случае, то index = (index + offset) % size
BFE>>Позиция шахматной фигуры — это беззаконное целое по модулю 8. TB>Я ж не про шахматы на торе
А вы вообще не про шахматы, потому что в шахматах ход на произвольное значение невозможен.
Здравствуйте, B0FEE664, Вы писали:
TB>Действительно, какое же отношение тип имеет к числам. BFE>Вот правильный вопрос. Ответ — опосредованное.
Правда? А в спецификации прямо сказано, какой диапазон у какого типа на какой платформе.
BFE>А ещё интересно сколько памяти на большинстве современных компов.
А какая разница? Тип usize такой, какой он есть.
BFE>Как обычно, с помощью итераторов. Для этого индексы вообще не нужны.
И как итератор позволяет перейти циклически на 1 элемент назад?
BFE>Если же в общем случае, то index = (index + offset) % size
А для отрицательного оффсета как?
BFE>А вы вообще не про шахматы, потому что в шахматах ход на произвольное значение невозможен.
Очевидно, что я про внутреннюю реализацию шахматного движка, а не про возможность игрока двигать любую фигуру на любое поле.
Сорян, даже полный наркоман, свихнувшийся на Александреску, не сможет записать корректный ход шахматной фигуры, чтобы его корректность выражалась на уровне системы типов.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Да хоть на 10. Я использовал знаковые размеры в других языках — жить стало лишь легче. Доменная ориентированность оказалась ненужным словом, чисто чтоб хипсторам порадоваться
А у нас вон один <censored> сделал LBA знаковым и насрал нам кучу геморроя сделав ну очень геморройным использование старшего бита.
Потому что этот мудак дане не потрудился подумать своим межушным ганглием ну хоть чуточку вперёд. Ай похрен на то, что LBA отрицательным не бывает, "мне так удобнее будет".
TB>Да нет никакой далеко растущей проблемы
Это у тебя нет, потому что ты её просто ещё пока не видишь.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, vsb, Вы писали:
vsb>И в чём проблема кернелу жить в других адресах?
Пусть все вокруг всё переделают только чтоб тебе было "удобнее", да?
Сразу нафиг!
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
CC>А у нас вон один <censored> сделал LBA знаковым и насрал нам кучу геморроя сделав ну очень геморройным использование старшего бита.
А что сложного в использовании старшего бита у знакового числа?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Кстати, как это помогает, когда 4 була подряд? Типа позволяет выдать аргументам имена в точке вызова, типа не просто
TB>foo(true, true, false, true)
TB>а
TB>foo(Big{true}, Black{true}, Long{false}, Strong{true})?
Типа того. Но еще полезнее это когда есть проброс параметров из одной функции в другую. Если все параметры типизированные, то случайно перепутать значения не получится.
Здравствуйте, T4r4sB, Вы писали:
CC>>А у нас вон один <censored> сделал LBA знаковым и насрал нам кучу геморроя сделав ну очень геморройным использование старшего бита.
TB>А что сложного в использовании старшего бита у знакового числа?
Он совершенно случайно оказывается нужен для представления обычных, не негативных адресов.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, no_ise, Вы писали:
_>Все это хорошо про "зависимые типы", Lof Type Theory, но, получается парадокс. _>Т.е. внизу у нас Тюринг-комплит система, скажем, C или там С++, и сверху мы начинаем _>сильной типизацией городить Тюринг-комплит метауровень.
А что, компилятор — не программа, чоль? На него не распространяется проблема останова, чоль?
Тем более, что вычисления времени компиляции — уже в абстрактном С++ являются тьюринг-полными.
А в голых сях оптимизирующий компилятор тоже может внутри себя поиграть в зависимые типы и уйти в глубокую задумчивость.
(Но обычно для этого принимаются противомеры — отсечка по длине-глубине вычислений).
_>Для хардкорного доказательства теорем это может быть круто. А для сложения-умножения точек _>в каком-нибудь GDI кажется будет перебором.
Для какого-нибудь критичного железа, может, и не будет перебором.
А то история знает ряд дурацких багов в авиации и космонавтике, которые могли быть пойманы сильной типизацией и анализом покрытия кода.
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, T4r4sB, Вы писали:
CC>>>А у нас вон один <censored> сделал LBA знаковым и насрал нам кучу геморроя сделав ну очень геморройным использование старшего бита.
TB>>А что сложного в использовании старшего бита у знакового числа? CC>Он совершенно случайно оказывается нужен для представления обычных, не негативных адресов.
То есть проблема не в наличии знака и не в старшем бите, а в том, что реальные значения адреса бывают и от 2 лярдов до 4 лярдов?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
К>>Почему компилятор должен догадываться, что вот здесь u8+u8 = u8, а вот здесь уже = u9? А последующий u9-u8 — это u8, u9 или i10?
TB>Ну ок, компилятор не должен догадываться. Пусть будет результат u8. А я возьму инт и не буду про это думать? Можно? Нет, нельзя.
В конкретном месте приводи к int и работай с ним, если ты прямо вот уверен, что никогда не выбежишь из разрядной сетки или не схватишь знаковый разряд как обычный.
К>>Если в русте договорились, что тип результата не продвигается без явных указаний, — ну, делай указания.
TB>Проблема в том что в раст коммьюнити считается нормой изнасиловать разработчика этой необходимостью делать указания. И по надежности при этом никакого профита по сравнению с простым хранением интов.
Когда в большом плюсовом проекте включили варнинг компилятора о числовых преобразованиях, — ух, сколько аннотаций пришлось расставить, ты бы знал.
Особенно, когда у тебя, например, две библиотеки геометрии, делающие почти одно и то же, но одна оперирует float (чтобы экономить сетевой и дисковый трафик), а другая double (чтобы гарантированно не терять точность — которая, в общем-то, и нафиг не нужна).
Или одна библиотека использует размеры и индексы типа int (и очень рассчитывает, что там не будет больше 2 миллиардов байтов), а все остальные — size_t (потому что 2 миллиарда байтов вполне встречаются, хоть и не всюду).
Но всякие глупости при этом были пойманы.
И всякое необоснованное смешивание нескольких библиотек было убрано (потому что надоедает аннотировать, проще содержательно вылизать код).
Хотя на первом этапе это и казалось изнасилованием.
К>>Если есть сущность "смещения только в пределах шахматной доски", то — возможно, автору библиотеки или тебе лично, — придётся завести и сущность "расширенные смещения без гарантии, что они влезли в доску".
TB>Да можно. Только эти хипстеры забыли что не надо плодить сущности без необходимости. А необходимости нет — на простых интах жилось ьы намного проще.
К>>Опять же, разрядность этих смещений — "мамой клянусь, i32 мне за глаза и за уши", а вдруг "возьму-ка я float64"?
TB>Переход на плавающие числа это уже радикальное изменение которое требует переписать почти все.
Не всегда.
Например, то же время — можно хранить в наносекундах с начала эпохи, а можно в секундах с микросекундами в дробной части (плавающая точка). А можно — в секундах и наносекундах (фиксированная точка).
И промышленные библиотеки в одном проекте используют все три представления.
К>>А по факту, i128 в большинстве случаев люто избыточно. К>>Если наносекунды с начала эпохи влезают в i64, а ты будешь буферные 64 бита всюду таскать и складывать нули с нулями.
TB>А я не знаю, влезают ли в i64? Там запаса почти нет вродь. Ну если и его хватит то можно и его. Зато голову морочить не надо.
Да, фигня какая, вдвое больше места и вчетверо медленнее вычисления.
К>>Все эти универсальное время, системное, монотонное... это всё разные сущности. Физически разные. К>>std::chrono прямо заставляет тебя сдать экзамен по метрологии, прежде чем ты пойдёшь кодить, — это правда.
TB>Когда я пользовалсяGetTickCount(), time(), rdtsc() и QueryPerformanceCounter() то как то обходился без экзамена. Правда один раз огреб с GetTickCount когда у компа аптайм превысил ограничения типа
Мало огрёб, если не понял, зачем нужен экзамен по метрологии.
Потом откроешь для себя високосные секунды и немонотонное время, и ещё разок огребёшь.
Сильная типизация не спасёт от скачков времени, но будет изолировать куски программы, работающие по разным законам.
К>>А какая физическая природа у суммы двух точек? К>>И как к ней, например, аффинные преобразования применять?
TB>Сумма это промежуточный результвт операции "полусумма" у которой есть смысл. TB>Конечно можно записать это в виде a+(b-a)*0.5, но не всегда. Например тебе надо миллион точек прополусуммировать с данной. Тогда заранее вычислить a*0.5 было бы проще.
Аха, то есть, координаты для промежуточных вычислений (а не только перед финальным округлением) у нас уже полуцелые. Кто тут говорил, что int хватит?
TB>А пользы от данной идеи не вижу. Защииа он неверных значений не имеющих физического смысла типа (a+b)*0.6? Ну так если я напишу a+(b-a)*0.6, то мне станет не легче от того что результат сиал гдето примерно посередине a и b
Почему точка ровно посередине отрезка AB имеет физический смысл, а шестая по счёту точка на гребёнке из десяти засечек — не имеет физический смысл?
Разница между точкой и вектором — в том, что аффинные преобразования с ними делаются по-разному.
Параллельный перенос изменяет точки, но не трогает векторы.
Если у тебя есть аффинный оператор (масштаб*поворот + смещение), то в библиотеке геометрии
— либо ты явно используешь две разные функции оператор_над_точкой(A,P), оператор_над_вектором(A,V)
— либо потрошишь оператор и явно используешь его недра — (A.M*P + A.S), (A.M*V)
— либо же назначаешь точке и вектору разные типы и неявно пользуешься перегрузкой — A*P, A*V
Я вот тоже думал "нафига ввели точку, есть же вектор" — до того момента, как не полез в "промышленную" геометрию.
Так что все эти вещи — выстраданные.
Но никто не мешает в целях оптимизации вообще массив точек распедалить на три массива x, y, z координат и делать всякие векторные вычисления с каждой колонкой независимо.
Просто держишь в голове, что эти три гигантских вектора (или один гигантский тензор) имеет вот такую физическую природу, а потом перегоняешь обратно в естественное представление — россыпь точек.
Здравствуйте, T4r4sB, Вы писали:
TB>То есть проблема не в наличии знака и не в старшем бите, а в том, что реальные значения адреса бывают и от 2 лярдов до 4 лярдов?
Реальные девайсы могут использовать все 64 бита адреса, объявленные в стандарте на протокол.
Реальные адреса в памяти могут находится в сааааамом конце 64битного пространства.
Потому вся эта детская отсебятина с сделаем то, что не бывает отрицательным всё равно signed, чтоб было "удобнее" для меня звучит примерно как "сделаем сердечник электромагнита из дерева для облегчения веса изделия".
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, no_ise, Вы писали:
К>А что, компилятор — не программа, чоль? На него не распространяется проблема останова, чоль? К>Тем более, что вычисления времени компиляции — уже в абстрактном С++ являются тьюринг-полными. К>А в голых сях оптимизирующий компилятор тоже может внутри себя поиграть в зависимые типы и уйти в глубокую задумчивость. К>(Но обычно для этого принимаются противомеры — отсечка по длине-глубине вычислений).
Программа, распространяется, да
Параблемы те же самые, что на уровне что на метауровне, однако.
К>Для какого-нибудь критичного железа, может, и не будет перебором. К>А то история знает ряд дурацких багов в авиации и космонавтике, которые могли быть пойманы сильной типизацией и анализом покрытия кода.
Вот и получается, что где-то много метауровня это хорошо, а где-то Вася за пузырь лучше сделает.
Вопрос в балансе. Сколько и чего вытаскивать на метауровень в разных случаях.
Ну, а если собрать стартап с пресидом 20 лямов, который на айфоне будет показывать какую задачу
лучше с сильной типизацией и анализом покрытия кода делать, а какую Васе делегировать, то там
такая же проблема откроется.
Здравствуйте, no_ise, Вы писали:
_>Ну, а если собрать стартап с пресидом 20 лямов, который на айфоне будет показывать какую задачу _>лучше с сильной типизацией и анализом покрытия кода делать, а какую Васе делегировать, то там _>такая же проблема откроется.
Это и есть проблема останова: что будет, если натравить анализатор на анализатор? (И что будет, если Васю с бутылкой заставить верифицировать код Васи с бутылкой)?
Очевидно, что без двух бутылок тут в любом случае не разберёшься!
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, no_ise, Вы писали:
_>>Ну, а если собрать стартап с пресидом 20 лямов, который на айфоне будет показывать какую задачу _>>лучше с сильной типизацией и анализом покрытия кода делать, а какую Васе делегировать, то там _>>такая же проблема откроется.
К>Это и есть проблема останова: что будет, если натравить анализатор на анализатор? (И что будет, если Васю с бутылкой заставить верифицировать код Васи с бутылкой)?
К>Очевидно, что без двух бутылок тут в любом случае не разберёшься!
Здравствуйте, Кодт, Вы писали:
К>В конкретном месте приводи к int и работай с ним, если ты прямо вот уверен, что никогда не выбежишь из разрядной сетки или не схватишь знаковый разряд как обычный.
Понимаешь, в чём проблема. Если я забуду привести к инту при сложении u8+u8, то я получу падающий код. И компилятор ничего мне на это не скажет. То есть эти ограниченные Strong Types сами порождают грабли, хотя по задумке якобы должны от них защищать. И что самое хреновое — правильный код выглядит грязнее и хуже, чем неправильный но компилирующийся.
К>Когда в большом плюсовом проекте включили варнинг компилятора о числовых преобразованиях, — ух, сколько аннотаций пришлось расставить, ты бы знал.
Я не про то, что неявные преобразования зло. Я про то, что не надо плодить слишком много типов, и боже упаси ограничивать диапазон этих типов.
К>Да, фигня какая, вдвое больше места и вчетверо медленнее вычисления.
Отбрось лишние биты (старшие или младшие — в зависимости от задачи) и будет быстрое время.
К>Аха, то есть, координаты для промежуточных вычислений (а не только перед финальным округлением) у нас уже полуцелые. Кто тут говорил, что int хватит?
Очевидно, что пример с шахматной доской это не тот же пример, что с векторами-точками.
К>Почему точка ровно посередине отрезка AB имеет физический смысл, а шестая по счёту точка на гребёнке из десяти засечек — не имеет физический смысл?
Потому что мне нужен корректный код. Если я опечатался и написал a+(b-a)*0.6, то мне от этого ничуть не легче, чем если бы я написал (a+b)*0.6. Результат в обоих случаях неверен.
Можно поспекулировать на тему, что во втором случае я замечу, что поведение системы меняется в зависимости от расстояния до нуля и поэтому быстрее найду причину бага, но это спекуляции, потому что в разных случаях может быть по-разному.
К>Я вот тоже думал "нафига ввели точку, есть же вектор" — до того момента, как не полез в "промышленную" геометрию. К>Так что все эти вещи — выстраданные.
Что такое "промышленная геометрия"? В популярных библиотеках нет этой шизы.
Если же ты про библиотеки, предназначенные для сверх-надёжного кода для прошивок ядерных реакторов, то надеюсь, что тебе очевидно, что методы, применяемые в этой сфере, категорически не подходят в тех случаях, когда цена ошибки — это максимум потеря правок за последнюю минуту?
И раз уж мы вспомнили про прошивки ядерных реакторов, то давай вернёмся к моему примеру про сложение u8+u8, которое компилятор не отловит. Ну и тогда уж, чтоб намёк про "надёжность" ограниченных типов был понятнее — давай заменим ядерный реактор на ракету Ариан-5
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CreatorCray, Вы писали:
CC>Реальные девайсы могут использовать все 64 бита адреса, объявленные в стандарте на протокол. CC>Реальные адреса в памяти могут находится в сааааамом конце 64битного пространства.
Блин, причём тут знак тогда?! У нас тут для хранения значения используется тип, у которого тупо диапазона не хватает для представления всех значений, причина вообще в другом.
В случае с размером вектора — он не может быть больше чем 2**63-1
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Ну короче тут наверное многие знают, и любой может нагуглить, что такое Primitive Obsession — это когда везде используются инты и строки, и из-за этого иногда случается фигня, когда секунды складываются с килограммами, а в емейл записывается заведомо невалидная строка. TB>А как называется противоположный антипаттерн? Это когда некий долбаный хипстер везде нагородил сраную овертипизацию, из-за которой даже нельзя блин сложить два вектора, потому что складывать можно только вектор и точку, а если таки надо сложить два вектора, то надо после получаса попыток заставить компилятор собрать код таки узнать, что надо использовать my_vector_lib::my_vector::point_cast<my_vector_lib::my_vector::point<std::ratio<1, 1000000000>>> на одном из них? Причём даже если для этой абракадабры есть простой алиас типа my_vector_lib::my_vector::millimeter_cast, то из сообщений компилятора это узнать невозможно, и это надо обязательно зазубрить.
А как называется феномен когда программист принципиально не читает документацию? Узнавать о возможностях библиотеки надо из документации, а не из сообщений компилятора.
Если у библиотеки нет/плохая документация — то за это можно и нужно ее поругать. Так же можно поругать того кто решил такую библиотеку использовать в проекте.
А пытаться изучать библиотеку по ошибкам компилятора... Ну такое.
Здравствуйте, T4r4sB, Вы писали:
TB>Понимаешь, в чём проблема. Если я забуду привести к инту при сложении u8+u8, то я получу падающий код. И компилятор ничего мне на это не скажет. То есть эти ограниченные Strong Types сами порождают грабли, хотя по задумке якобы должны от них защищать. И что самое хреновое — правильный код выглядит грязнее и хуже, чем неправильный но компилирующийся.
Нуу, посмотрел я на то, как ведёт себя руст, — да, соглашусь, это эребор!
Был бы я автором руста, я бы ввёл разные числовые типы — для арифметики в кольце и арифметики в диапазонах.
И ничего бы из них не делал выбором по умолчанию. Чтобы погроммисты сами выбирали себе вид боли.
Хотят получать странные числа в unsafe_i8 — пусть получают. Хотят получать за это по пальцам в strict_i8 — пусть получают.
А ещё лучше — ограничивать диапазоны не степенями 256, а произвольными числами. Как это делается в паскале и аде.
TB>Я не про то, что неявные преобразования зло. Я про то, что не надо плодить слишком много типов, и боже упаси ограничивать диапазон этих типов.
Много разных типов нужны для многих разных целей.
А то вон в сях пихали int куда ни попадя, и что, хорошо, что ли? Особенно, в функции работы с символами.
Где-то это важно для производительности, где-то напротив, важно сказать "компилятор, ну ты сам за меня реши, что лучше на какой платформе".
К>>Да, фигня какая, вдвое больше места и вчетверо медленнее вычисления.
TB>Отбрось лишние биты (старшие или младшие — в зависимости от задачи) и будет быстрое время.
Так с самого начала и отбросили. А если где-то кому-то надо сверхдлинное время — вот пусть ровно там для себя и вводит.
Зачем всех заставлять-то?
К>>Аха, то есть, координаты для промежуточных вычислений (а не только перед финальным округлением) у нас уже полуцелые. Кто тут говорил, что int хватит?
TB>Очевидно, что пример с шахматной доской это не тот же пример, что с векторами-точками.
К>>Почему точка ровно посередине отрезка AB имеет физический смысл, а шестая по счёту точка на гребёнке из десяти засечек — не имеет физический смысл?
TB>Потому что мне нужен корректный код. Если я опечатался и написал a+(b-a)*0.6, то мне от этого ничуть не легче, чем если бы я написал (a+b)*0.6. Результат в обоих случаях неверен. TB>Можно поспекулировать на тему, что во втором случае я замечу, что поведение системы меняется в зависимости от расстояния до нуля и поэтому быстрее найду причину бага, но это спекуляции, потому что в разных случаях может быть по-разному.
Насчёт легче или нет — это именно спекуляции.
Но в одном случае ты делаешь линейную интерполяцию с неправильным коэффициентом (хотел 0.7 или 0.5, рука дрогнула, подставил 0.6), а в другом — создаёшь неверную сущность, хотя для какой-нибудь фрактальной геометрии, возможно, она и пригодится.
Если тебя бесит, что в симметричной формуле линейной интерполяции появляется внутренняя асимметрия, — одна из точек становится важнее другой, — ну спрячь формулу в функцию.
Point interpolate(Point a, Point b, float ratio) { return a + (b-a) * ratio; }
Point midpoint(Point a, Point b) { return interpolate(a, b, 0.5); }
Point midpoint(vector<Point> points) { return points[0] + sum(points - points[0]) / size(points); } // псевдокод
А то, что interpolate(a,b,r) == interpolate(b,a,1-r), что симметрия там не вокруг 0, а вокруг 0.5 — ну блин извините! Сделай вокруг нуля
Point around_midpoint(Point a, Point b, float deviation) { return interpolate(a, b, deviation + 0.5); } // или свою реализацию по вкусу
Зачем при этом воевать против системы типов-то?
Наоборот, система типов не даст тебе облажаться в попытках колхозной интерполяции (a+b)/2 или (a+b+c+d+e)/5 вместо библиотечной.
К>>Я вот тоже думал "нафига ввели точку, есть же вектор" — до того момента, как не полез в "промышленную" геометрию. К>>Так что все эти вещи — выстраданные.
TB>Что такое "промышленная геометрия"? В популярных библиотеках нет этой шизы. TB>Если же ты про библиотеки, предназначенные для сверх-надёжного кода для прошивок ядерных реакторов, то надеюсь, что тебе очевидно, что методы, применяемые в этой сфере, категорически не подходят в тех случаях, когда цена ошибки — это максимум потеря правок за последнюю минуту?
TB>И раз уж мы вспомнили про прошивки ядерных реакторов, то давай вернёмся к моему примеру про сложение u8+u8, которое компилятор не отловит. Ну и тогда уж, чтоб намёк про "надёжность" ограниченных типов был понятнее — давай заменим ядерный реактор на ракету Ариан-5
Я про библиотеки, используемые в промышленной робототехнике, — в ROS.
И давай не мешать в кучу арифметику чисел (и несчастный ариан) и типизацию структур (векторы и точки).
Если бы разработчики ариана использовали векторы и накосячили в аффинных преобразованиях, это было бы не менее эпично.
Здравствуйте, Кодт, Вы писали:
К>Хотят получать странные числа в unsafe_i8 — пусть получают
Да даже незачем называть этот тип unsafe_i8, можно назвать его looped_i8.
К>А ещё лучше — ограничивать диапазоны не степенями 256, а произвольными числами. Как это делается в паскале и аде
Тогда возникает вопрос, какой тип должен быть у Integer<1..2> + Integer<3..4>? И допустимо ли их сложение?
Число по здравому смыслу это должен быть Integer<4..6>, но из-за ограничений платформы на деле получается, что в Расте
Integer<0..255> + Integer<0..255> имеет тип Integer<0..255> а вовсе не Integer<0..510> как должно быть.
К>Где-то это важно для производительности, где-то напротив, важно сказать "компилятор, ну ты сам за меня реши, что лучше на какой платформе".
В целом подход сей с кастом всего и вся к инту мне кажется каким-то неконсистентным, тут я солгасен.
TB>>Отбрось лишние биты (старшие или младшие — в зависимости от задачи) и будет быстрое время.
К>Так с самого начала и отбросили. А если где-то кому-то надо сверхдлинное время — вот пусть ровно там для себя и вводит. К>Зачем всех заставлять-то?
Мне всегда казалось, что правило, которое выводится прямой логикой, всегда намного легче для понимания и усвоения, чем правило, которое необходимо зубрить. По-моему, это очевидно, что для получения секунд из наносекунд надо поделить на 10**9
ции, потому что в разных случаях может быть по-разному.
К>Насчёт легче или нет — это именно спекуляции. К>Но в одном случае ты делаешь линейную интерполяцию с неправильным коэффициентом (хотел 0.7 или 0.5, рука дрогнула, подставил 0.6), а в другом — создаёшь неверную сущность, хотя для какой-нибудь фрактальной геометрии, возможно, она и пригодится.
Дык я в любом случае из-за опечатки имею неверный результат. И мне ничуть не легче от того, что он "немного по-другому" неверный.
"Раньше люди добрее были. Никого не убивали. А если и убивали, то как-то по-доброму что ли".
К>Если тебя бесит, что в симметричной формуле линейной интерполяции появляется внутренняя асимметрия, — одна из точек становится важнее другой, — ну спрячь формулу в функцию.
Меня бесит, что для задачи
auto half_of_center = center * 0.5;
for (auto& p: points) {
p = p * 0.5 + half_of_center ;
}
мне придётся делать лишнее сложение во внутреннем цикле в случае использования "типобезопасной" библиотеки. И это я вспомнил лишь самую простую формулу.
К>Я про библиотеки, используемые в промышленной робототехнике, — в ROS.
Лично я такие не использовал, но кто пользовался из моих знакомых — отзывы что разделение точек и векторов это бесполезный геморрой для программиста, не дающий никакой пользы.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Кодт, Вы писали:
К>соглашусь, это эребор!
С гномами и барлогами, да!
К>Хотят получать странные числа в unsafe_i8 — пусть получают. Хотят получать за это по пальцам в strict_i8 — пусть получают.
+1
К>А ещё лучше — ограничивать диапазоны не степенями 256, а произвольными числами. Как это делается в паскале и аде.
Чтоб фейерверки от взрывающихся пуканов были повеселее.
К>А то вон в сях пихали int куда ни попадя, и что, хорошо, что ли?
Нет, безумие получилось.
К>Так с самого начала и отбросили. А если где-то кому-то надо сверхдлинное время — вот пусть ровно там для себя и вводит.
+1
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Константин Б., Вы писали:
КБ>А как называется феномен когда программист принципиально не читает документацию? Узнавать о возможностях библиотеки надо из документации, а не из сообщений компилятора. КБ>Если у библиотеки нет/плохая документация — то за это можно и нужно ее поругать. Так же можно поругать того кто решил такую библиотеку использовать в проекте. КБ>А пытаться изучать библиотеку по ошибкам компилятора... Ну такое.
Каждую документацию надо начинать словами "Ну что, с наскоку не получилось?" (С)
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, T4r4sB, Вы писали:
TB>но из-за ограничений платформы на деле получается
Это не ограничения платформы а реальность, данная нам в ощуплении (tm)
Ибо каждый язык это всего лишь более удобный способ выразить логику программы чем писать в машкодах. И они все должны ложиться на архитектуру платформы.
Когда про это забывают — получается бардак и страдания.
TB>Integer<0..255> + Integer<0..255> имеет тип Integer<0..255> а вовсе не Integer<0..510> как должно быть.
Кому должно?
Это как кричать что неправильно что у человеков две руки а должно быть четыре!
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
CC>Кому должно?
Математике. Если в школе дать задачу, типа есть вот два числа из диапазона [0..255], то в каком диапазоне будет их результат, то любой первоклассник сможет вычислить, что результат попадёт в диапазон [0..510]. И было бы удобно, если бы система типов соответствовала математике. Но так как это не так, то из-за забытого каста имеем программу, падающую на валидных данных.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Математике.
Математика имеет такой интересный раздел как Rings и в частности подраздел Modular arithmetic
Потрудитесь ознакомиться.
TB>И было бы удобно, если бы система типов соответствовала математике.
И было бы удобно если бы количество пальцев соответствовало абстрактным моделям, вот только реальность не соглашается прогибаться под теорию.
TB> Но так как это не так, то из-за забытого каста имеем программу, падающую на валидных данных.
Не надо перекладывать рукожопие погромиста, не понимающего что он творит, на железо, которое просто делает как ему было погромистом сказано.
Garbage in — garbage out.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
CC>Математика имеет такой интересный раздел как Rings и в частности подраздел Modular arithmetic CC>Потрудитесь ознакомиться.
При написании кода в подавляющем большинстве случаев программист подразумевает обычную арифметику, и что на валидных данных никогда не случится арифметического переполнения.
И в русте арифметика не модульная.
CC>Не надо перекладывать рукожопие погромиста, не понимающего что он творит, на железо, которое просто делает как ему было погромистом сказано.
То есть ты утверждаешь, что опечаток не бывает, а бывают лишь ошибки, вызыванные непониманием?
Странно, я думал, что только в школе остались кульные какиры, которые думают, что всегда всё контролируют и что уж они-то никогда не уронят программу из-за случайно забытого символа или не отлавливаемой компилятором опечатки.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>И в русте арифметика не модульная.
В процессоре — модульная.
TB>То есть ты утверждаешь, что опечаток не бывает, а бывают лишь ошибки, вызыванные непониманием?
Очепятка это когда написали чутка не то, а не дыра в логике.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
CC>В процессоре — модульная.
И что с того, что что-то там в процессоре, теперь на асме писать, чтобы было как "в процессоре"? Мне казалось, что обязанность высокоуровнего ЯП это предоставление удобных абстракций. Если абстракция протекает и из-за случайной опечатки это приводит к падающей программе, то это дыра в дизайне.
CC>Очепятка это когда написали чутка не то, а не дыра в логике.
Забыть поставить каст к более широкому типу — это тоже опечатка.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Кодт, Вы писали:
К>Был бы я автором руста, я бы ввёл разные числовые типы — для арифметики в кольце и арифметики в диапазонах.
Примерно так и сделали: https://doc.rust-lang.org/std/num/struct.Wrapping.html
Ну и при необходимости локально можно использовать конкретные операции с нужным поведением: wrapping/checked/saturating/overflowing. Писать так весь код мало кто захотел бы, поэтому стандартное поведение и такое: паника в дебаге (чтобы был таки шанс поймать ошибку) и аналог Wrapping в релизе (с возможностью включить таки проверки).
К>А ещё лучше — ограничивать диапазоны не степенями 256, а произвольными числами. Как это делается в паскале и аде.
Здравствуйте, T4r4sB, Вы писали:
CC>>В процессоре — модульная. TB>И что с того, что что-то там в процессоре
К тому что принципы как оно будет на самом деле выполняться надо таки понимать.
TB> Если абстракция протекает и из-за случайной опечатки это приводит к падающей программе, то это дыра в дизайне.
Ну т.е. тебе тут надо памперсы ChatGPT чтоб за погромиста не забывал сделать то, что надо сделать, для получения ожидаемого результата.
Мдаааа, похоже эта нейросетка таки сможет выгнать на мороз куда больше херак-херак-и-в-продакшен маппетов чем ожидалось.
TB>Забыть поставить каст к более широкому типу — это тоже опечатка.
Очепяткой это было бы есди не к тому типу закастили.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
CC>К тому что принципы как оно будет на самом деле выполняться надо таки понимать.
И каким образом понимание избавит от опечатки? Кульные какиры никогда не опечатываются?
CC>Ну т.е. тебе тут надо памперсы ChatGPT чтоб за погромиста не забывал сделать то, что надо сделать, для получения ожидаемого результата. CC>Мдаааа, похоже эта нейросетка таки сможет выгнать на мороз куда больше херак-херак-и-в-продакшен маппетов чем ожидалось.
Просто у меня хватает мозгов заметить, что на меня тоже распростреняется человеческий фактор.
CC>Очепяткой это было бы есди не к тому типу закастили.
Если компилятор ни слова не говорит про отсутствующий каст, то случайно забыть сделать каст может любой программист с любым опытом. Ну кроме кульного какира из 9Б, который никогда нигде не ошибается.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, T4r4sB, Вы писали:
TB>>Если компилятор ни слова не говорит про отсутствующий каст CC>Ну разишо если warnings игнорировать.
И какой же варнинг у тебя проявится при сложении двух u8? Или при вычитании двух usize?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>В том же русте не так. Ты можешь сложить числа 100 и 200, но если оба аргумента имеют тип u8, то компилятор тебе ничего не скажет. Типа всё ок. Но ты получишь падающую программу, из-за чего матерясь полезешь явно кастить оба аргумента к i32. Ну и нахрена оно надо, изначально-то чего в i32 не хранится?
А почему ты тут думаешь именно про i32? А вдруг и его переполнит, тогда оно должно было святым духом догадаться, что надо было конвертить всё к i64? Или как?
Сложили два int32_t, получим int33_t?
Перемножаем. Первое произведение int64_t, второе int96_t, третье int128_t... Астанавитесь(c), Вите надо выйти!
Я понимаю твой плач, но проблема в том, что при столкновении заведомо противоречивых требований между автопредставлением всех значений именно с нужным размахом — с реальными ограничениями используемых числовых типов — нужно выбирать какой-то компромиссный вариант, и это именно случай эскобара.
Можно 1) влупить в лоб сразу, как в Rust, 2) маскировать проблему подольше, как в C/C++, 3) уходить от неё ценой производительности, как в Python и Erlang. Возможно, ещё как-то можно.
В Rust хорошо, что, в отличие от C/C++, тебе явно показывают проблему и дают средства её решения прямым и легкопонятным способом.
Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.
Я видел кучу кода, где, например, берут из переменной типа u8 (uint8_t) количество элементов, а затем итерируют по нему опять же переменной типа u8. Это, да, безграмотно.
TB> Нахрен мне нужно ограничение, при котором предполагается, что промежуточный результат будет иметь те же ограничения, что и сами данные, если это вообще даже близко не так? И тогда зачем вообще ограничивать тип, когда проще все эти проверки делать в сеттере поля?
Повторюсь, в C с int или long то же самое. И вообще это ещё из Фортрана растёт, как минимум. Ничто не ново под луною.
Нахрена в нём два (минимум) уровня integral promotion — не знаю, оно таки сомнительно. Как и его ценность сейчас вообще. Но зачем его делали в далёких 70-х — очевидно.
TB>И получаем либу, с которой невозможно работать без часового курения документации.
Ну chrono это отдельная пейсТня.
TB> А по факту было бы достаточно одной-единственной функции, возвращающей число наносекунд с начала эпохи в виде примитивного типа i128 (знаковый, чтоб можно было вычитать два момента и не париться).
Но тут другое. С какой именно эпохи? Юниксовой (начало 1970 года) или виндовой (1601)?
А может, с "юлианского дня" номер 1, как сделали в Delphi?
К>>Долбаный хипстер ввёл Point, Vector и Rotation, а людям расхлёбывать, да? А может, людям за чистотой своих рук последить, прежде чем Point+Point или Point+Rotation делать, не?
Чем дальше в лес, тем толще партизаны код, тем сложнее следить за его качеством, включая 100500 аспектов, которые могут на него повлиять, и тем дороже каждое изменение. Поэтому средства поддержки в виде запрета некорректных операций — бесценны.
TB>Point+Point это нормальная операция, не надо её запрещать.
Надо.
TB>Пример с размерностями матрицы — это положительный пример внедрения гарантий времени компиляции. Полагаю, с таких примеров и начались хорошие идеи по возможности проконтролировать что-то заранее на уровне системы типов. Но заставь дурака богу молиться, и он сделает систему, в которой очень трудно написать что-то полезное.
TB>> Если абстракция протекает и из-за случайной опечатки это приводит к падающей программе, то это дыра в дизайне. CC>Ну т.е. тебе тут надо памперсы ChatGPT чтоб за погромиста не забывал сделать то, что надо сделать, для получения ожидаемого результата. CC>Мдаааа, похоже эта нейросетка таки сможет выгнать на мороз куда больше херак-херак-и-в-продакшен маппетов чем ожидалось.
Судя по принципиальному непониманию проблемы, кое-кто полетит одним из первых — потому что учёт всех обстоятельств в сложном коде это даже для человека с опытом неподъёмно, а такой сетке точно ещё лет 50 расти до нужного уровня.
Здравствуйте, T4r4sB, Вы писали:
S>>А насколько часто у вас встречаются диапазонные типы? Ну, так, если по-честному? TB>На Русте какой-то идиот ввёл для размера массива тип usize, мотивируя это тем, что ограничение >=0 "соответствует специфике домена", при этом на вопрос что делать если надо вычитать два размера, мне сказали "мне никогда это не надо было делать". Дальше разгорелся срач, я привёл пример с шахматной доской 256х256, и спросил, реально ли они ради дебильной идеи сраных доменов будут использовать u8, понимая, что тривиальные операции будет делать крайне геморройно, и они сказали что да.
Здравствуйте, netch80, Вы писали:
N>Судя по принципиальному непониманию проблемы, кое-кто полетит одним из первых
Куда проще заменять нейросеткой пейсателей на памперсных языках, где памперсы примут в себя все косяки нейросетки, чем там, где надо чётко понимать что ты делаешь.
Кстати интересно, осилит ли нейросетка написать double linked list на rust?
N> потому что учёт всех обстоятельств в сложном коде это даже для человека с опытом неподъёмно
Не в сложном коде а в говнокоде, где ни декомпозиции, ни дизайна, ни комментов, рубили вместе с будкой писали как попало.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
N>>Судя по принципиальному непониманию проблемы, кое-кто полетит одним из первых CC>Куда проще заменять нейросеткой пейсателей на памперсных языках, где памперсы примут в себя все косяки нейросетки,
Проще, да. Но такие языки ещё надо разработать (хм, интересное направление)
AMM+GC это слишком низкоуровнево.
А вот безразмерный int это уже ближе к вопросу.
CC> чем там, где надо чётко понимать что ты делаешь. CC>Кстати интересно, осилит ли нейросетка написать double linked list на rust?
Текущие — скорее нет, а зачем?
N>> потому что учёт всех обстоятельств в сложном коде это даже для человека с опытом неподъёмно CC>Не в сложном коде а в говнокоде, где ни декомпозиции, ни дизайна, ни комментов, рубили вместе с будкой писали как попало.
Здравствуйте, CreatorCray, Вы писали:
CC>Здравствуйте, netch80, Вы писали:
N>>Судя по принципиальному непониманию проблемы, кое-кто полетит одним из первых CC>Куда проще заменять нейросеткой пейсателей на памперсных языках, где памперсы примут в себя все косяки нейросетки, чем там, где надо чётко понимать что ты делаешь.
Сколько раз вас, кулхацкеров, надо ударить головой, чтоб вы поняли, что есть такое явление как случайные опечатки по невнимательности?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
хъ
N>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.
Хм, я что-то пропустил и (в x86-64 например) из RAX куда-то исчезли AL/AX/EAX и команды умеющие с ними работать?
Здравствуйте, netch80, Вы писали:
N>А вот безразмерный int это уже ближе к вопросу.
Не ну всегда можно сделать язык в котором int будет подкапотно реализован через BigInteger а не POD типом, замапленным на платформенный тип.
С производительностью будут некоторые вопросы, но зато говнокодеру не надо будет думать.
CC>>Кстати интересно, осилит ли нейросетка написать double linked list на rust? N>Текущие — скорее нет, а зачем?
Просто интересно. Впрочем они "умеют" то, примеры чего уже есть в интернетах, так что скорее всего оно просто выдаст "переизобретение" уже написанного ранее.
N>А декомпозицию перекладываешь на человека? Читер.
А дизайном и декомпозицией должен заниматься инженер, больше некому.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, T4r4sB, Вы писали:
TB>Сколько раз вас, кулхацкеров, надо ударить головой, чтоб вы поняли, что есть такое явление как случайные опечатки по невнимательности?
Я уже достаточно долго живу чтоб воспринимать отмазку про подобные случайные очепятки это в стиле "хотел сказать "дорогая, передай пожалуйста соль" а сказал "что ж ты сука мне всю жизнь испортила!" "
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Patalog, Вы писали:
N>>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно.
P>Хм, я что-то пропустил и (в x86-64 например) из RAX куда-то исчезли AL/AX/EAX и команды умеющие с ними работать?
Команды — есть. Упаковка разных параметров в один регистр в ABI — нет (с редкими особыми исключениями). Хранение в процессе использования внутри функции разных параметров, например, рядом в AL и AH — тоже нет, компиляторы такое не делают — им это ломает логику распределения регистров.
В ARM/32 регистры векторов и плавучки устроены так, что, например, D0 состоит из S0 и S1. В MIPS/64 регистры для 64-битных значений это пара 32-битных. Количество и кривость костылей для поддержки этого оказались такими, что повторять этот гимор никто не хочет. В ARM/64, RISC-V это тоже не повторили.
Преимущества манипулирования 8-битным значением в AL вместо 32-битного в EAX или 64-битного в RAX давно нет. Скорее наоборот — из-за проблемы, что комбинирование со старым значением сокращает возможности параллеления на переименовании регистров.
Здравствуйте, 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
К сожалению, мой низкий уровень инглиша и фанатизм сообщества не позволили обратить внимание на проблему(
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CreatorCray, Вы писали:
CC>Я уже достаточно долго живу чтоб воспринимать отмазку про подобные случайные очепятки это в стиле "хотел сказать "дорогая, передай пожалуйста соль" а сказал "что ж ты сука мне всю жизнь испортила!" "
Я достаточно долго работаю, чтоб видеть, как люди, в квалификации которых я не сомневаюсь, иногда выдают в код полнейшую дичь, которая проходит тесты, но при определённых условиях заполняет память мусором. Просто по запарке. А вот с тобой есть сомнения.
И если компилятор ничего не скажет, то всегда есть шанс, что программист с любым уровнем квалификации чисто случайно вместо
((a as i32 + b as i32) / 2).try_into().unwrap()
напишет
(a+b)/2
А идеология руста с ограничениями на типы требует постоянно писать хрень как в первом коде. И не дай бог забудешь про каст в широкий тип — компилятор ничего не скажет, а программа упадёт. Руст умеет сделать безопасный код опасным.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
хъ
P>>Хм, я что-то пропустил и (в x86-64 например) из RAX куда-то исчезли AL/AX/EAX и команды умеющие с ними работать?
N>Команды — есть. Упаковка разных параметров в один регистр в ABI — нет (с редкими особыми исключениями).
Ну, это явно не наш случай, коль речь про сложении двух чисел или забег по массиву.
N>Хранение в процессе использования внутри функции разных параметров, например, рядом в AL и AH — тоже нет, компиляторы такое не делают — им это ломает логику распределения регистров.
Тут не буду спорить, но когда я последний раз глядел в эту сторону (году этак в 12-13м) — вполне себе видел код со всеми этими прелестями EAXов уж точно, насчет AH/AL в свеже сгенеренном коде врать не буду, не помню, а вот в каких-то из системных библиотек 7-ки, в котором приходилось ковырятся отладчиком (была тема самопального PE загрузчика) — точно были.
Здравствуйте, T4r4sB, Вы писали:
TB>Я достаточно долго работаю, чтоб видеть, как люди, в квалификации которых я не сомневаюсь, иногда выдают в код полнейшую дичь, которая проходит тесты, но при определённых условиях заполняет память мусором. Просто по запарке.
За последние 20+ лет я ни разу не видел чтоб квалифицированные люди спороли что нить подобное "по запарке"
TB>А идеология руста с ограничениями на типы требует постоянно писать хрень как в первом коде.
Печальный язык.
TB> И не дай бог забудешь про каст в широкий тип — компилятор ничего не скажет, а программа упадёт.
Когда программа откровенно делает то, что от неё не ждали — программе лучше упасть чем спрятать какашку в памперс. Были моменты когда приходилось откровенные panic в кернеловский код вставлять вместо сообщения об ошибке, когда QA попытались заметать найденные баги под коврик.
TB>Руст умеет сделать безопасный код опасным.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
N>>А вот безразмерный int это уже ближе к вопросу. CC>Не ну всегда можно сделать язык в котором int будет подкапотно реализован через BigInteger а не POD типом, замапленным на платформенный тип. CC>С производительностью будут некоторые вопросы, но зато говнокодеру не надо будет думать.
И чё? (tm)
Для ~95% кода типичного приложения это нормально, от него высокой производительности не требуется. Зато то, как его пишут, вынуждает использовать защищённые средства по максимуму, чтобы работало.
И как минимум в половине случаев это не "говнокодер", а говноменеджмент с говнопроцедурами, услужливо выгибающийся под давлением говнодиректоров, реализующих планы на основании говнотребований говноинвесторов и не обеспечивающий минимальных ресурсов на качественную разработку. Кодеры тут последние, кто виноват.
Ты часом не менеджер? А то только и слышу от тебя наезды на "говнокодеров".
N>>А декомпозицию перекладываешь на человека? Читер. CC>А дизайном и декомпозицией должен заниматься инженер, больше некому.
Здравствуйте, T4r4sB, Вы писали:
N>>Перемножаем. Первое произведение int64_t, второе int96_t, третье int128_t... Астанавитесь(c), Вите надо выйти! TB>Перемножение в цикле — это проблема, да, тут увы приходится задать одно ограничение на результат и в каждой итерации следить что вписываемся.
Так нет принципиальной разницы со сложением или вычитанием. Сложил два int32_t, получил int33_t. Прибавил к нему int32_t, можешь формально получить int34_t. И так далее.
Даже если транслятор не оперирует напрямую такими типами (LLVM — может, там любая битность допустима почти до самой зашкальной), то подсчёт диапазонов значений может к такому привести.
Потому возвращаемся к исходному — или своевременный контроль, или наплевательство, или явное разрешение усечения (а местами — насыщения, saturating mode), или, как в С для знаковых, доверие программисту. Но на чём-то надо остановиться.
Почему я постоянно и говорю — кто лучше знает, что именно тут надо, кроме автора кода? А раз он знает — может и должен явно указать. А компилятор должен позволять такие указания и правильно их отрабатывать.
N>>А почему ты тут думаешь именно про i32? А вдруг и его переполнит, тогда оно должно было святым духом догадаться, что надо было конвертить всё к i64? Или как? TB>В идеале — ограничивать операнды, чтобы компилятор знал, что результат впишется в i32.
Не будет такого идеала. В общем случае ты можешь просто не знать заранее, впишутся они или нет.
Исключения (паника) в рантайме — простой, надёжный, хоть и дорогой, метод получить тут гарантии вместе со стандартизованной (а часто и структурированной) обработкой ошибок.
Они сами по себе не проблема. Проблема — когда забывают обрабатывать ошибки, или административно не дают на это ресурсов, или когда (как ты описываешь) неудобно и громоздко всё конвертировать к адекватным типам.
Но именно в последнем случае — удобно или использовать стандартное "продвижение" целого (integral promotion), как в C/C++/много_где, или самим предварительно расширить все рабочие значения. Иногда этого расширения не хватает, увы. Но по крайней мере в твоём примере с u8 должно хватить.
N>>Да, и вдогонку — а действительно, почему у тебя они в u8? Это же тип скорее для упаковки в структуру, чем для манипулирования. Во всех современных ABI всё равно будет один регистр занят, так что u8 или i32 — одномайственно. TB>Ещё раз с самого начала — если у тебя шахматная доска 256х256, то для координат фигуры нормальный человек конечно же будет использовать int. Но с точки зрения хипстера, обдолбавшегося доменно-ориентированной хренотой, использовать int это неправильно, надо использовать тип, который в принципе не может содержать некорректных значений. Не знаю зачем ему это надо, но он считает, что это круто.
У тебя тут принципиально проблемные переходы:
1. От типа, который содержит только корректные значения (что правильно) — к конкретным вариантам типа u8. Какое твоё нафиг дело на этом уровне, сколько в нём бит? Может, у него вообще два корректных значения +238 и -245. Сколько ты на него бит выделишь — 1, 9, 16, 32? Пусть компилятор думает об этом, у него голова большая быстрее считает.
2. От диапазона значений конкретного базового типа вроде i32 ты переходишь к тому, как выполняются операции с ним. И вот тут, предполагая, что i32+i32 даёт i32, ты почему-то пытаешься получить, что 0..255 + 0..255 должен дать 0..510, а из этого — что i8+i8 даёт i9. Но почему тогда i32+i32 не должно дать i33? (см. выше)
Посмотри в этом смысле на Ada. Там можно определять типы в стиле
type chess_coord = Integer range 0..255;
После этого, насколько помню, в вычислениях используется продвижение целых до Integer (или, если сказано явно, до LongInt), контролируется переполнение согласно этому размеру, но при укладке в переменную проверяется диапазон (ну кроме если компилятор уверен, что выхода за его пределы не будет). Выглядит удобно и средне-разумно, позволяя отрабатывать максимум типовых ситуаций безболезненно и контролируемо.
(А для нужд всяких кольцевых счётчиков там есть типы целых в стиле "modulo 2**32". Вот с ними операции выполняются в модульной арифметике, как беззнаковые в C/C++.)
TB> Ну типа в функции figure.place(u8 x, u8 y) мы на этапе компиляции знаем что значения валидны! При этом хипстеру насрать, что код валидации просто будет вынесен из сеттера во все места, где мы вычисляем эти координаты и никакого выигрыша мы не получим,
Меняю мысленно u8 на "integer range 0..255". Вообще-то получим выигрыш: точно не будет молчаливого усечения значения. А какая цена проверок — зависит от компилятора. Во многих случаях он может их просто выкинуть.
TB> более того, мы создаём грабли, если напишем figure1.x — figure2.y, случайно забыв скастовать в инт.
Вполне себе аргумент в пользу удобства integral promotion для типовых операций. Но, с другой стороны, операция получения разности координат это особая операция, при которой меняется тип. Это было ещё в C: можно вычитать два однотипных указателя, получим разность между ними (причём разность адресов делится на размер указуемого). Почему не сделать такое же?
Причём это надо делать (в синтаксисе C++/GCC) так:
using coord_t = uint_t<8>;
using coord_diff_t = int_t<9>;
inline coord_diff_t operator-(coord_t a, coord_t b) {
coord_diff_t ret;
__builtin_sub_overflow(a, b, &ret); // No overflow happensreturn ret;
}
Ну а дальше у тебя будет просто figure1.x — figure2.y которое молча под капотом правильно выполнится.
TB> Кулхацкеры конечно же никогда (на словах) не забывают сделать лишний каст,
"Кулхацкеры" — да, возможно.
Нормальные хакеры сделают, как я описал выше, и забудут про проблему.
Rust это позволяет, но я не хочу выгибаться вспоминать, как в нём это делается. Но концептуально это 1:1 описанный подход C++.
N>>Чем дальше в лес, тем толще партизаны код, тем сложнее следить за его качеством, включая 100500 аспектов, которые могут на него повлиять, и тем дороже каждое изменение. Поэтому средства поддержки в виде запрета некорректных операций — бесценны.
TB>А вот и нет. Лишние запреты со стороны компилятора почему-то воспринимаются как абсолютное добро, но это не так. Во-первых, не все пишут прошивки для ядерных реакторов, я б сказал, что подавляющее большинство пишет код, в котором не требуется абсолютная надёжность.
Подавляющее большинство пишет код, в котором проверки надёжности несущественно влияют на скорость и объём. А те 1-5%, которые пишут критичный к этому код в отдельных местах, заинтересованы в специальных опциях ради этого ровно в этих отдельных местах.
Я недавно с одним проектом работал, в котором принципиально -O0 во всех компиляциях. Ничего, ресурсов хватало (управляющий слой над железкой). Создатели решили, что это лучше, чем бодаться с возможными проблемами даже от простого -O (не знаю, было ли тогда -Og, но они и его не включили).
А вот диагностика ситуации "процесс X не отработал запрос потому, что в этот момент упал процесс Y, а проверка криво сделана в промежуточном процессе Z, который выдал неполные данные" может обойтись на порядки дороже, чем однократное корректное написание. Особенно если это у субкастомера кастомера в пределах концерна-клиента.
Лучше пусть оно диагностируемо упадёт, чем выдаст неправильные данные.
TB> От падения программы просто завершится один процесс и в документ не попадут изменения за последнюю минуту. Память других программ не попортится, это не ДОС с убогим реальным
От падения — да, вероятно — и см. выше какие сценарии бывают (и я это реально видел).
А если оно молча выдаст неверные данные?
TB> режимом. Ещё со времён 386 процессора с его менеджером памяти уже есть абстракция, в которой любая программа, работающая с правами пользователя, уже является безопасной.
Нет.
И вообще, я не понимаю — выше ты против того, чтобы u8 + u8 проверялось на выход за пределы диапазона u8 — а теперь что? Ты уж определись.
TB> И если время, затрачиваемое на борьбу с компилятором больше, чем время, затрачиваемое на обнаружение и устранение бага — то лишние сложности в написании кода не только создают лишний гемор при написании и особенно рефакторинге, но и просто увеличат время создания работающего продукта. К сожалению, эпоха, когда средства повышения надёжности кода повышали и удобство программера, прошла.
Не прошла. Но многие из теперешних метаний выглядят, согласен, бессмысленными.
TB>Во-вторых, не все, что якобы повышает надёжность, действительно её повышает. TB>Вот те же вектора-точки. Допустим, я использую старпёрскую идеологически невыдержанную библиотеку, где вектор и точка это одно и то же. TB>Есть точка V. А есть плоскость, заданная уравнением V*N+C=0. И чтоб понять, с какой стороны точка находится от плоскости, я блин беру, и смотрю на знак этого самого V*N+C. TB>Как выглядит эта ситуация, если векторы и точки это разные сущности?! Я вижу два варианта: TB>1. Плоскость задаётся уравнением (P-C)*N=0, где P,C это точки, а N это вектор. Но тогда вычисление этой фигни как минимум требует лишние два вычитания. TB>2. Плоскость задаётся уравнением V*N+C=0, а чтоб понять, с какой стороны от этой плоскости находится точка, надо вычислить TB>(P-ZeroPoint)*N+C. И тут я боюсь, что любая мало-мальски сложная формула сведётся к бесконечным (P-ZeroPoint) вместо V, ну и в итоге формула будет содержать те же самые выражения, и при этом ошибиться в наборе формулы можно будет ровно в тех же местах. Более того, из-за ухудшившейся читаемости пропустить опечатку станет даже проще, и компилятор ничего не скажет.
Возможно, я что-то упускаю, но почему не создать промежуточную переменную типа "вектор", которая, по твоим описаниям, будет равна P-ZeroPoint, адекватно назвать её и дальше использовать в формулах?
(Причём при нормальной оптимизации компилятор операцию вида P-ZerPoint внутри себя превратит в копирование скаляров, потом проведёт через SSA, устранив копирования.)
>> Для архива оставлю ссылку. (ты там активно участвовал) TB>Спасибо, добавлю ещё это: https://internals.rust-lang.org/t/subscripts-and-sizes-should-be-signed/17699 TB>К сожалению, мой низкий уровень инглиша и фанатизм сообщества не позволили обратить внимание на проблему(
Почитал. Английский действительно так себе, но на дискуссию, по-моему, это не повлияло совсем. Там и хуже пишут (не в оправдание). Явного фанатизма я тоже не заметил. Что заметил:
1) Есть уже принятые решения (может, и преждевременно), которые менять сложно без полного слома языка: сохранение типа в операциях (что u8*u8 -> u8) и беззнаковый размер (даже если фактически не выходит за пределы знакового).
2) Есть масса приёмов (там приведены в примерах), которые дают возможность избежать подавляющего большинства проблем от этих решений.
Вообще их ответы очень интересны именно этими примерами.
Я лично бы сделал, да, integral promotions контекстно-устанавливаемыми. Но я плохо представляю себе, как это сочетать с дизайном языка. Вот пишешь ты impl для одного своего типа... нужны разные варианты функций в зависимости от этих параметров контекста? Компилятор должен уметь подбирать эти типы? Жестоко.
Здравствуйте, Patalog, Вы писали:
N>>Хранение в процессе использования внутри функции разных параметров, например, рядом в AL и AH — тоже нет, компиляторы такое не делают — им это ломает логику распределения регистров.
P>Тут не буду спорить, но когда я последний раз глядел в эту сторону (году этак в 12-13м) — вполне себе видел код со всеми этими прелестями EAXов уж точно,
Именно для x86 тут есть принципиальная разница:
1. Большинство команд в 32-битном варианте короче (нет REX префикса).
2. Исполнение команды над 32-битными версиями регистров чистит старшие 32 бита регистра, поэтому зависимости от предыдущего значения архитектурного регистра не создаётся. А вот для операций с xL, xH, xX (x=A,B,C,D), SIL, DIL... чистки верхней части не происходит, это специфическое наследие x86 из 1980-х, когда они об этом не думали. (Почему не думали — не знаю, OoO с переименованием регистров растёт минимум из 1969, но у Intel собственная гордость.)
Поэтому оптимизация с работой с EAX вместо RAX и т.п. — полезна, а с AX, AL, AH — уже (почти всегда) нет.
Работу с AH можно найти или в ручном ассемблерном коде, или в результате peephole-оптимизаций, где, например, b = a>>8; заменяется на извлечение AH (и то, только в случае если значение уже сидит в регистре, а писать в память).
Типовые более современные RISC-архитектуры (ARM, RISC-V) не имеют подобной специфики потому, что у них вообще нет неполной загрузки в регистр, любое загруженное значение расширяется до полной ширины. В ARM, если таковая нужна, надо сначала загрузить во временный регистр, а потом доработать командой группы BFM. Аналогичное есть, например, в SystemZ (IC, RISBG и тому подобные команды).
P> насчет AH/AL в свеже сгенеренном коде врать не буду, не помню, а вот в каких-то из системных библиотек 7-ки, в котором приходилось ковырятся отладчиком (была тема самопального PE загрузчика) — точно были.
Здравствуйте, CreatorCray, Вы писали:
TB>>Я достаточно долго работаю, чтоб видеть, как люди, в квалификации которых я не сомневаюсь, иногда выдают в код полнейшую дичь, которая проходит тесты, но при определённых условиях заполняет память мусором. Просто по запарке. CC>За последние 20+ лет я ни разу не видел чтоб квалифицированные люди спороли что нить подобное "по запарке"
Ну как бы... Не то, чтобы претендовал на то, чтобы числиться сильно уж квалифицированным, но какая-то квалификация все-таки есть. Вот, давеча потратил кучу времени на то, чтобы найти и устранить баг, внесенный собственноручно года полтора назад по явному недосмотру.
Здравствуйте, so5team, Вы писали:
S>Вот, давеча потратил кучу времени на то, чтобы найти и устранить баг, внесенный собственноручно года полтора назад по явному недосмотру.
Баги делают все. Вопрос скорее в том, была ли это та самая "очепятка", про которую ты тут рассказываешь или что нить менее очевидное?
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, netch80, Вы писали:
N>Так нет принципиальной разницы со сложением или вычитанием. Сложил два int32_t, получил int33_t. Прибавил к нему int32_t, можешь формально получить int34_t. И так далее.
Да, в худшем случае всё равно придётся контролировать результат на вписываемость в рамки.
N>Они сами по себе не проблема. Проблема — когда забывают обрабатывать ошибки, или административно не дают на это ресурсов, или когда (как ты описываешь) неудобно и громоздко всё конвертировать к адекватным типам.
Так я говорю — подход Раста самый консистентный, и в нём в целом проблемы нет. Проблема возникает, когда хипстор, обдолбавшийся домен драйвером, начинает использовать u8 для хранения координат на доске 256х256.
N>1. От типа, который содержит только корректные значения (что правильно) — к конкретным вариантам типа u8.
В языке нет более простого способа задать тип, который умеет принимать только значения из 0..255.
Вариант со структурой с упоротым сеттером и перегруженными всеми операциями не предлагать, на деле любое обобщение в операциях с числами приводит к дополнительному гемору.
N>Посмотри в этом смысле на Ada.
Я знаю, как в Ada, я на ней даже пару программ писал. Но это вообще даже близко не мейнстрим.
N>Вполне себе аргумент в пользу удобства integral promotion для типовых операций. Но, с другой стороны, операция получения разности координат это особая операция, при которой меняется тип. Это было ещё в C: можно вычитать два однотипных указателя, получим разность между ними (причём разность адресов делится на размер указуемого). Почему не сделать такое же? N>Ну а дальше у тебя будет просто figure1.x — figure2.y которое молча под капотом правильно выполнится.
Почему бы просто не взять с самого начала сраный инт и не морочить голову?
N>А вот диагностика ситуации "процесс X не отработал запрос потому, что в этот момент упал процесс Y, а проверка криво сделана в промежуточном процессе Z, который выдал неполные данные" может обойтись на порядки дороже, чем однократное корректное написание. Особенно если это у субкастомера кастомера в пределах концерна-клиента.
Я не спорю, что есть задачи, где надёжность превыше всего. Но большинство из нас работают не с ними.
N>И вообще, я не понимаю — выше ты против того, чтобы u8 + u8 проверялось на выход за пределы диапазона u8 — а теперь что? Ты уж определись.
Я уже написал несколько раз: я против использования разных целый чисел в каждой задаче. Это хипстерская придурь, которая только вынуждает пердолиться с кастами. В русте у вектора размер имеет тип usize, но в библиотеке для работы с bmp размер уже имеет тип u32, и если ты её используешь и из вектора данные как-то по точкам пишешь в битмап, то твой код это "ехал каст через каст".
Но почему-то только один я вижу тут проблему: https://github.com/sondrele/rust-bmp/issues/31
Нормальный человек использует инт. Если инта не хватает — то это либо формула неправильная, либо очень специфичная задача, где малой кровью уже не отделаешься и надо уже думать, как иначе организовать подсчёт.
N>Возможно, я что-то упускаю, но почему не создать промежуточную переменную типа "вектор", которая, по твоим описаниям, будет равна P-ZeroPoint, адекватно назвать её и дальше использовать в формулах?
А что я тогда выигрываю? Я написал сложную формулу с векторами и опечатался. Потом я применил крутую безопасную либу, и написал ту же формулу, но вместо векторов везде подставил P-ZeroPoint, и снова опечатался. Разница в том, что я написал менее читаемую строчку, но не получил никакого выигрыша ни в надёжности ни в скорости создания продукта.
N>2) Есть масса приёмов (там приведены в примерах), которые дают возможность избежать подавляющего большинства проблем от этих решений. N>Вообще их ответы очень интересны именно этими примерами.
Проблема в том, что вместо того, чтобы взять инт и не париться, приходится каждый раз использовать специальный приём, причём если забудешь это сделать, то у тебя программа упадёт.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, CreatorCray, Вы писали:
CC>За последние 20+ лет я ни разу не видел чтоб квалифицированные люди спороли что нить подобное "по запарке"
Звучит, как будто ты 20+ лет не работал с кодом.
TB>>А идеология руста с ограничениями на типы требует постоянно писать хрень как в первом коде. CC>Печальный язык.
Не язык, а сообщество. Взять инт и не париться — не для нас. Надо взять u8 и самим себе создать проблему, а потом героически её решать.
CC>Когда программа откровенно делает то, что от неё не ждали — программе лучше упасть чем спрятать какашку в памперс.
Я не про поведение программы, а про модные тенденции использовать "тип который не может принимать некорректные значения". Как только у нас начинается арифметика, это всё летит лесом.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Звучит, как будто ты 20+ лет не работал с кодом.
Вот с таким говнокодом, за который ты тут топишь, к счастью приходилось иметь дело крайне редко.
TB>Взять инт и не париться — не для нас.
TB>Как только у нас начинается арифметика, это всё летит лесом.
У типа с нестандартным поведением должны быть перекрыты его же операторы.
Или в расте так не умеют?
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, T4r4sB, Вы писали:
TB>Ну мы уже поняли, что тебе вообще приходилось программировать крайне редко.
20+ лет только этим и занимаюсь.
TB>>>Взять инт и не париться CC>> TB>Что ты хочешь сказать?
Эта песня хороша, начинай сначала.
TB>Перегрузить операторы для стандартного u8? Нет, не умеют.
Для своего типа
Если у тебя есть что то с нестандартным поведением то надо не "взять int и не париться" а сделать свой тип с заданным поведением.
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, T4r4sB, Вы писали:
TB>Так я говорю — подход Раста самый консистентный, и в нём в целом проблемы нет. Проблема возникает, когда хипстор, обдолбавшийся домен драйвером, начинает использовать u8 для хранения координат на доске 256х256.
А ты не видишь, что одно другому противоречит у тебя? Координата влезает в u8, но операции с ней делать в u8 ни-ни, надо конвертить к нужным размерам, и лучше чтобы само догадалось. Причём, какие операции и почему — ты сказать не хочешь. Может, там факториал координаты браться будет? (это шахматы, там много чего может быть )
Я как раз никакой такой уж преобладающей консистентности не вижу. Сишное неотменяемое расширение с последующим слабоконтролируемым сужением — да, часто даёт проблемы и избыточно, но жёсткие противоположные рамки тоже не лучший вариант.
Вот где, например, операция вида u8*u8->u16? Что, всегда писать расширение до u16 с последующим умножением (а компилятор должен обратно догадаться использовать команду косого умножения)? Дайте её в виде функции/метода. Почему это есть в Forth или в GCC builtins, но не в нормальном языке? (Для C++ были предложения, но не прошли.)
N>>Так нет принципиальной разницы со сложением или вычитанием. Сложил два int32_t, получил int33_t. Прибавил к нему int32_t, можешь формально получить int34_t. И так далее. TB>Да, в худшем случае всё равно придётся контролировать результат на вписываемость в рамки.
Его _всегда_ придётся контролировать хотя бы на уровне определения компилятору, что тут делают. Компилятор сейчас не может работать иначе, если он хочет нормально оптимизировать. И вот тут надо решать (а лучше всего — давать кодеру задавать вариант), что делать. Главное — консистентность и удобство правил на таком уровне, чтобы не требовать лишних слов на каждое входное-выходное значение и на каждую операцию.
N>>1. От типа, который содержит только корректные значения (что правильно) — к конкретным вариантам типа u8. TB>В языке нет более простого способа задать тип, который умеет принимать только значения из 0..255.
Вот почему я вспоминал Ada.
TB>Вариант со структурой с упоротым сеттером и перегруженными всеми операциями не предлагать, на деле любое обобщение в операциях с числами приводит к дополнительному гемору.
Ну, наверно, там не сделали мягкое адекватное обобщение.
N>>Посмотри в этом смысле на Ada.
TB>Я знаю, как в Ada, я на ней даже пару программ писал. Но это вообще даже близко не мейнстрим.
"Не мейнстрим" к чему тут вообще?
Разве тяжело сделать аналогичное для C++ или Rust?
По-моему, они уже давно есть в десятках вариантов для каждого.
N>>Вполне себе аргумент в пользу удобства integral promotion для типовых операций. Но, с другой стороны, операция получения разности координат это особая операция, при которой меняется тип. Это было ещё в C: можно вычитать два однотипных указателя, получим разность между ними (причём разность адресов делится на размер указуемого). Почему не сделать такое же? N>>Ну а дальше у тебя будет просто figure1.x — figure2.y которое молча под капотом правильно выполнится.
TB>Почему бы просто не взять с самого начала сраный инт и не морочить голову?
Возьми. Я вот и удивляюсь, почему ты использовал u8 вместо int. У тебя структура с ними? Ну так проконвертируй в момент извлечения.
N>>А вот диагностика ситуации "процесс X не отработал запрос потому, что в этот момент упал процесс Y, а проверка криво сделана в промежуточном процессе Z, который выдал неполные данные" может обойтись на порядки дороже, чем однократное корректное написание. Особенно если это у субкастомера кастомера в пределах концерна-клиента.
TB>Я не спорю, что есть задачи, где надёжность превыше всего. Но большинство из нас работают не с ними.
НЕТ.
Мы все работаем с ними.
Сейчас сложность любой простейшей системы в компьютере, включая железо, прошивки, ОС и прикладные программы, такая, что любые подобные эффекты начинают фатально и недиагностируемо (потому что слишком сложно) влиять на работу. Последние годы, когда ты мог честно сказать "большинство работают не с ними" это примерно 1990-й год.
И хорошо если это BSOD — хуже, если это скрытая порча данных.
N>>И вообще, я не понимаю — выше ты против того, чтобы u8 + u8 проверялось на выход за пределы диапазона u8 — а теперь что? Ты уж определись. TB>Я уже написал несколько раз: я против использования разных целый чисел в каждой задаче.
Я не увидел этого прямым текстом, ну да ладно.
Но как тогда ты будешь разбираться с тем, что на до чёрта современных платформ иногда нужен long = i64, но он сильно дороже, чем i32? Будешь пытаться обобщать всех до размера iptr?
А знаковость/беззнаковость, её тоже обобщим?
А 3-4 современных разных типа float?
TB> Это хипстерская придурь, которая только вынуждает пердолиться с кастами. В русте у вектора размер имеет тип usize, но в библиотеке для работы с bmp размер уже имеет тип u32, и если ты её используешь и из вектора данные как-то по точкам пишешь в битмап, то твой код это "ехал каст через каст". TB>Но почему-то только один я вижу тут проблему: https://github.com/sondrele/rust-bmp/issues/31
Посмотрел. Насколько я понял, выбор i32 тут происходит из i32 в структуре заголовка BMP, а значит, внутри библиотеки не будет проблем типа "значение не влезло в сгенерированный заголовок".
Или же они пошли по пути "i32 умолчание — делаем в нём" (это уже вопрос, почему в Rust явный i32, а не зависимый от платформы int).
Если первое, то я бы так не делал. Тут согласен с твоим тикетом, примерно на 2/3. Треть оставляю на то, что i32 тут ограничение контекста, которое имеет смысл таки применять во всём, что в этом контексте.
Если второе, то это неустранимо в пределах Rust.
Ещё вариант — что они подумали о платформах, где isize == i64, но манипулирование с таким размером усложнено и дороже (например, MIPS/64).
TB>Нормальный человек использует инт.
Которого нет в Rust.
N>>Возможно, я что-то упускаю, но почему не создать промежуточную переменную типа "вектор", которая, по твоим описаниям, будет равна P-ZeroPoint, адекватно назвать её и дальше использовать в формулах?
TB>А что я тогда выигрываю? Я написал сложную формулу с векторами и опечатался. Потом я применил крутую безопасную либу, и написал ту же формулу, но вместо векторов везде подставил P-ZeroPoint, и снова опечатался.
Опечатался в чём?
TB> Разница в том, что я написал менее читаемую строчку, но не получил никакого выигрыша ни в надёжности ни в скорости создания продукта.
Получил выигрыш.
Я не знаю, как в твоём домене, но я возился с NumPy+SciPy. Там очень любят использовать одну операцию для 100500 разных действий, типа одним '*' умножать матрицу и на скаляр, и на вектор. И когда оно вылетает в рантайме оттого, что, например, ndarray вместо matrix — это ещё полбеды, тесты ловят сразу. А если молча делает не то — приходится разлагать на микрооперации, примерно как ты рассказываешь про касты, и сравнивать тип каждого с желаемым.
Предпочитаю явные касты.
N>>2) Есть масса приёмов (там приведены в примерах), которые дают возможность избежать подавляющего большинства проблем от этих решений. N>>Вообще их ответы очень интересны именно этими примерами.
TB>Проблема в том, что вместо того, чтобы взять инт и не париться, приходится каждый раз использовать специальный приём, причём если забудешь это сделать, то у тебя программа упадёт.
Вообще-то тебе там никто не мешает размер сразу привести к isize.
Здравствуйте, netch80, Вы писали:
N>А ты не видишь, что одно другому противоречит у тебя?
У меня — это у кого? Может быть ты глаза разуешь, и прочитаешь наконец-то, что я как раз за инты и против использования мелких типов только ради "доменного дизайна"?
TB>>Я знаю, как в Ada, я на ней даже пару программ писал. Но это вообще даже близко не мейнстрим.
N>"Не мейнстрим" к чему тут вообще? N>Разве тяжело сделать аналогичное для C++ или Rust? N>По-моему, они уже давно есть в десятках вариантов для каждого.
Это будет структура с перегруженным оператором, при этом её, в отличие от чисел, нельзя будет просто так выводить на экран, тебе надо будет везде таскать трейты Numeric+Debug, первый чтоб просто иметь то, что имеют обычные числа, второй чтоб можно было печатать, и я не уверен что структура в 4 байта не будет пихаться везде по ссылке.
TB>>Почему бы просто не взять с самого начала сраный инт и не морочить голову?
N>Возьми. Я вот и удивляюсь, почему ты использовал u8 вместо int. У тебя структура с ними? Ну так проконвертируй в момент извлечения.
Дальше разгорелся срач, я привёл пример с шахматной доской 256х256, и спросил, реально ли они ради дебильной идеи сраных доменов будут использовать u8, понимая, что тривиальные операции будет делать крайне геморройно, и они сказали что да.
Я за инты, понимаешь? Я против u8. А фанатики доменного бреда говорят что инты это Primitive Obsession
N>Мы все работаем с ними.
Чушь, от падающего приложения в 99% случаев никто не ощутил никакого ущерба.
N>Я не увидел этого прямым текстом, ну да ладно.
Прочитай тему, перестань обвинять меня в поддержке того, против чего я прямым текстом выступаю, перестань сношаться в глаза, что я могу посоветовать.
N>Но как тогда ты будешь разбираться с тем, что на до чёрта современных платформ иногда нужен long = i64, но он сильно дороже, чем i32? Будешь пытаться обобщать всех до размера iptr?
Это какие, например? Только не надо про x86, пожалуйста.
N>А знаковость/беззнаковость, её тоже обобщим?
Беззнаковость почти никогда не нужна. Если ты думаешь, что тебе нужна беззнаковость только потому, что тебе кажется, что у тебя тут никогда не будет отрицательных чисал — то перечитай тему с самого начала, что я думаю про доменно-ориентированный идиотизм.
N>А 3-4 современных разных типа float?
Есть f32, f64
N>Посмотрел. Насколько я понял, выбор i32 тут происходит из i32 в структуре заголовка BMP, а значит, внутри библиотеки не будет проблем типа "значение не влезло в сгенерированный заголовок".
Таки u32. Ну и делать кривой интерфейс ради каких-то особенностей реализации — это говнокод.
TB>>Нормальный человек использует инт.
N>Которого нет в Rust.
Там есть i32, который по умолчанию выбирается, если по контексту не удалось явно определить тип, видимо это намекает, что он должен быть "дефолтным" интом. Хотя лучше б взяли isize, чтоб консистентно с векторами было.
TB>>А что я тогда выигрываю? Я написал сложную формулу с векторами и опечатался. Потом я применил крутую безопасную либу, и написал ту же формулу, но вместо векторов везде подставил P-ZeroPoint, и снова опечатался.
N>Опечатался в чём?
А формуле, оперирующей векторами.
TB>> Разница в том, что я написал менее читаемую строчку, но не получил никакого выигрыша ни в надёжности ни в скорости создания продукта.
N>Получил выигрыш.
Получил проигрыш.
N>Я не знаю, как в твоём домене
Тогда зачем отстаиваешь заведомо кривую реализацию паттерна, если не знаешь, как там?
Наверное вектор и матрицу действительно лучше отделить на этапе компиляции, потому что одно и другое никак не взаимозаменяемо. А вот точку и вектора отделать бесполезно, есть куча формул в алгебре, где это одно и то же.
N>Вообще-то тебе там никто не мешает размер сразу привести к isize.
Вообще-то
1. Легко забыть это сделать, ведь компилятор ничего не скажет, а потом программа упадёт.
2. Подход руста вынуждает весь код превращать в бесконечную кашу из "as isize", при этом ради чего? Чего эти идиоты сразу не взяли isize?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
N>>А ты не видишь, что одно другому противоречит у тебя?
TB>У меня — это у кого? Может быть ты глаза разуешь, и прочитаешь наконец-то, что я как раз за инты и против использования мелких типов только ради "доменного дизайна"?
Это я прочитал, нет проблем. Я считаю противоречием то, что при этом ты считаешь, что для этих мелких типов подход типа u8*u8 -> u8 является самым осмысленным.
Ну вот не могу я это свести в единую непротиворечивую концепцию.
TB>>>Я знаю, как в Ada, я на ней даже пару программ писал. Но это вообще даже близко не мейнстрим.
N>>"Не мейнстрим" к чему тут вообще? N>>Разве тяжело сделать аналогичное для C++ или Rust? N>>По-моему, они уже давно есть в десятках вариантов для каждого.
TB>Это будет структура с перегруженным оператором, при этом её, в отличие от чисел, нельзя будет просто так выводить на экран, тебе надо будет везде таскать трейты Numeric+Debug, первый чтоб просто иметь то, что имеют обычные числа, второй чтоб можно было печатать, и я не уверен что структура в 4 байта не будет пихаться везде по ссылке.
Мелкие структуры размером до 1-2 регистров процессора, если в них нет элементов с особым поведением, в современных (>= 30 лет) C ABI передаются по значению. Rust ещё новее, так что должен тоже. "Таскать везде" Numeric+Debug — разве это сложно? Просто пометить соответствующим образом? Тут упоминали std::num::Wrapping, там уже сделано. Если какие-то мелкие детали недоделаны — Rust бурно развивается, можно пожаловаться (если не менять уже принятые основы, как ты пытался).
TB>А я удивляюсь, почему ты долбишься в глаза
[...]
TB>Я за инты, понимаешь? Я против u8. А фанатики доменного бреда говорят что инты это Primitive Obsession
Тогда это ты долбишься в глаза. Потому что я объяснил, что я в пределах "доменного бреда" за range(0..255), но против явного u8.
И вообще, хоть мы и в flame.comp, но мне не нравится такая лексика ;\
N>>Мы все работаем с ними. TB>Чушь, от падающего приложения в 99% случаев никто не ощутил никакого ущерба.
Чушь тут твои слова. Ущерб только по отчётам всяких статистических организаций идёт на десятки миллиардов.
TB>Прочитай тему, перестань обвинять меня в поддержке того, против чего я прямым текстом выступаю, перестань сношаться в глаза, что я могу посоветовать.
Это я тебе должен посоветовать остановится, подумать и разобраться, чего же ты хочешь.
N>>Но как тогда ты будешь разбираться с тем, что на до чёрта современных платформ иногда нужен long = i64, но он сильно дороже, чем i32? Будешь пытаться обобщать всех до размера iptr? TB>Это какие, например? Только не надо про x86, пожалуйста.
Что именно не надо про x86? И который x86? Я уже не понимаю, что ты называешь этим. Если в хромой виндовой терминологии где "x64" = x86-64, то есть масса вполне живого embedded и полу-embedded на ARM/32. У меня такая платформа недавно была в целевых, и наверняка буду к этому возвращаться.
N>>А знаковость/беззнаковость, её тоже обобщим? TB>Беззнаковость почти никогда не нужна. Если ты думаешь, что тебе нужна беззнаковость только потому, что тебе кажется, что у тебя тут никогда не будет отрицательных чисал — то перечитай тему с самого начала, что я думаю про доменно-ориентированный идиотизм.
Для размеров контейнеров я согласен. Но вот сейчас работаю с протоколом, где seqnums — 16-битные беззнаковые и потому достаточно быстро оборачиваются по кругу.
N>>А 3-4 современных разных типа float? TB>Есть f32, f64
А также f16-ieee, bfloat16, decfloat32, decfloat64... и даже тут есть люди, которые активно работают с ними.
Но даже если бы были только f32, f64 — ты бы точно так же шипел "я за флоаты и против f32" когда ты бы решил, что тебе не хватает точности f32 и надоело кастить к f64?
N>>Посмотрел. Насколько я понял, выбор i32 тут происходит из i32 в структуре заголовка BMP, а значит, внутри библиотеки не будет проблем типа "значение не влезло в сгенерированный заголовок". TB>Таки u32. Ну и делать кривой интерфейс ради каких-то особенностей реализации — это говнокод.
Ну я их и не защищал. Попытался пояснить, почему это имеет отношение к их решению.
TB>>>Нормальный человек использует инт.
N>>Которого нет в Rust.
TB>Там есть i32, который по умолчанию выбирается, если по контексту не удалось явно определить тип, видимо это намекает, что он должен быть "дефолтным" интом. Хотя лучше б взяли isize, чтоб консистентно с векторами было.
Про "лучше isize" я согласен на 234%. Ну если это не извращение типа MIPS/64.
TB>>>А что я тогда выигрываю? Я написал сложную формулу с векторами и опечатался. Потом я применил крутую безопасную либу, и написал ту же формулу, но вместо векторов везде подставил P-ZeroPoint, и снова опечатался.
N>>Опечатался в чём? TB>А формуле, оперирующей векторами.
Как и почему?
TB>>> Разница в том, что я написал менее читаемую строчку, но не получил никакого выигрыша ни в надёжности ни в скорости создания продукта. N>>Получил выигрыш. TB>Получил проигрыш.
В общем случае — выигрыш, когда у тебя формула посложнее или расчёты более громоздкие.
N>>Я не знаю, как в твоём домене
TB>Тогда зачем отстаиваешь заведомо кривую реализацию паттерна, если не знаешь, как там?
Потому что стараются покрыть таки статистически максимум, чем каждый специфический домен.
Но с математикой я работал (и даже образование у меня оттуда), так что я очень близко ходил к твоему домену, и проблемы подстановки не того типа знаю.
Ты, кстати, не прочитал, что я ниже писал, сразу ринулся возражать. Это плохо.
TB>Наверное вектор и матрицу действительно лучше отделить на этапе компиляции, потому что одно и другое никак не взаимозаменяемо. А вот точку и вектора отделать бесполезно, есть куча формул в алгебре, где это одно и то же.
Тебе так кажется. А авторы numpy тебе ответят, что вектор это матрица с размером 1 по одному из измерений, скаляр — вообще матрица 1*1, а 2-dimensional array это матрица, и "есть куча формул в алгебре" (и применений) где это одно и то же.
Они просто пошли чуть дальше, чем ты. Но на принципиальном уровне то же самое — "художник так видит", а проблемы пользователей волнуют слабо.
N>>Вообще-то тебе там никто не мешает размер сразу привести к isize.
TB>Вообще-то TB>1. Легко забыть это сделать, ведь компилятор ничего не скажет, а потом программа упадёт.
Ты ж сам говоришь, что от падения проблем нет?
Ну и чтобы isize не влезло в i32, надо иметь ну очень большие размеры.
TB>2. Подход руста вынуждает весь код превращать в бесконечную кашу из "as isize", при этом ради чего? Чего эти идиоты сразу не взяли isize?
Здравствуйте, netch80, Вы писали:
N>Это я прочитал, нет проблем. Я считаю противоречием то, что при этом ты считаешь, что для этих мелких типов подход типа u8*u8 -> u8 является самым осмысленным. N>Ну вот не могу я это свести в единую непротиворечивую концепцию.
Почему? Если ты просто используешь инты, то никаких проблем. А мелкие типы просто не надо использовать, кроме низкоуровневой фигни.
N>Тогда это ты долбишься в глаза. Потому что я объяснил, что я в пределах "доменного бреда" за range(0..255), но против явного u8.
Давай говорить про реальные языки. В русте для поддержки доменного бреда для диапазона 0..255 берут тип u8, о чём мне хипсторы прямо сказали в сраче про беззнаковые индексы. Про потенциальные проблемы они сказали "пиши свой приватный метод с кастами на каждый чих, чтобы абстрагироваться и воспринимать это как чорный ящег".
N>И вообще, хоть мы и в flame.comp, но мне не нравится такая лексика ;\
Давай ты не будешь меня обвинять в поддержке того, что я прямым текстом осуждаю уже 5ю страницу. Иначе это разговор со слепоглухим.
N>Чушь тут твои слова. Ущерб только по отчётам всяких статистических организаций идёт на десятки миллиардов.
Ущерб от невыпущенной в срок программы, потому что отдел разработки не сумел верифицировать перед компилятором какой-то хитрый случай хитрого алгоритма, ещё выше.
N>Это я тебе должен посоветовать остановится, подумать и разобраться, чего же ты хочешь.
Изначально я хотел узнать название антипаттерна, которым болеет руст-коммьюнити и автор библиотеки std::chporno.
N>Что именно не надо про x86? И который x86? Я уже не понимаю, что ты называешь этим. Если в хромой виндовой терминологии где "x64" = x86-64, то есть масса вполне живого embedded и полу-embedded на ARM/32. У меня такая платформа недавно была в целевых, и наверняка буду к этому возвращаться.
Ну сорян, есть платформы, где размер указателя вдвое превышает размер слова, и там даже ллвм непонятно что предоставляет. Думаю, со временем будет какая-то унификация. Нестандартные отрицательные числа же в С++ победили наконец-то к 20 году.
N>Для размеров контейнеров я согласен. Но вот сейчас работаю с протоколом, где seqnums — 16-битные беззнаковые и потому достаточно быстро оборачиваются по кругу.
Это относится к работе с АПИ. Там выбора нет.
N>Но даже если бы были только f32, f64 — ты бы точно так же шипел "я за флоаты и против f32" когда ты бы решил, что тебе не хватает точности f32 и надоело кастить к f64?
Там нет такой проблемы, потому что либы как правило состоят из функций где все аргументы и результат одного типа, причём тип можно выбрать любой, поэтому просто изначально выбираешь нужный тип под свои потребности.
В случае с целыми типами когда каждый хипстор берёт свой собственный u32,usize,u8,i32 — просто затрахаешься всё кастить туда-сюда.
N>Про "лучше isize" я согласен на 234%. Ну если это не извращение типа MIPS/64.
Слава богу, пришли к какому-то консенсусу.
N>Как и почему?
Ну по запарке плюс с минусом перепутал, и две сущности вида (P-ZeroPoint) не вычел, а сложил. Толку тогда от такой "защиты"?
N>В общем случае — выигрыш, когда у тебя формула посложнее или расчёты более громоздкие.
Именно в сложной формуле вообще невозможно оперировать отдельно точками и отдельно векторами и приходится заранее все точки превращать в вектора при помощи (P-ZeroPoint), а потом писать точно такую же векторную формулу с точно такими же шансами на опечатку.
N>Тебе так кажется. А авторы numpy тебе ответят, что вектор это матрица с размером 1 по одному из измерений, скаляр — вообще матрица 1*1, а 2-dimensional array это матрица, и "есть куча формул в алгебре" (и применений) где это одно и то же. N>Они просто пошли чуть дальше, чем ты. Но на принципиальном уровне то же самое — "художник так видит", а проблемы пользователей волнуют слабо.
А там на этапе компиляции не отследить размер матрицы? Аааа, это ж питон. Ну так блин, это другая крайность.
TB>>1. Легко забыть это сделать, ведь компилятор ничего не скажет, а потом программа упадёт.
N>Ты ж сам говоришь, что от падения проблем нет?
Да, с моей стороны это всего лишь +1 одна итерация "прочитать лог и воткнуть каст ещё в то место". Просто и её могло бы не быть, если бы не это типобесие. Если бы целые везде были интами кроме редких случаев, то ряд случаев падения-по-переполненю бы исчез, и ни одного нового случая падения бы не появилось. Тогда почему так изначально не сделать?!
Ну и самое идиотское во всей этой истории, что всё это подаётся по соусом... повышения надёжности!!! То есть лишний источник падений добавили как раз те, кто за надёжность в ущерб скорости написания прототипа.
TB>>2. Подход руста вынуждает весь код превращать в бесконечную кашу из "as isize", при этом ради чего? Чего эти идиоты сразу не взяли isize?
N>Не знаю. Можешь попробовать спросить.
Дык я спросил в руст-коммьюнити. Мне сказали, что я ничего не понимаю в доменно-ориентированных типах. И я до сих пор ничего в них не понимаю.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, netch80, Вы писали:
N>Вот где, например, операция вида u8*u8->u16? Что, всегда писать расширение до u16 с последующим умножением (а компилятор должен обратно догадаться использовать команду косого умножения)? Дайте её в виде функции/метода. Почему это есть в Forth или в GCC builtins, но не в нормальном языке? (Для C++ были предложения, но не прошли.)
Здравствуйте, Слава, Вы писали:
С>Здравствуйте, netch80, Вы писали:
N>>Вот где, например, операция вида u8*u8->u16? Что, всегда писать расширение до u16 с последующим умножением (а компилятор должен обратно догадаться использовать команду косого умножения)? Дайте её в виде функции/метода. Почему это есть в Forth или в GCC builtins, но не в нормальном языке? (Для C++ были предложения, но не прошли.)
С>А может вы proposal напишете?