У деяких англійських акцентах, коли ми швидко кажемо «two for», це звучить як «two fer». «Two-for-one» означає, що, купивши одну річ, другу ми отримуємо безкоштовно. Тож фраза «two-fer» часто означає пропозицію «два за ціною одного».
Уявімо пекарню, яка має святкову пропозицію: можна купити два печива за ціною одного («two-fer one!»). Ми приймаємо пропозицію і (дуже щедро) вирішуємо віддати зайве печиво комусь іншому в черзі.
Наше завдання - визначити, що ми скажемо, віддаючи зайве печиво.
Якщо ми знаємо імʼя людини (наприклад, якщо її звати Do-yun), то скажемо:
One for Do-yun, one for me.
Якщо ми не знаємо імʼя людини, то замість нього скажемо you.
One for you, one for me.
Ось кілька прикладів:
| Імʼя | Діалог |
|---|---|
| Alice | One for Alice, one for me. |
| Bohdan | One for Bohdan, one for me. |
| One for you, one for me. | |
| Zaphod | One for Zaphod, one for me. |
Odin підтримує типові аргументи. Типові аргументи - це корисна можливість, яка дозволяє викликати процедуру з різними наборами параметрів для випадків, коли потрібні схожі, але різні API.
Без типових аргументів ми могли б отримати вибух кількості процедур, потрібних для нашого API. Мови, які не підтримують типових аргументів, як-от Java, покладаються на перевантаження методів, щоб досягти того самого ефекту (ціною більшої кількості коду), або мусять надавати процедури з потенційно великим набором аргументів.
Розгляньмо приклад процедури greeting, у якій ми хочемо мати змогу вказати мову, чи записане імʼя великими літерами та чи додавати знак оклику в кінці привітання.
Після деякого аналізу ми виявили, що найбільша група користувачів вказує мову англійську, не переводить імʼя у верхній регістр і не хоче знака оклику в кінці, а друга за чисельністю група додає знак оклику в кінці привітання.
Ми могли б створити одну процедуру з усіма аргументами:
greeting :: proc(name: string, language: Language, do_uppercase: bool, add_exclamation: bool) {
...
}
Це змусило б усіх користувачів читати документацію до всіх аргументів і завжди їх заповнювати.
Без типових аргументів ми могли б також визначити кілька процедур із різними наборами параметрів:
greeting_common :: proc(name: string) {...}
greeting_with_exclamation :: proc(name: string) {...}
greeting_general :: proc(name: string, language: Language, do_uppercase: bool, add_exclamation: bool) {...}
// Odin supports overloading but it has to be explicitly defined
greeting :: proc {
greeting_common,
greeting_with_exclamation,
greeting_general,
}
Якщо мова, яку ми використовуємо, підтримує типові аргументи, як-от Odin, ми можемо просто надати слушні типові значення найрідше вживаним аргументам. Ті, хто викликає процедуру, можуть пропустити типові аргументи, і тоді процедура використає надані типові значення, або ж перевизначити їх.
greeting :: proc(name: string, language: Language = Language.English, do_uppercase : bool = false, add_exclamation: bool = false) {...}
// Note: because Odin supports type inference, we can simplify the interface.
greeting :: proc(name: string, language:= Language.English, do_uppercase := false, add_exclamation:= false) {...}
Процедуру можна викликати, коли всі аргументи мають типові значення:
greeting("John Doe")
Аргументи, важливі для того, хто викликає, можна перевизначити:
greeting("John Doe", Language.Spanish)
Якщо потрібні нам аргументи йдуть у правильному позиційному порядку, як у прикладі вище, немає потреби називати їх, як у прикладі вище, але якщо треба пропустити деякі з них, доведеться назвати аргументи після першого пропущеного.
greeting("John Doe", add_exclamation=true)
У цій вправі ми реалізуємо процедуру, яка має виділяти памʼять під рядок, який повертає. За звільнення памʼяті під цей рядок відповідає той, хто викликає процедуру.
// The procedure will be called like that:
str := two_fer("Alice")
// ...
// and eventually the caller will delete the string
delete(str)
Нам також може бути цікавою офіційна документація Odin про типові аргументи та іменовані аргументи в Odin.