November 18th, 2021

moose, transparent

немного о дизайне функций

Интересный вопрос попался (интересно может быть программистам).

Скажем, нам нужна функция, которая "зажимает" значение переменной в данном промежутке. Если промежуток [20, 255] а переменная x, то фунция вернет x без изменений когда он между 20 и 255, вернет 20 если он меньше 20, и 255 если он больше 255.

Первый вариант: clamp(x, low, high)

В чем недостаток этого API? Подумайте перед тем, как читать дальше.

Ответ: в момент вызова трудно вспомнить, как правильно вызвать: clamp(x, 20, 255) или clamp(20, 255, x). Оба варианта могут показаться "логичными". Все три аргумента одного типа - компилятор не остановит неправильный вызов, и он может привести к неправильному поведению.

Второй вариант: mid(x, y, z). Фунцкия возвращает среднее из трех значений, неважно, в каком порядке их расположить. Оказывается, это делает ровно то, что требуется от clamp(). Красиво!

В чем недостаток этого API? Подумайте перед тем, как читать дальше.

Ответ: во время чтения кода намерения автора (intent) неясны. Да, mid() сделает "зажим", но то, что она делает зажим - некая нетривиальная мысль, ее надо продумать и перебрать в голове, если сам это не написал, или если написал больше, чем неделю назад и уже забыл. Можно оставить комментарий возле каждого вызова mid(), но и у этого есть очевидная, хоть и небольшая, цена с точки зрения читаемости и понятности кода.

Третий вариант: оставить название clamp(), но делать то, что делает mid(). Иными словами, делать больше проверок внутри кода функции, чтобы точно вернуть среднее из значений. clamp(x, low, high) может уже точно знать, что вернуть, если прошла проверка if (x > high), но в этом варианте мы обязательно делаем минимум два сравнения.

В чем недостаток этого API? Подумайте перед тем, как читать дальше.

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

Из этих трех вариантов я выбираю третий.

Хотелось бы что-то еще лучше - каков он четвертый вариант? В языках, позволяющих именные параметры, можно написать clamp(x, low=20, high=255), но это относительно редко встречается. Какие будут еще предложения?
moose, transparent

не сэндвич

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

Является ли хот-дог сэндвичем?

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

Я считаю, что хот-дог нельзя считать сэндвичем.

Но не потому, что в нем лежит сосиска!!!

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

Почему же тогда хот-дог - не он?

Потому что это не два куска хлеба, а один. Это одна, разрезанная НЕ ДО КОНЦА булка. То, что у двух кусков булки остается смежный не прорезанный до конца край - исключительно важно, и именно это позволяет мне утверждать, что это не сэндвич. В приготовлении сэндвича участвуют два не связанных друг с другом куска хлеба.

Мне скажут: что если ты возьмешь длинный овальный кусок хлеба, положишь в него начинку и свернешь пополам, и так возьмешь в руки, будет ли это сэндвичем?

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

Dixi.

P.S. Не надо сообщать мне, что по моему определению гамбургер выходит сэндвичем. Просто не надо. Вы не первый и не десятый человек будете. Не издевайтесь и не сыпьте соль на рану. Я подумаю и найду достойный ответ, и решу парадокс гамбургера. Но это будет завтра.