Чи не доцільно робити функцію, яка по суті перейменовує вбудовану функцію?


40

Мене плутають функції min та max у певних контекстах.

В одному контексті, коли ви використовуєте функції для отримання більших чи менших двох значень, проблеми не виникає. Наприклад,

//how many autographed CD's can I give out?
int howManyAutographs(int CDs, int Cases, int Pens)
{
    //if no pens, then I cannot sign any autographs
    if (Pens == 0)
        return 0;

    //I cannot give away a CD without a case or a case without a CD
    return min(CDs, Cases);
}

Легко. Але в іншому контексті я плутаюсь. Якщо я намагаюся встановити максимум або мінімум, я отримую це назад.

//return the sum, with a maximum of 255
int cappedSumWRONG(int x, int y)
{
    return max(x + y, 255); //nope, this is wrong
}

//return the sum, with a maximum of 255
int cappedSumCORRECT(int x, int y)
{
    return min(x + y, 255); //much better, but counter-intuitive to my mind
}

Чи не доцільно робити власні функції так?

//return x, with a maximum of max
int maximize(int x, int max)
{
    return min(x, max);
}

//return x, with a minimum of min
int minimize(int x, int min)
{
    return max(x, min)
}

Очевидно, що використання вбудованих файлів буде швидше, але це здається мені зайвою мікрооптимізацією. Чи є якась інша причина, що це було б недоцільно? Що з груповим проектом?


72
Якщо min та max шкодять вашій читальності, подумайте про заміну, а потім на звичайні "if". Іноді варто написати трохи більше коду для кращої читабельності.
Т. Сар - Відновити Моніку

23
одним коротким повідомленням ви зруйнували всю концепцію "чистого кодування". Вітаю вас, пане!
Еван

21
Може бути , ви можете розглянути на C ++ 11 std::clampфункції або що - щось подібне.
rwong

15
Можливо, кращі назви були б up_to(за min) та at_least(за max)? Я думаю, що вони передають значення краще, ніж minimizeтощо. Хоча це може замислитися на мить, щоб зрозуміти, чому вони комутативні.
Варбо

59
minі, maxа також minimizeі maximizeє абсолютно неправильними іменами для функцій, які ви хочете написати. За замовчуванням minі maxмають набагато більше сенсу. Ви фактично ALMOST отримали правильні назви функцій. Ця операція називається затисканням або обмеженням, і ви написали дві функції обмеження. Я б запропонував capUpperBoundі capLowBound. Мені не потрібно нікому пояснювати, хто з них робить, це очевидно.
slebetman

Відповіді:


120

Як вже згадували інші: не створюйте функції з іменем, подібним до вбудованої, стандартної бібліотеки або загально широко використовуваної функції, але не змінюйте її поведінку. Можна звикнути до конвенції про іменування, навіть якщо це не має великого сенсу для вас з першого погляду, але неможливо буде міркувати про функціонування вашого коду, як тільки ви введете ті інші функції, які роблять те саме, але мають їхні імена помінялися місцями.

Замість того, щоб «перевантажувати» імена, що використовуються у стандартній бібліотеці, використовуйте нові імена, які точно передають те, що ви маєте на увазі. У вашому випадку вас не дуже цікавить «мінімум». Швидше, ви хочете обмежити значення. Математично це та сама операція, але семантично це не зовсім. То чому б не просто функцію

int cap(int value, int limit) { return (value > limit) ? limit : value; }

що робить те, що потрібно, і говорить це від свого імені. (Крім того, можна реалізувати capз точки зору , minяк показано в timster «s відповідь ).

Ще одна часто використовується назва функції clamp. Він займає три аргументи і "затискає" задане значення в інтервал, визначений двома іншими значеннями.

int clamp(int value, int lower, int upper) {
    assert(lower <= upper);  // precondition check
    if (value < lower) return lower;
    else if (value > upper) return upper;
    else return value;
}

Якщо ви використовуєте таке загальновідоме ім’я функції, будь-яка нова особа, яка приєднається до вашої команди (включаючи майбутнє, коли ви через деякий час повернетесь до коду), швидко зрозуміє, що відбувається, замість того, щоб проклинати вас за те, що їх переплутали, порушивши їх очікування щодо імен функцій, які вони думали, що знають.


2
Ви також можете назвати це getValueNotBiggerThan (x, limit) - це правильний підхід, і при гідному компіляторі функція буде вкладена, і отриманий машинний код буде точно таким же, як і за допомогою вбудованих
Falco

