As a special service "Fossies" has tried to format the requested source page into HTML format (assuming markdown format).
Alternatively you can here view or download the uninterpreted source code file.
A member file download can also be achieved by clicking within a package contents listing on the according byte size field.

Kotlin allows us to provide implementations for a predefined set of operators on our types. These operators have fixed symbolic representation (like `+`

or `*`

) and fixed (see grammar). To implement an operator, we provide a member function or an extension function with a fixed name, for the corresponding type, i.e. left-hand side type for binary operations and argument type for unary ones.

Here we describe the conventions that regulate operator overloading for different operators.

Expression | Translated to |
---|---|

`+a` |
`a.plus()` |

`-a` |
`a.minus()` |

`!a` |
`a.not()` |

This table says that when the compiler processes, for example, an expression `+a`

, it performs the following steps:

- Determines the type of
`a`

, let it be`T`

. - Looks up a function
`plus()`

with no parameters for the receiver`T`

, i.e. a member function or an extension function. - If the function is absent or ambiguous, it is a compilation error.
- If the function is present and its return type is
`R`

, the expression`+a`

has type`R`

.

Expression | Translated to |
---|---|

`a++` |
`a.inc()` + see below |

`a--` |
`a.dec()` + see below |

These operations are supposed to change their receiver and (optionally) return a value.

.`inc()/dec()`

shouldn’t mutate the receiver object

By “changing the receiver” we meanthe receiver-variable, not the receiver object. {:.note}

The compiler performs the following steps for resolution of an operator in the *postfix* form, e.g. `a++`

:

- Determines the type of
`a`

, let it be`T`

. - Looks up a function
`inc()`

with no parameters, applicable to the receiver of type`T`

. - If the function returns a type
`R`

, then it must be a subtype of`T`

.

The effect of computing the expression is:

- Store the initial value of
`a`

to a temporary storage`a0`

, - Assign the result of
`a.inc()`

to`a`

, - Return
`a0`

as a result of the expression.

For `a--`

the steps are completely analogous.

For the *prefix* forms `++a`

and `--a`

resolution works the same way, and the effect is:

- Assign the result of
`a.inc()`

to`a`

, - Return the new value of
`a`

as a result of the expression.

Expression | Translated to |
---|---|

`a + b` |
`a.plus(b)` |

`a - b` |
`a.minus(b)` |

`a * b` |
`a.times(b)` |

`a / b` |
`a.div(b)` |

`a % b` |
`a.mod(b)` |

`a..b` |
`a.rangeTo(b)` |

For the operations in this table, the compiler just resolves the expression in the *Translated to* column.

Expression | Translated to |
---|---|

`a in b` |
`b.contains(a)` |

`a !in b` |
`!b.contains(a)` |

For `in`

and `!in`

the procedure is the same, but the order of arguments is reversed. {:#in}

{:#Equals}

Expression | Translated to |
---|---|

`a == b` |
`a?.equals(b) ?: b === null` |

`a != b` |
`!(a?.equals(b) ?: b === null)` |

*Note*: `===`

and `!==`

(identity checks) are not overloadable, so no conventions exist for them

The `==`

operation is special in two ways:

- It is translated to a complex expression that screens for
`null`

’s, and`null == null`

is`true`

. - It looks up a function with a specific
*signature*, not just a specific*name*. The function must be declared as

Or an extension function with the same parameter list and return type.

Symbol | Translated to |
---|---|

`a > b` |
`a.compareTo(b) > 0` |

`a < b` |
`a.compareTo(b) < 0` |

`a >= b` |
`a.compareTo(b) >= 0` |

`a <= b` |
`a.compareTo(b) <= 0` |

All comparisons are translated into calls to `compareTo`

, that is required to return `Int`

.

Symbol | Translated to |
---|---|

`a[i]` |
`a.get(i)` |

`a[i, j]` |
`a.get(i, j)` |

`a[i_1, ..., i_n]` |
`a.get(i_1, ..., i_n)` |

`a[i] = b` |
`a.set(i, b)` |

`a[i, j] = b` |
`a.set(i, j, b)` |

`a[i_1, ..., i_n] = b` |
`a.set(i_1, ..., i_n, b)` |

Square brackets are translated to calls to `get`

and `set`

with appropriate numbers of arguments.

Symbol | Translated to |
---|---|

`a(i)` |
`a.invoke(i)` |

`a(i, j)` |
`a.invoke(i, j)` |

`a(i_1, ..., i_n)` |
`a.invoke(i_1, ..., i_n)` |

Parentheses are translated to calls to invoke with appropriate number of arguments.

Expression | Translated to |
---|---|

`a += b` |
`a.plusAssign(b)` |

`a -= b` |
`a.minusAssign(b)` |

`a *= b` |
`a.timesAssign(b)` |

`a /= b` |
`a.divAssign(b)` |

`a %= b` |
`a.modAssign(b)` |

For the assignment operations, e.g. `a += b`

, the compiler performs the following steps:

- If the function from the right column is available
- If the left-hand side can be assigned to and the corresponding binary function (i.e.
`plus()`

for`plusAssign()`

) is available, report error (ambiguity). - Make sure its return type is
`Unit`

, and report an error otherwise. - Generate code for
`a.plusAssign(b)`

- If the left-hand side can be assigned to and the corresponding binary function (i.e.
- Otherwise, try to generate code for
`a = a + b`

(this includes a type check: the type of`a + b`

must be a subtype of`a`

).

*Note*: assignments are *NOT* expressions in Kotlin.

**Discussion of the ambiguity rule**: We raise an error when both `plus()`

and `plusAssign()`

are available only if the lhs is assignable. Otherwise, the availability of `plus()`

is irrelevant, because we know that `a = a + b`

can not compile. An important concern here is what happens when the lhs *becomes assignable* after the fact (e.g. the user changes *val* to *var* or provides a `set()`

function for indexing convention): in this case, the previously correct call site may become incorrect, but not the other way around, which is safe, because former calls to `plusAssign()`

can not be silently turned into calls to `plus()`

.