Обновить
129
0
Григорий Демченко@gridem

Software Engineer

Отправить сообщение
У них есть уйма минусов с которыми нужно считаться. Не всем они подходят.

Хочу увидеть эту уйму. Хотя бы пяток, но лучше десяток. Мне кажется, что "уйма" подразумевает немалое количество пунктов.

Тот факт, что в других языках что-то сделано не говорит о том, что оно сделано правильно.


Все дело в безопасности. Я бы хотел иметь контроль над тем, что происходит при вычислениях и преобразованиях, а именно:


  1. Возможность выбирать между быстротой и безопасностью.
  2. Выделять явно куски кода, где я хочу разных гарантий.
  3. Иметь иерархическую модель обработки исключений.

Это минимальный набор, далеко не исчерпывающий. Однако вместо этого мне подсовывают странное и говорят, что это — правильное развитие. На мой взгляд, это — даже не топтание на месте.


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

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


Решая одну проблему тут же упираешься в другую. Она была сразу, но маскировалась другой, более важной проблемой. Грубо говоря, есть процесс, который состоит из стадий. Оптимизируешь самую долгую стадию, тут же возникает узкое место в другом месте. Оптимизируешь и его, всплывает третье. Так и в разработке.

Представьте, что вы — ворона, клюющая хлебушек около лавочки. Вам бабуся подбрасывает еще хлебушек. И тут налетает стая ворон и начинает отнимать этот хлебушек.


Как вы думаете, смогли бы вы выжить в этой ситуации?

Мне всегда казалось, что хабр уже давно стер границу, разделяющую эти ресурсы. Как же я ошибался!

Что, Гриша, тоскуешь по Яндексу?

По коллегам.


О чём статья-то? Я ничего не понял.

Статья о том, что везде говнокодеры.


Как тебе Erlang после C++?

Эрланг — отличный. Уникальный язык. Все никак не соберусь написать отдельную статью.

Никогда не делайте абсолютных утверждений о реальном мире.

Очень самоиронично. Квантор "никогда" подразумевает абсолютность утверждения, таким образом это утверждение противоречит самому себе.

Я бы тут копнул немного глубже, чтобы понять, что тут происходит и почему мы имеем то, что имеем.


Возьмем изначальный пример:


int b = a + 1000;
if (b < a) { // переполнение
    puts("input too large!"); return;
}

Теперь вспомним ассемблер и подумаем, как бы этот код мог быть написан на нем?


  1. Складываем a + 1000.
  2. Проверяем флаг переполнения. Если выставлен, то пишем "input too large!".
  3. Если нет переполнения, то все ок и продолжаем работу.

Т.е. по сути, ассемблер как раз нам дает абсолютно корректное и железобетонное поведение: пытаемся выполнить операцию и проверяем итоговый результат. Нет необходимости предсказывать, является ли значение переменной меньше, чем мы ожидаем при прибавлении. Ведь в случае константы 1000 все очевидно, а в случае прибавление динамической переменной — уже не очень. Она может оказаться любой, и отрицательной в том числе. Т.е. надо будет сначала проверить с чем складываем, а потом уже выставить правильное условие? Выглядит крайне непривлекательно.


Вместо этого, по сути, ассемблер позволяет сделать аналог try/catch: выполняем операцию, и ловим исключение (выставленный флаг) в случае нарушения условий.


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


Итого мы имеем, что низкоуровневый язык, каким и изначально задумывался язык С, не может передать достаточно важные и эффективные конструкции из машинного языка. Этот костыль носит фундаментальный характер, и проявился он в спецификации UB, выкидывающей на помойку костыли из прошлого.


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

throw new ...


А вы, часом, не джавист?


И да, я хочу, чтобы такое мне делал компилятор. А ручками я могу и на асме пописать, если захочу.

Я исхожу из "язык для программиста". К сожалению, то, что написано выше, приходит к "программист для языка". Что меня печалит.

В исходном коде оно может быть — а в итоговой программе вместо этого будет операция «сделать ерунду».

Хочется понять обоснованность данной посылки. Всегда ли справедливо такое утверждение? И почему?