20
@Falco Я б сказав, що "cap" - це майже синонім "отримати вартість не більше", але я не збираюся сьогодні малювати цей сарай. ;-)
5gon12eder

1
clampшироко використовується у всіх видах обробки сигналів та подібних операціях (обробка зображень тощо), тож, безумовно, з цим я б і пішов. Хоча я б не сказав, що це вимагає верхньої та нижньої меж: я бачив це досить часто і лише в одному напрямку.
Во

1
Хотілося б також згадати clamp. І якщо це написано правильно, ви можете просто використовувати межу нескінченності / негативної нескінченності, коли ви хочете, щоб вона була пов'язана одним шляхом. Наприклад, щоб переконатися, що число не перевищує 255 (але не має нижньої межі), ви використовуєте clamp(myNumber, -Infinity, 255).
Кет

115

Якщо ви зробите таку функцію, яка minimize(4, 10)повертає 10 , то я б сказав, що це недоцільно, оскільки ваші колеги-програмісти можуть вас задушити.

(Гаразд, можливо, вони буквально не задушать вас до смерті, але серйозно ... Не робіть цього.)


2
Також цілком можливим є те, що, повернувшись до роботи над цим кодом через кілька років, ви самі витратите кілька годин, намагаючись з’ясувати, чому ваші цифри помиляються, коли ви телефонуєте мінімізувати ...
Падді,

Aww ... ця відповідь використовувала справді крутий (і досить високо проголосований) коментар. (Це був також перший коментар до відповіді, який допоміг гумористичній течії.)
TOOGAM

Я все одно хочу дістати перфокарти та закреслити DO NOT(з "НЕ шпинделя, не згортайте та не змішуйте"). Хтось, хто реалізував щось подібне, отримав би картку.
Завод-Муза

26

Згладжування функції чудово, але не намагайтеся змінювати значення існуючих термінів

Добре створити псевдонім функції - загальні бібліотеки роблять це постійно .

Однак погана ідея використовувати терміни таким чином, що суперечить загальному використанню, як-от ваш приклад, де слід враховувати максимум і мінімум, що слід враховувати. Це заплутано для інших програмістів, і ви будете робити собі загрозу, навчаючи себе продовжувати тлумачити ці терміни нестандартно.

Тож у вашому випадку відмовтесь від мови «мінімум / максимум», яку ви вважаєте заплутаною, і створіть свій власний, легкий для розуміння код.

Відновлення вашого прикладу:

int apply_upper_bound(int x, int y)
{
    return min(x, y);
}


int apply_lower_bound(int x, int y)
{
    return max(x, y)
}

Як додатковий бонус, кожного разу, коли ви дивитесь на цей код, ви будете нагадувати собі про те, як у мові програмування використовуються min та max . Врешті-решт це стане сенсом у вашій голові.


4
Я думаю, ви неправильно зрозуміли застосування minта maxщо заплутує ОП. Це коли minвикористовується для встановлення фіксованої верхньої межі деякого значення. get_lower_valueбуло б настільки ж непротилежним у цій програмі. Якби я вибрав альтернативну назву для цієї операції, я назвав би це суперсумом , хоча я не впевнений, скільки програмістів відразу це зрозуміють.
близько

3
@leftaroundabout: підсумкова множина {1, 2} дорівнює 2, тому не використовуйте ім'я supremumдля функції get_lower_value, визначеної вище, для простого виклику min. Це викликає у наступного програміста точно таку ж проблему, як і його виклик maximise. Я б запропонував зателефонувати apply_upper_bound, але я не впевнений, що це ідеально. Це все-таки дивно, оскільки він працює так само, як і залежно від того, коли ви поставите параметри, але назва означає, що один з параметрів - "значення", а інший - "пов'язаний", і що вони якось відрізняються.
Стів Джессоп

1
Я думаю, ви по суті покладаєтесь на того, щоб читач не надто знайомий зі словом supremum, щоб вони сприйняли ваше значення, а не англійське значення. Добре визначити жаргон локальним для вашого коду, але своєрідним питанням є те, що робити, коли жаргон, який ви хочете, безпосередньо суперечить уже знайомому значенню, і, боюся, я думаю, що ви все ще робите це (для певна версія "англійської мови" стосується лише тих, хто вивчав теми STEM)
Стів Джессоп

