Extension functions.
Sometimes you want to add functionality to a class you cannot modify. The class comes from a library. You cannot edit its source. Kotlin has a solution: extension functions. Today we learn to extend existing types without inheritance.
You use a class from a library. It does almost what you need. But it lacks one method you want.
In Java, you might create a utility class with static methods. StringUtils dot capitalize with s. This works but feels awkward. The method takes the string as a parameter instead of being called on it.
Inheritance might help, but only if you control instance creation. And many classes are final.
Kotlin offers extension functions. You write a function that appears to be a method of the class. s dot capitalize. But you define it outside the class. No modification needed.
Define an extension by specifying the receiver type before the function name.
fun String dot addExclamation returning String equals this plus exclamation mark.
String is the receiver type. addExclamation is the function name. Inside, this refers to the receiver.
Now you can call it like a method: "Hello" dot addExclamation returns "Hello!".
The function is not actually added to the class. It is syntactic sugar. The compiler transforms it into a regular function with the receiver as the first parameter.
But to users of your code, it looks and feels like a method.
Inside an extension function, this refers to the receiver.
fun String dot shout returning String equals this dot uppercase plus three exclamation marks.
this is the string the function was called on. If you call "hello" dot shout, this is "hello".
You can often omit this: fun String dot shout equals uppercase plus exclamation marks. Methods are called on the implicit receiver.
Use this explicitly when you need clarity or to disambiguate.
You can also add properties to existing classes.
val String dot wordCount Int get equals this dot split space dot size.
Now you can write "hello world" dot wordCount and get 2.
Extension properties cannot have backing fields. They must be computed. There is no place to store state.
Extension properties are getters, optionally with setters. They compute a value from the receiver.
Use extension properties when the value feels like an attribute rather than an action.
Extensions must be imported to be used.
If you define an extension in a package, code in other packages must import it.
Extensions can be defined at the top level, inside classes, or inside objects.
Top-level extensions are the most common. They are available throughout the project once imported.
Extensions inside a class are available only within that class. They can access the outer class's members.
The scope controls where the extension is visible. Use it to limit availability when needed.
What if a class has a member with the same signature as an extension?
The member always wins. Members are not hidden by extensions.
class Example with fun greet prints "Member". fun Example dot greet prints "Extension". The extension is never called.
This is intentional. You cannot use extensions to hijack existing methods. Existing code remains safe.
Extensions can only add new functionality, not replace existing functionality.
This makes extensions predictable. You know the original class behavior is preserved.
Extensions shine in several scenarios.
Adding convenience methods to library types. String dot isEmail to check format. List dot second to get the second element.
Domain-specific operations. BigDecimal dot formatAsCurrency. Date dot isWeekend.
Adapting types for your domain. Add methods that make sense in your context.
Creating fluent APIs. Extensions let you chain operations naturally.
Kotlin's standard library is full of extensions. map, filter, forEach on collections. let, also, apply on any object.
Extensions can be defined on nullable types.
fun String question mark dot orEmpty returning String equals this question mark colon empty string.
Now you can call orEmpty on any String question mark, even if it is null.
val s String question mark equals null. s dot orEmpty returns empty string.
This is how many null-safe utilities work. They extend the nullable type directly.
Be careful: if the receiver can be null, you must handle it in the function.
Let us summarize.
Extension functions add methods to existing classes without modification.
Use fun ReceiverType dot name syntax. this refers to the receiver.
Extension properties add computed properties.
Extensions must be imported. Members always win over extensions.
Use extensions for convenience methods, domain operations, and fluent APIs.
Extensions can have nullable receivers.
Extensions make Kotlin code expressive without modifying original classes.