▪️ПОДДЕРЖКА ИМЕНОВАННЫХ АРГУМЕНТОВ
👋 Привет! Я очень люблю изучать разные языки программирования, а затем сравнивать их между собой по тем или иным аспектам дизайна.
И вот сегодня хочется поговорить про поддержку именованных аргументов.
Для начала разберемся, что же это такое. 🧐 Смотрите, при вызове функции мы можем передать ей её входные аргументы. И контракт на то, какой аргумент, что означает, обычно, задается по-разному для того, кто реализует функцию и для того, кто её вызывает.
Для реализации функции основной контракт для аргумента - это его имя, например,
А для вызывающей стороны у нас уже тут другой контракт: по номеру аргумента, а имя мы не пишем вовсе.
Это позволяет нам спокойно переименовывать аргументы функции, и это гарантированно не будет иметь никакого эффекта для других. Но если мы поменяем порядок аргументов, то это уже настоящий breaking change нашего API.
Контракт также может определяться типом аргументов или их количеством, особенно если наш язык программирования поддерживает перегрузки. Например, как это сделано в Julia:
Однако по-прежнему у нас два разных контракта на внешнее и внутреннее использование. Проблема передачи аргументов по порядку возникает, когда аргументов становится много; использовать такую функцию становится неудобно, особенно когда многие аргументы могут иметь значение по умолчанию. Как раз для решения этой проблемы, некоторые ЯП поддерживают передачу аргументов не по порядку, а по их имени. Так например сделано в Python. Причем мы можем одновременно использовать оба способа.
Это очень удобно, но вводит новый строгий контракт: мы не можем свободно переименовывать аргументы, так как не знаем, каким образом их передают пользователи нашей функции.
В JavaScript нет именованных аргументов, но мы можем добиться похожего эффекта, используя передачу объекта и деструктуризацию:
И тут с одной стороны нет проблем описанных в Питоне, т.к. такие вот аргументы описываются особым образом.
А с другой стороны вылазит множество новых. Например, для работы деструктуризации важно, чтобы у аргумента всегда было значение. Для необязательных параметров приходится писать так:
Такие вот параметры приходится особым образом описывать в JSDoc, чтобы оно корректно работало везде.
Мы не можем бесшовно перейти от формы передачи по номеру к передаче по имени, т.к. у нас меняется тип данных.
К тому же, это просто зашумляет декларацию функции.
Хорошо, а как можно иначе? 💡Мне вот очень нравится подход в Julia: там есть поддержка именованных аргументов, но они обозначаются явно.
И здесь у нас строгий контракт: все что до
Выглядит очень декларативно и чисто, а добавление новых именованных параметров не приводит к изменению типа аргумента.
Казалось бы такая простая вещь, как передача аргументов в функцию, а столько нюансов. Изучайте разные языки и расширяйте кругозор. Всем базы! 🚀
👋 Привет! Я очень люблю изучать разные языки программирования, а затем сравнивать их между собой по тем или иным аспектам дизайна.
И вот сегодня хочется поговорить про поддержку именованных аргументов.
Для начала разберемся, что же это такое. 🧐 Смотрите, при вызове функции мы можем передать ей её входные аргументы. И контракт на то, какой аргумент, что означает, обычно, задается по-разному для того, кто реализует функцию и для того, кто её вызывает.
Для реализации функции основной контракт для аргумента - это его имя, например,
function extend(original, extender) {
// Мы работаем с аргументами по их имени
return Object.assign(original, extender);
}
А для вызывающей стороны у нас уже тут другой контракт: по номеру аргумента, а имя мы не пишем вовсе.
extend({a: 1}, {b: 2});
Это позволяет нам спокойно переименовывать аргументы функции, и это гарантированно не будет иметь никакого эффекта для других. Но если мы поменяем порядок аргументов, то это уже настоящий breaking change нашего API.
Контракт также может определяться типом аргументов или их количеством, особенно если наш язык программирования поддерживает перегрузки. Например, как это сделано в Julia:
function test(a :: String)
println(a)
end
function test(a :: Int)
return a + 10
end
test("Hello world")
println(test(15))
Однако по-прежнему у нас два разных контракта на внешнее и внутреннее использование. Проблема передачи аргументов по порядку возникает, когда аргументов становится много; использовать такую функцию становится неудобно, особенно когда многие аргументы могут иметь значение по умолчанию. Как раз для решения этой проблемы, некоторые ЯП поддерживают передачу аргументов не по порядку, а по их имени. Так например сделано в Python. Причем мы можем одновременно использовать оба способа.
def test(a, b):
return a / b
# Передача по имени позволяет отвязаться от порядка
print(test(b = 10, a = 50))
# Здесь порядок важен
print(test(50, 10))
Это очень удобно, но вводит новый строгий контракт: мы не можем свободно переименовывать аргументы, так как не знаем, каким образом их передают пользователи нашей функции.
В JavaScript нет именованных аргументов, но мы можем добиться похожего эффекта, используя передачу объекта и деструктуризацию:
function test({a, b}) {
return a / b;
}
console.log(test({b: 10, a: 50}));
И тут с одной стороны нет проблем описанных в Питоне, т.к. такие вот аргументы описываются особым образом.
А с другой стороны вылазит множество новых. Например, для работы деструктуризации важно, чтобы у аргумента всегда было значение. Для необязательных параметров приходится писать так:
// Если не написать = {} и не передать параметры, то будет ошибка
function test(a, b, {c = 10, d = 15} = {}) {
return a / b + c / d;
}
Такие вот параметры приходится особым образом описывать в JSDoc, чтобы оно корректно работало везде.
/**
* @param opts
* @param opts.a
* @param opts.b
*/
function test({a, b}) {
return a / b;
}
Мы не можем бесшовно перейти от формы передачи по номеру к передаче по имени, т.к. у нас меняется тип данных.
К тому же, это просто зашумляет декларацию функции.
Хорошо, а как можно иначе? 💡Мне вот очень нравится подход в Julia: там есть поддержка именованных аргументов, но они обозначаются явно.
# Обратите внимание на ;
function test(a, b; c = 10, d = 15)
return a / b + c / d
end
test(50, 10; d = 55)
И здесь у нас строгий контракт: все что до
;
передается только по порядку, а все что после - только по имени.Выглядит очень декларативно и чисто, а добавление новых именованных параметров не приводит к изменению типа аргумента.
Казалось бы такая простая вещь, как передача аргументов в функцию, а столько нюансов. Изучайте разные языки и расширяйте кругозор. Всем базы! 🚀