Limited operator overloading

Operator overloading defines the behavior of certain binary operators for certain types.

struct Vec { x int y int } fn (a Vec) str() string { return '{${a.x}, ${a.y}}' } fn (a Vec) + (b Vec) Vec { return Vec{a.x + b.x, a.y + b.y} } fn (a Vec) - (b Vec) Vec { return Vec{a.x - b.x, a.y - b.y} } fn main() { a := Vec{2, 3} b := Vec{4, 5} mut c := Vec{1, 2} println(a + b) // "{6, 8}" println(a - b) // "{-2, -2}" c += a //^^ autogenerated from + overload println(c) // "{3, 5}" }

Operator overloading goes against V's philosophy of simplicity and predictability. But since scientific and graphical applications are among V's domains, operator overloading is an important feature to have in order to improve readability:

a.add(b).add(c.mul(d)) is a lot less readable than a + b + c * d.

Operator overloading is possible for the following binary operators: +, -, *, /, %, <, ==.

Implicitly generated overloads

  • == is automatically generated by the compiler, but can be overridden.

  • !=, >, <= and >= are automatically generated when == and < are defined. They cannot be explicitly overridden.

  • Assignment operators (*=, +=, /=, etc) are automatically generated when the corresponding operators are defined and the operands are of the same type. They cannot be explicitly overridden.

Restriction

To improve safety and maintainability, operator overloading is limited.

Type restrictions

  • When overriding < and ==, the return type must be strictly bool.
  • Both arguments must have the same type (just like with all operators in V).
  • Overloaded operators have to return the same type as the argument (the exceptions are < and ==).

Other restrictions

  • Arguments cannot be changed inside overloads.
  • Calling other functions inside operator functions is not allowed (planned).