When should one prefer Kotlin extension functions? - kotlin

In Kotlin, a function with at least one argument can be defined either as a regular non-member function or as an extension function with one argument being a receiver.
As to the scoping, there seems to be no difference: both can be declared inside or outside classes and other functions, and both can or cannot have visibility modifiers equally.
Language reference seems not to recommend using regular functions or extension functions for different situations.
So, my question is: when do extension functions give advantage over regular non-member ones? And when regular ones over extensions?
foo.bar(baz, baq) vs bar(foo, baz, baq).
Is it just a hint of a function semantics (receiver is definitely in focus) or are there cases when using extensions functions makes code much cleaner or opens up opportunities?

Extension functions are useful in a few cases, and mandatory in others:
Idiomatic Cases:
When you want to enhance, extend or change an existing API. An extension function is the idiomatic way to change a class by adding new functionality. You can add extension functions and extension properties. See an example in the Jackson-Kotlin Module for adding methods to the ObjectMapper class simplifying the handling of TypeReference and generics.
Adding null safety to new or existing methods that cannot be called on a null. For example the extension function for String of String?.isNullOrBlank() allows you to use that function even on a null String without having to do your own null check first. The function itself does the check before calling internal functions. See documentation for extensions with Nullable Receiver
Mandatory Cases:
When you want an inline default function for an interface, you must use an extension function to add it to the interface because you cannot do so within the interface declaration (inlined functions must be final which is not currently allowed within an interface). This is useful when you need inline reified functions, for example this code from Injekt
When you want to add for (item in collection) { ... } support to a class that does not currently support that usage. You can add an iterator() extension method that follows the rules described in the for loops documentation -- even the returned iterator-like object can use extensions to satisfy the rules of providing next() and hasNext().
Adding operators to existing classes such as + and * (specialization of #1 but you can't do this in any other way, so is mandatory). See documentation for operator overloading
Optional Cases:
You want to control the scoping of when something is visible to a caller, so you extend the class only in the context in which you will allow the call to be visible. This is optional because you could just allow the extensions to be seen always. see answer in other SO question for scoping extension functions
You have an interface that you want to simplify the required implementation, while still allowing more easy helper functions for the user. You can optionally add default methods for the interface to help, or use extension functions to add the non-expected-to-be-implemented parts of the interface. One allows overriding of the defaults, the other does not (except for precedence of extensions vs. members).
When you want to relate functions to a category of functionality; extension functions use their receiver class as a place from which to find them. Their name space becomes the class (or classes) from which they can be triggered. Whereas top-level functions will be harder to find, and will fill up the global name space in IDE code completion dialogs. You can also fix existing library name space issues. For example, in Java 7 you have the Path class and it is difficult to find the Files.exist(path) method because it is name spaced oddly. The function could be placed directly on Path.exists() instead. (#kirill)
Precedence Rules:
When extending existing classes, keep the precedence rules in mind. They are described in KT-10806 as:
For each implicit receiver on current context we try members, then local extension functions(also parameters which have extension function type), then non-local extensions.

Extension functions play really well with the safe call operator ?.. If you expect that the argument of the function will sometimes be null, instead of early returning, make it the receiver of an extension function.
Ordinary function:
fun nullableSubstring(s: String?, from: Int, to: Int): String? {
if (s == null) {
return null
}
return s.substring(from, to)
}
Extension function:
fun String.extensionSubstring(from: Int, to: Int) = substring(from, to)
Call site:
fun main(args: Array<String>) {
val s: String? = null
val maybeSubstring = nullableSubstring(s, 0, 1)
val alsoMaybeSubstring = s?.extensionSubstring(0, 1)
As you can see, both do the same thing, however the extension function is shorter and on the call site, it's immediately clear that the result will be nullable.

There is at least one case where extension functions are a must - call chaining, also known as "fluent style":
foo.doX().doY().doZ()
Suppose you want to extend the Stream interface from Java 8 with you own operations. Of course, you can use ordinary functions for that, but it will look ugly as hell:
doZ(doY(doX(someStream())))
Clearly, you want to use extension functions for that.
Also, you cannot make ordinary functions infix, but you can do it with extension functions:
infix fun <A, B, C> ((A) -> B).`|`(f: (B) -> C): (A) -> C = { a -> f(this(a)) }
#Test
fun pipe() {
val mul2 = { x: Int -> x * 2 }
val add1 = { x: Int -> x + 1 }
assertEquals("7", (mul2 `|` add1 `|` Any::toString)(3))
}

There are cases where you have to use extension methods. E.g. if you have some list implementation MyList<T>, you can write an extension method like
fun Int MyList<Int>.sum() { ... }
It is impossible to write this as a "normal" method.

Related

Differenence between ways to declare functions in Kotlin

I have seen some code declaring functions as seen below. What is the difference between fun1 and fun2?
interface Test {
fun fun1() : Boolean = false
}
fun Test.fun2() : Boolean = true
fun1 defined inside the interface describes an open function that any implementer of the interface can override. Since it also defines a default implementation by returning something, it is not abstract and implementing classes can choose not to override it.
fun2 is an extension function. When these are used with interfaces, often the reason is to discourage overriding. An extension function cannot be overridden, but it can be hidden by another extension function with the same signature, but only in a specific scope. Therefore, some implementer of Test in another module that passes its instance back to this module cannot change the functionality of fun2 as used in this module.
The second version is an extension function.
The difference is that extension functions can be applied to any type (even outside of your code), but they do not have access to private members of that type. They are pretty much the same as calling function with this type as a first parameter, just nicer syntax

how to read kotlin type annotations

I'm coming to kotlin after working in mostly dynamically typed languages for years, so I get a lot of what I'm seeing, but I'm still tripping up a bit over reading some of the type annotations.
Most of them make sense (I've written some C++ and typescript so I'm not wholey familiar with more strictly type languages). so stuff like annotating the parameters and return types for functions, variable declaration, stuff like that makes sense.
What I'm having trouble with is the more complex annotations like looking at this explanation of the fold method when talking about higher order functions:
fun <T, R> Collection<T>.fold(
initial: R,
combine: (acc: R, nextElement: T) -> R
): R {
var accumulator: R = initial
for (element: T in this) {
accumulator = combine(accumulator, element)
}
return accumulator
}
I get that:
the Collection refers to an arbitrary collection with elements that are of type T
the fold method call takes an value of type R named initial as the first argument and a callable function labeled combine as the second argument
the callable function will be called for each element of the collection with an accumulator of type R labeled acc and the next element of the collection of type T (since it's a collection of Ts) labeled nextElement
The callable function will return a type R in the end
The fold method will return a type R in the end
And I can use it like this:
val greetings = listOf("hey", "hi", "yo", "what's up")
val personalized = greetings.fold("", { carry, current -> "${carry}\n$current, Chris." })
println(personalized)
That all makes sense, but what does the <T, R> between the fun and the Collection mean? What is that part called? (It's hard to search for an explanation when you don't know what the thing you're looking for is called :P)
And more importantly, is there a section of the documentation that specifically talks about how to read these annotations or what each are called? I've been looking through the docs and searching in general for an explanation of how to read the type annotations and I can't find anything.
It feels like a silly question, but to the uninitiated it's kind of daunting and the docs are written as if you already understand that part of the language.
As Alexey already said, these names between angled brackets after the fun keyword are called "type parameters". They are used to declare generic functions.
the Collection refers to an arbitrary collection with elements that are of type T
Here you can see that Collection and T play different roles: Collection is a well-known defined type that you are referencing, while T is just a name that you arbitrarily choose for the definition of this function.
We want the compiler to check that Collection is a type that is defined and imported, and if you make a typo there will be a compile error.
On the other hand, we don't want that for T and R, so it is necessary to mention them in a special syntactic place so that the compiler knows you're just making up arbitrary names for the sake of the function definition.
It is nice to draw a parallel between the type parameters and the method arguments. The method arguments are also arbitrary names that you define in the signature and use in the function body, as opposed to class members like properties, which you can access without declaring them as arguments.
Just like the values of the arguments are passed when you call a method, and can be different for each different invocation, the "values" of the type parameters are also given at the call site, and can be different for each invocation (they are often inferred, though, so you don't see them).
Note that the "value" of a type parameter is a type (e.g. String), not a value in the usual sense like the string "abc". You can actually specify these types explicitly on the call site if you want:
listOf(1, 2, 3).fold<Int, Int>(42) { acc, e -> acc + e }
The syntax on the call site is similar to the declaration site, it uses <>, except that it's written after the function name.
In general, these types are easily inferred by the compiler using the argument types or the return type in the context of the call site, that's why it's often unnecessary to explicitly specify them.
Difference with generics at the class level
It may seem weird that the methods in the interface List don't need to declare such type parameters, despite the fact that they use generic types:
interface MutableList<T> {
fun add(element: T): Boolean {
//....
}
}
This is because T is already "well-defined" when using it for the method declaration: it was already defined as a type parameter for the List interface itself. The mechanism is the same, but the difference is the scope of the definition: class-level type parameters are defined by the instance of the class (you can create a List<Int> or a List<String>, and this is chosen when you create your instance), while function type parameters are defined by each call to the function.
You can even combine both:
interface List<T> {
fun <R> map(transform: (T) -> R): List<R> {
//...
}
}
Here T will be determined by the list instance on which you call map, but R can be different for each call to map even on the same list instance.
<T, R> are the type parameters. Since you are familiar with C++, it's like
template <typename T, typename R>
It just happens to be placed after the fun keyword in Kotlin (and after the type name when declaring a generic class/interface/type alias) instead of before the function definition.

Kotlin benifits of writing helper/util methods without wrapping in class

There are can be two ways of writing helper method in Kotlin
First is
object Helper {
fun doSomething(a: Any, b: Any): Any {
// Do some businesss logic and return result
}
}
Or simply writing this
fun doSomething(a: Any, b: Any): Any {
// Do some businesss logic and return result
}
inside a Helper.kt class.
So my question is in terms of performance and maintainability which is better and why?
In general, your first choice should be top-level functions. If a function has a clear "primary" argument, you can make it even more idiomatic by extracting it as the receiver of an extension function.
The object is nothing more than a holder of the namespace of its member functions. If you find that you have several groups of functions that you want to categorize, you can create several objects for them so you can qualify the calls with the object's name. There's little beyond this going in their favor in this role.
object as a language feature makes a lot more sense when it implements a well-known interface.
There's a third and arguably more idiomatic way: extension functions.
fun Int.add(b: Int): Int = this + b
And to use it:
val x = 1
val y = x.add(3) // 4
val z = 1.add(3) // 4
In terms of maintainability, I find extension functions just as easy to maintain as top-level functions or helper classes. I'm not a big fan of helper classes because they end up acquiring a lot of cruft over time (things people swear we'll reuse but never do, oddball variants of what we already have for special use cases, etc).
In terms of performance, these are all going to resolve more or less the same way - statically. The Kotlin compiler is effectively going to compile all of these down to the same java code - a class with a static method.

Kotlin extension functions vs member functions?

I am aware that extension functions are used in Kotlin to extend the functionality of a class (for example, one from a library or API).
However, is there any advantage, in terms of code readability/structure, by using extension functions:
class Foo { ... }
fun Foo.bar() {
// Some stuff
}
As opposed to member functions:
class Foo {
...
fun bar() {
// Some stuff
}
}
?
Is there a recommended practice?
When to use member functions
You should use member functions if all of the following apply:
The code is written originally in Kotlin
You can modify the code
The method makes sense to be able to use from any other code
When to use extension functions
You should use extension functions if any of the following apply:
The code was originally written in Java and you want to add methods written in Kotlin
You cannot change the original code
You want a special function that only makes sense for a particular part of the code
Why?
Generally, member functions are easier to find than extension functions, as they are guaranteed to be in the class they are a member of (or a super class/interface).
They also do not need to be imported into all of the code that uses them.
From my point of view, there are two compelling reasons to use extension functions:
To "extend" the behaviour of a class you're not the author of / can't change (and where inheritance doesn't make sense or isn't possible).
To provide a scope for particular functionality. For example, an extension function may be declared as a freestanding function, in which case it's usable everywhere. Or you may choose to declare it as a (private) member function of another class, in which case it's only usable from inside that class.
It sounds like #1 isn't a concern in your case, so it's really more down to #2.
Extension functions are similar to those you create as a utility functions.
A basic example would be something like this:
// Strings.kt
fun String.isEmail() : Boolean {
// check for email pattern and return true/false
}
This code can be written as a utility function in Java like this:
class StringUtils {
public static boolean isEmail(String email) {
// check for email pattern and return true/false
}
}
So what it essentially does is, calling the same function with the object you call on will be passed as the first parameter to the argument. Like the same function I have given example of in Java.
If you want to call the extension function created in kotlin from java, you need to pass the caller as the first argument. Like,
StringsKt.isEmail("example#example.com")
As per the documentation,
Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type.
They are simply static functions with the caller as the first argument and other parameters followed by it. It just extends the ability for us to write it that way.
When to create extension functions?
When you don't have access to that class. When that class belongs to some library you have not created.
For primitive types. Int, Float, String, etc.
The another reason for using extension function is, you don't have to extend that class in order to use the methods, as if they belong to that class (but not actually part of that class).
Hope it makes a bit clear for you..
As mentioned in other answers, extension functions are primarily used in code that you can't change - maybe you want to change complex expression around some library object into easier and more readable expression.
My take would be to use extension functions for data classes. My reasoning is purely philosophical, data classes should be used only as data carriers, they shouldn't carry state and by themselves shouldn't do anything. That's why I think you should use extension function in case you need to write a function around data class.

Call java varargs method from kotlin

I have a java function:
public static void initialize(#NonNull Activity activity, Settings... settings) {}
I want to call it from kotlin:
fun initialize(activity: Activity, vararg settings: settings) = JavaClass.initialize(activity, settings)
But it does not compile, telling me that there is type mismatch, Settings is required, but the argument is kotlin.Array<out Settings>
I see that it's trying to match it with signture
public static void initialize(#NonNull Activity activity, Settings settings) {}
but I want to use
public static void initialize(#NonNull Activity activity, Settings[] settings) {}
You should use the following syntax:
fun initialize(activity: Activity, vararg settings: settings) =
JavaClass.initialize(activity, *settings)
https://kotlinlang.org/docs/reference/java-interop.html#java-varargs
Michael's answer is correct, though I'd like to make some additional comments.
The reason you cannot pass a Kotlin vararg parameter into a Java (or Kotlin) function that expects another vararg is because the compiler resolves the vararg into an Array.
Hence, it is as if you've declared your function as below (from the perspective of the function's internal scope):
fun initialize(activity: Activity, settings: Array<Settings>) = //...
This is why it is unintuitive that we need to use the spread * operator. As far as I can tell, there are two benefits to this design choice:
The spread operator, in addition to being used to populate variable arguments, can be used to mix-and-match between individual arguments and spreaded arrays. This means that Kotlin is giving us a convenient way to add additional parameters to a vararg list.
In Java, the following code does not compile:
Settings[] settings = //...
Setting myAdditionalSetting = new Setting();
JavaClass.initialize(activity, settings, myAdditionalSetting); //Compiler Error
However, in Kotlin we can do this:
JavaClass.initialize(activity, *settings, myAdditionalSetting)
The second benefit is increased safety. The spread operator compiles down to a call to Arrays.copyOf() which guarantees immutability of the spreaded values.i This ensures that the called function cannot corrupt the original array.
i: While the actual class references would be immutable, the objects they refer to might still be mutable.