A Tour of Morfa

Overloading

Functions may be overloaded: two functions with the same name and declared in the same scope are said to be in the same overload set. The compiler determines which one should be called by looking at the number and the types of arguments (return types are not taken into account).

func sumUpTo(n: int): int
{
    return n * (n+1) / 2;
}

func sumUpTo(from: int, upto: int)
{
    return sumUpTo(upto) - sumUpTo(from) + from;
}

unittest 
{
    var lhs = sumUpTo(10);    // obviously, this refers to the unary sumUpTo(),
    var rhs = sumUpTo(1, 10); // and this to the binary one.
    assert (lhs == rhs);
}

Things get more interesting if a function call matches more than one function declaration, as in the following code snippet:

import morfa.math.base: abs;

func closeTo(expected: float, actual: float)
{ 
    var error = abs((expected - actual) / expected);
    return error < 0.01;
}

func closeTo(expected: int32, actual: int32)
{
    return expected == actual;
}

unittest
{
    assert (    closeTo(1000000.0, 1000001));
    assert (not closeTo(1000000,   1000001));
}

In this case, for each call to closeTo the compiler chooses the most specific matching function declaration. For the first call, the choice is from the singleton set, as only one declaration may accept floating point arguments.

For the second call, the compiler considers both declarations, as the arguments may be treated as both int32 and float values. The second declaration is chosen since it is more specific. That is, all pairs of call arguments that match the second declaration match the first one as well, but not the other way around.