3
Ця політика "Згладжування функції чудово, але не намагайтеся змінити значення існуючих термінів" ідеально і красиво виражена. По-друге, ідея, яку ви не повинні перейменовувати таким чином, що є заплутаною у відношенні до вбудованих функцій (і: навіть якщо вбудовані функції погано названі / дурні / заплутані), є ідеальною ідеєю. Приклад max / min, який з’явився на цій сторінці, це загальна плутанина, хе.
Fattie

1
Гаразд, я відредагував відповідь, щоб використати "apply_upper_bound", який обидва відповідає міркуванням ОП і уникає перевантаження термінології. Багатослів’я - це не проблема. Я не збираюся писати тут ідеальне ім'я методу, просто встановіть основні правила іменування псевдонімів. ОП може відредагувати його на все, що йому здається найбільш зрозумілим і стислим.
Тім Грант

12

Я люблю це питання. Давайте розбимо, хоча.

1: Чи слід вписати один рядок коду?

Так, я можу привести безліч прикладів, де ви могли це зробити. Можливо, ви застосовуєте введені параметри або ховаєте конкретну реалізацію за інтерфейсом. У своєму прикладі ви фактично приховуєте виклик статичного методу.

Крім того, ви можете зробити багато речей в одному рядку в ці дні.

2: Чи заплутані назви "Мін" та "Макс"

Так! Вони цілком є! Чистий гуру кодування перейменовує їх у "FunctionWhichReturnsTheLargestOfItsParameters" або щось подібне. На щастя, у нас є документація та (якщо вам пощастило) IntelliSense та коментарі, щоб допомогти нам, щоб кожен, хто плутається у назвах, міг прочитати, що вони повинні робити.

3: Якщо ви самі перейменовуєте їх на щось інше.

Так, іди. Наприклад, у вас можуть бути:

class Employee
{
    int NumberOfHolidayDaysIShouldHave(int daysInLue, int maxAllowableHolidayDays)
    {
         // Return the number of days in lue, but keep the value under the max allowable holiday days!
         // Don't use max, you fool!!
         return Math.Max(daysInLue, maxAllowableHolidayDays)
    }
}

Це додає сенсу, і абонент не повинен або хоче знати, як обчислити значення.

4: Якщо ви перейменовуєте "min" на "maximize"

Ні!! ти здурів?! Але так, питання підкреслює, що різні люди читають різні значення в імена функцій та об'єктів. Те, що одна людина вважає ясним і звичайним, інше вважає непрозорим і заплутаним. Тому ми маємо коментарі. Натомість слід написати:

// Add x and y, but don't let it go over 255
s = min(x + y, 255);

Потім, коли хтось читає

// Add x and y, but don't let it go over 255
s = max(x + y, 255);

вони знають, що ти помилився.


6
Смішно! У вашому прикладі ви зробили точну помилку, з якою стосується op: ви хочете, щоб кількість відпусток не було більше maxHolidaysAllowed, тож вам потрібно min (a, b)
Falco

14
Якщо чистий код справді говорить про те, що такі глузливі імена, як FunctionWhichReturnsTheLargestOfItsParametersце є доброю справою, я не хочу цього робити.
Девід Хаммен

1
@Falco lol ой !!!
Еван

4
@DavidHammen: насправді це не так, оскільки жоден реальний стиль програмування не ставить бородавку FunctionWhichReturnsна передню частину кожної функції (що не кидає винятку і не припиняє). Ви можете закінчити getMinimum, getLarger(або getLargestз більш ніж двома входами), проте, дотримуючись реальних порад відповідно до того, що (a) чисті функції та / або "геттери" повинні використовувати бородавку get, (b) англійські слова не повинні бути скорочені у імена. Зрозуміло, що це занадто багатослівно для тих, хто вирішив викликати такі функції max.
Стів Джессоп

1
так, дивіться коментар @ falco. я не міг реально виправити це після цього!
Еван

4

Ні . Не робіть функції з іменами, дуже схожими на вбудовані функції, але які насправді роблять навпаки . Це може здатися вам інтуїтивно зрозумілим, але це буде дуже бентежно для інших розробників і навіть для себе якийсь час у майбутньому, коли у вас буде більше досвіду.

Сенс max"максимум", але ваше "інтуїтивне" розуміння - це щось на кшталт "до максимуму". Але це просто неправильне розуміння функції, а зміна назви з maxна maximumне повідомляє вашу різну інтерпретацію. Навіть якщо ви впевнені, що мовні дизайнери допустили помилку, не робіть подібного.