Может, вы слишком сильно зациклились на своей архитектуре? Напомню, C++ не только на AMD64 существует.

Нет.


Хм? На AVR я могу разыменовать 0x0000,

А при чем тут нулевой адрес и ошибка с нулевым указателем? Когда я говорю про NullPointerException, я имею в виду nullptr, числовое представление которого может быть любым.


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

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


Вам явно пишут, что результат операции неизвестен, так как зависит от программистов архитектуры+компилятора.

Похоже, что некоторые вещи тяжело доходят. Вот я напишу в стандарте, что для A+B результат UB. Напишу это явно, большими буквами. Чтобы не было иллюзий. Хорошо будет разработчику? Отнюдь.


Короче, я хотел сказать несколько другое. Кто хотел понять, тот уже понял.

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

О, первый комментарий по делу. Обычно это редкость. В смысле, часто и первого не бывает.


Собственно, то, что это UB — это понятно. Непонятно только то, зачем вместо того, чтобы решать реальные проблемы, заниматься рюшечками? Реальная проблема в том, что это не должно быть UB. Это неудобно, надежную программу так не напишешь.


Зачем придумали исключения? Чтобы не париться каждый раз с проверками на ошибки. А с делением на 0 надо париться каждый раз. Так же, как и с нулевым указателем.


Ну и главный посыл — это про то, что обработка ошибок — это не цель. И отсюда исходит топтание на месте.


А если бы я разбирал каждый абзац, то было бы как с предыдущей статьей.

Категоричность подобных утверждений всегда вызывала у меня вопросы.


То есть при разыменовании нулевого указателя может возникнуть исключение

Предположим.


а может вместо этого программа сделает какую-нибудь ерунду

А может и не сделает.


и это никак не отловить.

Отловить ерунду или исключение? Вот системный вызов завершился ошибкой. Программа потом может сделать ерунду и не отловить ее. Звучит бредово, правда? Так же, как и с нулевым указателем.

А если предусмотрено? То значит, что деление на ноль не фатально?

Мне всегда казалось, что разделение ошибки на фатальную/не фатальную решает программист, а не процессор.

Конечно, все просто.


Ошибок в программе быть не должно

Всегда об этом говорю своей команде. А они продолжают писать с ошибками. Видимо, надо чаще об этом говорить.


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

Так и вижу: сервис, который работает 24/7/365 внезапно складывается и отсылает отчет разработчику, что он ленивая жопа и не хочет фиксить баги.


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

Сильное утверждение. Проверять его, я конечно же, не буду.


Ошибки во внешнем мире могут быть — например нет сети, места на диске, ошибка формата открываемого файла и т.д. — тут нужно просто сказать пользователю. Программа тут не при чем — значит можно продолжать работать.

Ага, пример в статье прошел мимо.

Не все баги являются фатальными. Почему-то этот простой и понятный тезис может быть оспорен. На мой взгляд, это очевидно. Поэтому деление на ноль — это:


  1. Может быть не багом, а специальным допущением, который можно корректно обработать.
  2. Может быть багом, после которого программа может откатиться к некоторому валидному состоянию и продолжить нормальное исполнение далее.
Состояние детерминировано, но квантовыми битами, его невозможно 100% точно закодировать классическими битами, булевыми.

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


Про двухфазный коммит (статью прочитал): он может и не тормозной. Но каждый сервис системы должен быть с нуля описан так, чтобы понимать двухфазные операции (prepare+commit).

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


Что же касается сравнения с сагой по скорости: 2-х фазному комиту, как ясно по названию, всегда нужно 2N операций. А Саге — N для корректной саги, и 2m для сбоившей (m-номер сбоившего шага, от 1 до N).

Скорость я бы описывал временем на операцию, нежели количеством операций. Количество определяет пропускную способность. В данном случае N и 2N — это небольшая разница. Все дело в том, что на первом шаге в двухфазном коммите ничего такого не происходит, а только блокируются записи. Т.е. такие операции неравноценны, а потому 2N может оказаться меньше N.


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

Информация

В рейтинге
Не участвует
Дата рождения
Зарегистрирован
Активность