Виммельбух, 3, перетяжка
Виммельбух, 3, перетяжка
Виммельбух, 3, перетяжка

Умеете ли вы правильно называть функции?

Аватар Типичный программист
Отредактировано

Как имя, которое хорошо описывает то, что делает функция, может на практике оказаться абсолютно бесполезным и что с этим делать? Рассказываем в статье.

14К открытий14К показов

Автор перевода — Мария Багулина

Названия функций крайне важны, особенно если вы занимаетесь разработкой пользовательского API. Иногда имя может прекрасно описывать то, что делает функция, но на практике оказывается абсолютно бесполезным. И с этим можно столкнуться даже в стандартных библиотеках. В качестве примеров рассмотрим несколько функций C++20.

Пример 1: std::log2p1()

Начнём с функции std::log2p1().Её код выглядит так:

			int log2p1(int i)
{
    if (i == 0)
        return 0;
    else
        return 1 + int(std::log2(x)); 
}
		

Функция просто возвращает двоичный логарифм числа плюс один, о чём и говорит её название.

Но какая от этого польза?

На самом деле std::log2p1(x) возвращает количество битов, необходимых для хранения x. Это действительно нужная функция, но её название совсем не отражает суть выполняемой операции.

Пример 2: std::bless()

Если вы плохо знакомы с языком C++, то вот быстрое введение в его объектную модель.

В С++ существует такая штука, как указатель — переменная, в которую записывается адрес другого объекта в памяти. Над указателем можно выполнять арифметические действия, но только если он является элементом массива. Почему так? Потому что нельзя вычитать или прибавлять что-то к произвольному указателю — это не имеет смысла, так как расположение объектов в памяти неизвестно.

			int obj = 0;
int* ptr = &obj;

++ptr; // Неопределённое поведение
		

Однако такое действие не является явной ошибкой, а порождает неопределённое поведение (то есть результат, зависящий от состояния памяти, компилятора, фазы луны или каких-либо других случайных факторов).

Проблема сводится не к глупым программистам, которые зачем-то складывают указатели (ведь это не запрещено), а к самому языку С++. Поэтому Ричард Смит, исследователь из Google, предложил добавить в стандарт функцию std::bless(void* ptr, std::size_t n),чтобы при необходимости автоматически выделять массив памяти и тем самым разрешить вопрос с арифметикой для указателей.

Имя bless, разумеется, никак не сообщает обо всех этих нововведениях, поэтому было решено придумать другое название для функции. За дело взялся комитет по развитию языка C++: в качестве кандидатов они выдвинули верси иimplicitly_create_objects() и implicitly_create_objects_as_needed() («неявно создать объекты» и «неявно создать объекты при необходимости»). Имена вполне логичны, ведь функция делает именно то, что в них сказано. Но, согласитесь, если бы вы не знали предысторию, то совершенно не поняли, зачем нужно создавать какие-то объекты.

Пример 3: std::popcount()

Напоследок ещё одна стандартная функция C++ 20. Просто посмотрите на её имя и попробуйте угадать, что она делает. Кажется, что-то считает? Может быть, это связано со стековыми операциями pop и push?

Скорее всего, вы не догадаетесь, если только уже не знаете о низкоуровневой инструкции с таким же названием. Функция popcount (сокращённо от «population count») подсчитывает количество установленных битов в машинном слове.

С одной стороны, это было бы отличное имя, если бы все разработчики знали названия ассемблерных битовых операций. Но будет ли оно очевидно новичку, который не в курсе таких тонкостей?

Как же следует называть функции?

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

Вряд ли вы подумаете: «Так, мне нужно вычислить двоичный логарифм плюс один, нет ли случайно стандартной функции для этого?». Скорее в вашей голове будет мысль: «Теперь мне нужно знать, сколько битов требуется для хранения этого значения». И ваш запрос в Google будет выглядеть примерно как: «bit width function C++» — почему бы тогда вместоlog2p1()не использовать имяbit_width()?

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

Happy end

Раз уж мы затронули тему C++20, спешим сообщить хорошие новости: кажется, комитет по развитию языка всё-таки переименует std::log2p1()вstd::bit_width(). Но проблема именования затрагивает не только стандартные библиотеки. Поэтому если ваш проект предполагает, что его кодом кто-то будет пользоваться в дальнейшем, выбирайте говорящие имена и смотрите на функции с точки зрения пользователей.

Следите за новыми постами
Следите за новыми постами по любимым темам
14К открытий14К показов