Функции

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

Примеры объявлений функций:

fn Add( i32 x, i32 y ) : i32; // Функция принимает два аргумента типов "i32" и возвращает значение типа "i32".
fn Sleep( f32 sec ); // Функция принимает один аргумент типа "f32" и не возвращает значения.
fn GetPi() : f64; // Функция не принимает аргументов и возвращает значение типа "f64".
fn Max( i64& x, i64& y ) : i64&; // Функция принимает два аргумента типов "i64" по ссылке и возвращает ссылку того же типа.

Аргументы

Функции могут принимать аргументы-значения и ссылочные аргументы. Ссылочные аргументы объявляются с использованием & после имени типа аргумента. Аргументы могут иметь модификаторы изменяемости mut или imut, указываемые после имени типа или после & (для ссылочных аргументов). Если модификатор изменяемости не указан, неявно будет применён модификатор imut.

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

Примеры аргументов:

fn Add( i32 imut x, i32 y ) : i32; // Неизменяемые аргументы-значения. Второй аргумент будет неизменяемым, т. к. к нему применён модификатор по умолчанию "imut"
fn Inc( u32 &mut x ); // Изменяемый ссылочный аргумент
fn GetLength( ust::string8 &imut str ) : size_type; // Неизменяемый ссылочный аргумент
fn GetNumZeros( ust::string8 & str ) : size_type;  // Неизменяемый ссылочный аргумент, т. к. к нему применён модификатор по умолчанию "imut"

Возвращаемое значение

Функция может не возвращать значений. Для этого можно или не указать тип возвращаемого значения, или указать тип void:

fn Sleep( f32 sec );
fn USleep( u64 ns ) : void;

Функция может возвращать значение. Для этого надо указать тип значения:

fn Add( i32 x, i32 y ) : i32; // тип возвращаемого значения - "i32"

Функция может возвращать ссылочное значение - изменяемое или неизменяемое. Для этого надо указать & после типа возвращаемого значения. После него можно опционально указать модификатор изменяемости mut или imut. Если модификатор изменяемости не указан, неявно будет применён модификатор imut.

fn Max( i64& x, i64& y ) : i64 &imut; // Функция вернёт неизменяемую ссылку типа "i64"
fn Max( u64& x, u64& y ) : u64 &; // Функция вернёт неизменяемую ссылку типа "u64", модификатор "imut" применён неявно
fn Max( u64 &mut x, u64 &mut y ) : i64 &mut; // Функция вернёт изменяемую ссылку типа "u64"

Перегрузка функций

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

fn Foo();
fn Foo(i32 x); // Ок, перегрузка с другим количеством параметров
fn Foo(f32 &imut x); // Ок, перегрузка с другим типом параметра
fn Foo(f32 &mut x); // Ок, перегрузка с с отличной изменяемостью параметра

Если у функций различается только что-то кроме параметров (возвращаемое значение, модификатор unsafe), то перегрузка невозможна. Также невозможна перегрузка с различием только в изменяемости параметров-значений или перегрузка неизменяемого параметра по модификатору ссылочности.

fn Foo() : i32;
fn Foo() unsafe : f32; // Ошибка, перегрузка невозможна - сигнатура функций одинакова

fn Bar(i32 mut x);
fn Bar(i32 imut x); // Ошибка, перегрузка невозможна - различается только изменяемость параметра-значения

fn Baz(i32 imut x);
fn Baz(i32 &imut x); // Ошибка, перегрузка невозможна - различается только ссылочный модификатор неизменяемого параметра

Прототипы и реализации

Объявление функции, оканчивающееся на ; означает, что объявлен лишь прототип функции, если же после объявления функции следует блок её тела, обрамлённый в {}, то это объявление реализации.

// объявили прототип
fn Add( i32 x, i32 y ) : i32;

// позже объявили реализацию функции
fn Add( i32 x, i32 y ) : i32
{
     return x + y;
}

Вывод типа возвращаемого значения

Вместо типа возвращаемого значения функции можно указать ключевое слово auto. В этом случае тип возвращаемого значения выведется автоматически из оператора return.

fn Div( i32 x, i32 y ) : auto
{
    return x / y; // Тип будет "i32"
}

fn Abs( f32 x ) : auto
{
    // Во всех операторах "return" тип - "f32"
    if( x >= 0.0f ) { return x; }
    return -x;
}

Функции с выводом типа возвращаемого значения имеют ряд ограничений:

  • Они должны иметь тело
  • Они не могут рекурсивно звать сами себя
  • Они не могут быть членами структур или классов

Условное наличие функции

Иногда необходимо, чтобы функция отсутствовала, в зависимости от какого-либо условия. Особенно это может быть полезно в шаблонном коде. Для этого в Ü существует специальная конструкция - enable_if. Эта конструкция может быть указана после fn, опциональных constexpr, virtual, nomangle в объявлении функции. После этого указывается выражение, в () скобках. Выражение должно быть константой времени компиляции и иметь тип bool. Если выражение ложно - функция построена не будет, дальнейший её заголовок и тело не будут обрабатываться.

auto constexpr is_32bit = typeinfo</size_type/>.size_of == 4s;
// Функция будет существовать только на 32-битной платформе
fn enable_if( is_32bit ) Bar();

fn Foo()
{
    Bar(); // На 64-битной платформе будет ошибка компиляции - функция не найдена.
}