RSS Telegram YouTube Apple Яндекс Spotify Google Amazon Почта

41. Ноль или один: споры о индексации

03.03.2024

Скачать

К списку выпусков

Ссылки выпуска:

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

Не всегда мы начинаем считать с единицы. Иногда счет идет с нуля, например, когда ребенок только родился, можно сказать, что ему 0 лет. В астрономическом календаре также есть нулевой год. Представим массив, где в качестве индекса используется возраст (в годах), а в качестве элемента массива — средний рост человека за год. В таком случае индекс 0 окажется удобным. Таким образом, индексация с нуля покрывает все случаи использования, хотя этот аргумент и кажется слабым, поскольку возраст можно считать начиная с "неполных одного года". Редко когда требуется считать что-то с нуля, в основном счет ведется с единицы, так как массив для нас — это хранилище, в ячейках которого что-то лежит.

В компьютерной графике иногда удобно использовать нулевой индекс. Все пиксели на экране представлены в виде двумерного массива, и часто требуется сконвертировать двумерный массив в одномерный. Первый элемент в исходном массиве имеет координаты (0, 0), и будет проще, если итоговый массив также начинается с нуля. Так, в некоторых операциях выражения выглядят проще, и ради этой простоты в таких операциях следует использовать индексацию с нуля, хотя этот довод тоже кажется слабым, так как редко выполняются такие специализированные вычисления.

Есть и другие математические операции, которые проще выполняются, если индексация идет с единицы, например, деление по модулю, что используется чаще, чем конвертация массивов. Еще один довод в пользу индексации с нуля — это апелляция к авторитету. Известный ученый Эдсгер Дейкстра в своей статье "Почему нумерация должна начинаться с нуля" обосновывает удобство использования полуоткрытого интервала, где нижняя граница включена, а верхняя исключена, что упрощает получение длины массива и обозначение пустого массива. Однако, использование закрытого интервала кажется проще, так как в этом случае мы указываем только необходимые индексы.

Считая с нуля, у массива верхний индекс будет равен его длине, что также приводится в аргументы, хотя во многих языках программирования для получения длины массива существуют встроенные функции, например, len в Go.

Возможно, все эти аргументы кажутся натянутыми. Тем, кто убежден в удобстве нулевого индекса для математики, следует напомнить, что в самой математике счет обычно ведется с единицы. Основная причина использования индексации с нуля, возможно, кроется в удобстве выполнения адресной арифметики в историческом контексте: индекс, по сути, является смещением от адреса начала массива, и для доступа к первому элементу достаточно прибавить к адресу массива 0. В современных языках программирования мы редко высчитываем адреса самостоятельно, но традиция использования нулевого индекса сохраняется, так как многие программисты к этому привыкли.

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

Проблемы индексации порождают целый класс ошибок, называемых "ошибками на единицу" (off by one), когда разработчик ошибается на один элемент при выполнении циклов или других операций. Одна из простых задач, демонстрирующих такие ошибки — определение необходимого количества столбов для забора определенной длины, когда легко спутать количество сегментов с количеством столбов.