4 2 Контракты и выбор

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

fn retDiv(let const a : int,let const b : int, {b != 0}) 
   -> (let const : int)
{
    return a / b;
}

Проверяет что деление ок.

fn returnConc(let const a : string,let const b : string)
   -> (let const : string, {@.len() > 0})
{
    return a + b;
}

Проверяет что возвращаемая строка не пуста.

fn test(let a : int {>0}) 
{

}

Говорит, что a должно быть больше нуля.

Оператор выбора

Функции могут иметь выбор явный/неявный. Функции могут иметь уникальное полное имя (имя + расширение)

fn run::now default() // ключевое слово default
{
    doTask();
}

fn run::after()
{
    sleep(1000);
    dotask();
}

run::after(); // Вызовет вторую функцию
run(); // Вызовет первую ()т.к. она default
run::() // Вызовет любую подходящую функцию (первую)

Мы можем воспользоваться SFINAE и вызвать функцию наиболее подходящую под параметры без указания расширения.

fn sum::a(let a : int, let b : int) -> (let int) {return a + b;}
fn sum::b(let a : real, let b : real) -> (let real) {return a + b;}

let const a = sum(1,2); // 3
let const b = sum(0.1, 0.2); // 0.3

Мы можем применить интроспекцию и передать в функцию её расширение как переменную.

fn test::<let t : fn::ext::enum>()
{
    if t == ::run
    {
        doTask();
    }
    elif t == ::runLater
    {
        sleep(1000);
        doTask();
    }
}

test::run();    // Вызовет первую ветку
test::<run>();

test::runLater(); // Вызовет вторую ветку

Запрет общего имени

Можно запретить использование расширения имени.

func:: = null;
fn func::a()
{ ... }
fn func::b()
{ ... }

func::a(); //ok
func::b(); //ok
func(); // error

SFINAE

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

// Мы используем здесь числа для различия функций
fn func::0(a : int, {a <= 100})
{
    println!("<= 100");
}

fn func::1(a : int, {a > 100})
{
    println!("> 100");
}

func(150); // Выведет вторую функцию
func(90);  // Выведет первую функцию

В случае если функция всё равно не найдена будет выброшено исключение или CE.