Але змінити ім'я так, cap(x, limit)як було запропоновано, було б добре, оскільки воно чітко повідомляє про наміри, навіть якщо воно просто завершує роботу min.


3

Те, що може вас бентежити, - це або використання функції Capped у назві функції, або розуміння того, що означає розміщення кришки. Це обмежувач і не вимагає максимуму нічого.

Якщо вас запитують про найнижчу, найменшу чи ранню, чи вважаєте ви, що Макс є відповідною функцією?

Залиште min і max у спокої. Пишіть тести, щоб принаймні ви вдруге виправтеся.

Якщо вам потрібно так багато використовувати ці функції у вашому проекті, ви створите якусь підказку, яка допоможе вам уточнити, яку саме використовувати. Начебто <або>, широка частина рота стикається з більшим значенням.


1
+1 для можливої ​​плутанини термінології як основної проблеми. Я думаю, що плутанина починається з коментаря "поверніть суму, максимум 255", тому він вважає, що maxфункція є більш підходящою, але логічно розумною minє те, що він насправді шукає.
Реванш

2

Щоб відповісти на ваше запитання: Чи є якась інша причина, яку це було б недоцільно? Що з груповим проектом? Має сенс, що ти хочеш власних функцій, що не проблема. Просто переконайтеся, що вони перебувають у вашому власному класі помічників, і вони не можуть легко телефонувати для інших, якщо вони не імпортують його. (Joes.Utilities.)

Але щоб переглянути ще раз свою проблему, я б замість цього подумав:

return (input >= 255) ? 255 : input;

Ви заплутуєтесь, оскільки намагаєтесь застосувати свою мозкову логіку до цих функцій min / max. Натомість просто говоріть англійською. в іншому випадку .ifinputgreater than or equal to 255 then return 255returninput

Який:

if (input >= 255) {
   255 
} else {
   input
}

Моя думка. Ви переходите до функцій max / min з неправильних причин, швидкість цих речей незначна. Робіть те, що має сенс.


1
Один з моїх старших колег завжди говорив "Нехай комп'ютер задумає тебе".

1

Поки я розумію вашу проблему, я б не хотів цього робити. Було б краще просто просвердлити свій череп, що роблять min () та max ().

Більшість програмістів знають, що виконують функції min () та max () - навіть якщо, як і ви, вони іноді борються зі своєю інтуїцією, якою користуватися в будь-який момент часу. Якщо я читаю програму і бачу max (x, y), я одразу знаю, що це робить. Якщо ви створите свою власну функцію "псевдонім", той, хто читає ваш код, не знатиме, що робить цей псевдонім. Вони повинні знайти вашу функцію. Це зайво порушує потік читання і змушує читача зайнятись додатковим мисленням, щоб зрозуміти вашу програму.

Якщо у вас виникли проблеми з розібранням, який використовувати в якийсь момент, я б сказав, додайте коментар, що пояснює це. Тоді, якщо майбутній читач аналогічно плутається, ваш коментар повинен прояснити це. Або якщо ви зробите це неправильно, але коментар пояснює, що ви намагалися зробити, людина, яка намагається налагодити це, матиме підказку.

Як тільки ви псевдонім функцію, тому що ім'я стикається з вашою інтуїцією ... це єдиний випадок, коли це проблема? Або ти збираєшся в інших функціях? Можливо, вас бентежить "читання" і вам стає легше сприймати це як "прийняти", ви змінюєте "додавати" на "StringTogether", "круглий" на "DropDecimals" тощо, і т.д. і ваші програми будуть незрозумілі.

Дійсно, років тому я працював з програмістом, якому не сподобалися всі пунктуації в C. Тому він написав купу макросів, щоб він написав "THEN" замість "{" та "END-IF" замість "}" та десятки інших таких підстановок. Тоді, коли ви намагалися читати його програми, це вже навіть не схоже на С, це було як би вивчити зовсім нову мову. Я зараз не пам'ятаю, чи "І" перекладено на "&" чи "&&" - і в цьому справа. Ви підриваєте інвестиції, які інвестували люди у вивчення мови та бібліотеки.

