Overloading

Several functions in one scope may share a name when their parameter lists differ. Together they form an overload set, and each call picks one member by looking at its arguments. Methods and constructors overload the same way.

func Describe(value: int) {
    PrintLine("an integer: {}", value);
}

func Describe(value: float64) {
    PrintLine("a number with a fraction: {}", value);
}

func Area(side: int) -> int {
    return side * side;
}

func Area(width: int, height: int) -> int {
    return width * height;
}

Describe(42) and Describe(2.5) run different functions; Area(4) and Area(4, 5) likewise.

What may differ

Overloads must differ in their parameters — the number of them or their types. The result type takes no part: a call does not say what type it wants back, so two functions that differ only in their result could never be told apart, and the second is refused.

func Half(value: int) -> int {
    return value / 2;
}

func Half(value: int) -> float64 {   // error
    return 0.0;
}
error: function 'Half' has the same parameter signature as an earlier overload

Parameter names do not count either. When the difference really is in the result, give the functions different names.

How a call is resolved

Declaration order never decides a call. The compiler finds every overload that could accept the arguments and keeps the best, in these steps:

  1. Fixed parameter lists first. Overloads without a variadic parameter are tried first; a variadic overload is chosen only when none of them accepts the call.
  2. Exact matches first. Within that group, overloads whose parameter types are exactly the argument types are tried before overloads that need any conversion.
  3. The most specific overload. Among the overloads that accept the call, one that is no worse for any argument and better for at least one wins. For each argument, from best to worst:
    RankThe argument's type is…
    1exactly the parameter's type
    2the same type, differing only in a view's writability (var int[..] for int[..])
    3the same type reached through a borrow or a read through a reference (int32 for &int32, &var int32 for int32)
    4any other type the argument converts to, such as an unsuffixed integer literal to another integer type
  4. No default needed. Among overloads still tied, one that the arguments fill without using a default value wins.
  5. Not generic. Then a function without type parameters wins over a generic one.

Overloads still tied after that make the call ambiguous, which is an error.

func G(x: int) -> int { return 1; }
func G(x: int, y: int = 1) -> int { return 2; }

func H<T>(x: T) -> int { return 3; }
func H(x: int) -> int { return 4; }

func V(args: int...) -> int { return 5; }
func V(a: int, b: int) -> int { return 6; }

func W(x: float64) -> int { return 7; }
func W(x: int32) -> int { return 8; }
CallCallsBecause
G(2)G(x: int)step 4 — the other needs its default
G(2, 3)G(x: int, y: int)only it takes two arguments
H(1)H(x: int)step 5 — the generic one ties but loses
H(true)H<T>(x: T)only it accepts a bool
V(1, 2)V(a: int, b: int)step 1 — a fixed list is preferred
V(1, 2, 3)V(args: int...)no fixed overload takes three arguments
W(small)W(x: int32)step 2 — small is an int32
W(2.0)W(x: float64)only it accepts a float64

A literal is not converted to suit an overload, except that an unsuffixed integer literal may become another integer type. Area(4, 2.0) matches nothing when the overloads take (int, int) and (float64, float64):

error: no matching overload for 'Area' with argument types (int, float64)

Ambiguous calls

When two overloads remain after every step, the compiler names both:

func F(x: int8) -> int { return 8; }
func F(x: int64) -> int { return 64; }

func Main() -> int {
    return F(5);   // error
}
error: call to 'F' is ambiguous: 2 overloads accept argument types (int)
  note: candidate 'F(x: int8)' declared at …
  note: candidate 'F(x: int64)' declared at …
  help: rename one of the overloads, or remove a default value that makes them overlap

The literal 5 converts to both int8 and int64 at rank 4, and nothing else separates them. A suffix picks one — F(5i8) is an exact match.

See also