avatarGabriel Shanahan

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3739

Abstract

In actuality, <code>f()</code> calls <code>f.invoke()</code>, in the same way that <code>2 + 3</code> actually calls <code>2.plus(3)</code>. You can see this for yourself when you look at the definition of e.g. <a href="https://github.com/JetBrains/kotlin/blob/master/spec-docs/function-types.md#functions-with-022-parameters-at-runtime">Function1</a> and its counterparts.</p><p id="c8e2">Therefore, any object can be called like a function just by implementing the <code>invoke</code> operator:</p> <figure id="69b2"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FIJfB58EX2&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FIJfB58EX2&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="1a09">Hopefully this goes without saying, but implementing <code>invoke</code> is not always a good thing! You should think hard before making this decision.</p><h2 id="8807">ComponentN</h2><p id="2d05">The <code>componentN</code> family of operators are what enable <b>destructuring</b>, which we talked about in the lesson on <a href="https://readmedium.com/data-classes-97cbd6bfa0b7">data classes</a> (feel free to refresh your memory before moving on). <b>When you destructure an expression, what actually happens is that <code>component1</code>, <code>component2</code> etc. get called in turn to produce the individual parts of the result</b>:</p> <figure id="e5bf"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FAjhtJkLPZ&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FAjhtJkLPZ&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="271f">The same thing happens when you destructure expressions in a lambda:</p> <figure id="0323"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FhJNkFrLu4&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FhJNkFrLu4&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="ddd7">As was mentioned when we talked about <a href="https://readmedium.com/data-classes-97cbd6bfa0b7">data classes</a>, you can use <code>_</code> to omit a specific component. When you do that, the corresponding <code>componentN</code> method is not called at all:</p> <figure id="036e"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FRNGhbgaav&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FR

Options

NGhbgaav&image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="3443">Since <code>componentN</code> functions are operators, any class can implement destructuring:</p> <figure id="25c2"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FVVNQl-Qih&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FVVNQl-Qih&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><h2 id="38ff">Contains & RangeTo</h2><p id="de0b">The <code>contains</code> method is called when <code>in</code> is used, and the <code>rangeTo</code> method is called when <code>..</code> is used. Both can be overridden</p> <figure id="77dc"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2F86FP-End3&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2F86FP-End3&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="7372">However, this is rarely necessary. The standard library contains implementations of these operators for almost all reasonable situations, including numbers, characters, time and date objects, etc. If you do ever find yourself in a situation where you need to implement them, it’s very likely you can just call the builtin implementations:</p> <figure id="9d09"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2F-8EGYkSpG&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2F-8EGYkSpG&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><h1 id="9baa">Indexed array access</h1><p id="5fa4">Just so you know, <a href="https://kotlinlang.org/docs/operator-overloading.html#indexed-access-operator">it’s there</a>.</p><p id="c99c">Go back to <a href="https://readmedium.com/infix-functions-f2c328941939">Infix functions</a>, jump to the <a href="https://readmedium.com/table-of-contents-c52573cfa291">Table of Contents</a>, or continue to <a href="https://readmedium.com/type-aliases-ea59a5180880">Type Aliases</a>.</p><figure id="8ecd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*biBSB579iezsNvEQ_NMLBg.png"><figcaption><a href="https://www.etnetera.cz/prace-u-nas?utm_source=medium&amp;utm_medium=GabrielShanahan&amp;utm_campaign=KotlinPrimer&amp;utm_content=join-our-team&amp;utm_term=KotlinPrimer#pozice">Join me in Etnetera</a></figcaption></figure></article></body>

Operators

A short exposition of operators, and why they should be used sparingly. Special mentions of invoke, componentN, contains and rangeTo, and the index array access operator [].

— — — — — — — — — — — — — — —

THE CURRENT VERSION OF THIS ARTICLE IS PUBLISHED HERE.

— — — — — — — — — — — — — — —

Tags: #KOTLIN FEATURE

This article is part of the Kotlin Primer, an opinionated guide to the Kotlin language, which is indented to help facilitate Kotlin adoption inside Java-centric organizations. It was originally written as an organizational learning resource for Etnetera a.s. and I would like to express my sincere gratitude for their support.

It is recommended to read the Introduction before moving on. Check out the Table of Contents for all articles.

Unlike Java, Kotlin allows you to provide custom implementations for a predefined set of operators. Operators are ordinary methods that can be called using a special syntax, e.g. operator fun plus() can be called using +, == calls equals, > calls compareTo etc.

I would recommend you go easy on them. There are situations where implementing an operator makes clear sense (i.e. when creating a Vector2D class, plus makes perfect sense), but unless there is an absolutely crystal clear concept of what a given operator means in the domain you’re modeling, it’s usually best to avoid them.

For example, going back to Vector2D, plus might make sense, but what about times? There are two product operations associated with a vector, the dot and cross products. Which one should you implement? Probably neither, because there isn’t any general argument that makes one more important or fundamental than the other. But if you don’t implement either, does it make sense to implement plus and be inconsistent with which operations are implemented? It might be, but these are the kinds of questions you should ask yourself before going down this road. Often, it’s much better to simply define a custom infix function.

You can find the list of legal operators in the docs. The vast majority won’t surprise you, but there are a couple of operators I want to mention explicitly: invoke, componentN, contains and rangeTo, and the index array access operator [].

Invoke

The invoke operator is certainly among the less traditional operators, because it represents a function call. In actuality, f() calls f.invoke(), in the same way that 2 + 3 actually calls 2.plus(3). You can see this for yourself when you look at the definition of e.g. Function1 and its counterparts.

Therefore, any object can be called like a function just by implementing the invoke operator:

Hopefully this goes without saying, but implementing invoke is not always a good thing! You should think hard before making this decision.

ComponentN

The componentN family of operators are what enable destructuring, which we talked about in the lesson on data classes (feel free to refresh your memory before moving on). When you destructure an expression, what actually happens is that component1, component2 etc. get called in turn to produce the individual parts of the result:

The same thing happens when you destructure expressions in a lambda:

As was mentioned when we talked about data classes, you can use _ to omit a specific component. When you do that, the corresponding componentN method is not called at all:

Since componentN functions are operators, any class can implement destructuring:

Contains & RangeTo

The contains method is called when in is used, and the rangeTo method is called when .. is used. Both can be overridden

However, this is rarely necessary. The standard library contains implementations of these operators for almost all reasonable situations, including numbers, characters, time and date objects, etc. If you do ever find yourself in a situation where you need to implement them, it’s very likely you can just call the builtin implementations:

Indexed array access

Just so you know, it’s there.

Go back to Infix functions, jump to the Table of Contents, or continue to Type Aliases.

Join me in Etnetera
Kotlin
Java
Programming
Operators
Object Oriented
Recommended from ReadMedium