Синтаксис функций - 2: аргументы

Мы определили, как лучше всего описывать функции. Но функция - это довольно сложный объект, обладающий многими фичами. Рассмотрим следующие вопросы:
- Передача аргументо в фукнцию (по порядку и по именам)
- Аргументы функций по умолчанию

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

Передача аргументов по порядку очевидна - аргументы просто перечисляются через запятую. Это стандартный синтаксис, применяемый практически во всех ЯП.
Передача по имени встречается гораздо реже.
Обычно для связывания имени и значения используют какие-то спецсимволы, типа стрелок -> => или чего-то подобного. Например,  в C# используется двоеточие:

foo( "Hello world",  x: 10.2, y: 29.3);

В Ada используется стрелочка:

foo(X => 5, Y => 3 * 45);

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

Любая функция - это область видимости. Имя функции также является именем пространства имен, а это значит, что по идее, возможен доступ к внутреннему содержимому функции через оператор "точка" (более того, такой доступ возможен для публичных статических переменных, объявленных внутри функции).

def Foo()
{
 public static int x;
};
Foo.x = 10;

В точке вызова функции создается стековый фрейм, условно соответствующий понятию "объект функции". То есть при вызове функции доступны также ее локальные переменные.

def Foo(int x, y) {}
Foo(Foo.x=10, Foo.y=20);

Фактически, это и есть передача аргументов по имени. Для сокращения синтаксиса я ввел понятие "контекстная область видимости". В отличие от прямой области видимости (все доступно напрямую, без каких-либо квалификаторов доступа), контекстная область доступна как-бы через некий "квалификатор по умолчанию", определяемый контекстом. В нашем случае этот контекст - вызов функции (круглые скобки), и поэтому окончательный вариант синтаксиса такой

Foo(.x=10, .y=20);


Оператор "унарная точка" как раз и является вполне логичным решением доступа к контекстной области видимости. Кстати, этот оператор применяется также во многих других случаях, так как концепция "контекстной области видимости" оказалась весьма удачной и органично вписалась в синтаксис и семантику языка.



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



def Foo(int x = 0, int y = 0) {}



Если при вызове функции не указывать аргумент - будет взято значение по умолчанию.

В традиционных языках типа C++ и C# можно не указывать только крайние справа аргументы. В большинстве случаев этого достаточно, но для универсальности синтаксиса я ввел возможность обращаться к аргументу по умолчанию в любой позиции списка аргументов. Для этого используется универсальный символ - placeholder "_" (подчеркивание). Например, вышеописанная функция Foo() может быть вызвана следующим образом:
Foo(); // Foo(0,0), оба аргумента по умолчанию

Foo(1); // Foo(1,0), последний аргумент по умолчанию

Foo(1,2); // обычный вызов

Foo(_,3); // Foo(0,3), первый аргумент по умолчанию а второй задан явно

Foo(.y=3); // то же самое, но с передачей по имени

Foo(.y(3)); // то же самое, но инициализация в синтаксисе
конструктора

Foo(.y(_)); // забавный вариант - фактически все аргументы по умолчанию, но таким вот хитрым способом

Foo(1, _+4); // использование значения аргумента по умолчанию в арифметическом выражении
Foo(.y(_+4)); // тоже, но с передачей по имени


Последние два примера интересны тем, что в отличие от всех других языков, в Neo имеется возможность использовнания значений аргументов по умолчанию не напрямую, а в составе выражений. Для этого используется символ "_". При рассмотрении понятия "атрибуты" будет показано, как получить значения по умолчанию любых аргументов любых функций в любом месте программы (в Neo возможно и такое!). В большинстве же случаев такого синтаксиса будет вполне достаточно.











No comments:

Post a Comment