З цього приводу я б не сказав, що функція, яка не робить нічого, крім виклику стандартної функції бібліотеки, обов'язково погана. Якщо сенс вашої функції полягає не в створенні псевдоніму, а в інкапсуляції поведінки, яка, як раз, є однією функцією, це може бути добре і належним чином. Я маю на увазі, якщо логічно і неминуче вам доведеться робити максимум в цей момент програми, тоді просто зателефонуйте до max. Але якщо вам доведеться виконати якийсь розрахунок, який сьогодні вимагає максимуму, але це може бути змінено в майбутньому, щоб зробити щось інше, тоді проміжна функція є доречною.


0

Добре перейменовувати вбудовані функції за умови, що нові імена роблять ваш код дуже зрозумілим, і його ніхто не пропустить. (Якщо ви використовуєте C / C ++, не використовуйте #define, оскільки це важко зрозуміти, що відбувається.) Назва функції має діяти як коментар, що пояснює, що робить викликовий код і чому він робить .

Ви не єдина людина, яка мала цю проблему з min та max, проте я все ще не бачив хорошого загального рішення, яке працює у всіх областях. Я думаю, що одна з проблем при іменуванні цих функцій полягає в тому, що два аргументи мають різне логічне значення, але вони подаються як однакові.

Якщо ваша мова дозволяє це, ви можете спробувати

return  calculatedDiscount.ButNoMoreThen(maxAllowedDiscount)

return  CDsInStocked.ButNoMoreThen(CasesInStock)

0

Немає.

Ви не пишете обгортки. Назви цих обгортків не дуже важливі.

Те, що ви намагаєтеся зробити, - це своєрідна затуманення коду. Ви винаходите додатковий шар, який виконує 2 цілі:

  1. Інші люди не можуть зрозуміти ваш код.
  2. Ви ніколи не навчитеся розуміти код інших людей.

Приховуючи речі, які вам не зручні, ви тільки завдаєте шкоди своєму коду зараз і собі в майбутньому. Ви не можете рости, залишаючись у зоні комфорту. Що вам потрібно - це навчитися працювати minі як maxпрацювати.


-1

Це нормально, і не дуже протизаконно використовувати Min, Max, щоб втриматись і підкреслити. Це також робиться за допомогою:

  • підлога () і стеля ()
  • затискач, ліміт, межі
  • і, звичайно, мод з високим порядком усічення.

У прошивці він датується більше, ніж MMX, який сам по собі передує сучасній 3D графіці, яка спирається на цю екстенсівну.

Замінивши стандартну функцію навіть на місцевому рівні, мене би хвилювало, назва похідної може бути кращою. Студенти на C ++, можливо, можуть перевантажувати свій незрозумілий клас


Вибачте, що з MMX?
Тобіа Тесан

Я думав про "насичені значення", де результат обмежений на межі. Ідея коду могла бути простішою, якщо вона не повинна включати граничні і переповнені тести (в графіку, щоб уникнути руху на велосипеді чи переходу позитиву, проходячи минулі межі негативу). PSUBSB / PSUBSW. Я визнаю, механізм може бути не однаковим, але ефект і мета функції є.
mckenzm

-1

Це добре в деяких випадках, але НЕ в вашому прикладі, тому що є набагато кращі способи слова це:
saturate, clamp, clipі т.д.


-1

Я вважаю за краще створити загальну функцію з назвою "обмежений"

//Assumes lower_bound <= upper_bound
template <typename T>
T bounded(T value, T lower_bound, T upper_bound){
    if (value < lower_bound)
        return lower_bound;
    if (value > upper_bound)
        return upper_bound;
    return value;
}

//Checks an upper (by default) or lower bound
template <typename T>
T bounded(T value, T bound, bool is_upper_bound = true){
    if (is_upper_bound){
        if (value > bound)
            return bound;
    }
    else {
        if (value < bound)
            return bound;
    }
    return value;
}

або з використанням 'min' та 'max'

//Assumes lower_bound <= upper_bound
template <typename T>
T bounded(T value, T lower_bound, T upper_bound){
    return max(min(value, upper_bound), lower_bound);
}

//Checks an upper (by default) or lower bound
template <typename T>
T bounded(T value, T bound, bool is_upper_bound = true){
    if (is_upper_bound)
        return min(value, bound);
    else
        return max(value, bound);
}

-1

Як щодо виклику своїх функцій:

atmost(x,255): поверніть найменше значення x або 255.

atleast(10,x): повертайте вище x або принаймні 10.


-1

min(x+y, MAX_VALUE); матиме набагато більше значення, ніж myCustomFunction(x, y);

Тож відповідь ТАК, це недоцільно . Це лише псевдонім для вашої мови мозку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.