About This Series
This “Android Kotlin Basics” blog series is all about fundamentals. We’ll take a look at the basics of building Android apps with Kotlin from the SUPER basics, to the standard basics, to the not-so-basics. We’ll also be drawing comparisons to how things are done in Kotlin vs. Java and some other programming languages to build Android apps (like C# and Xamarin or JavaScript/TypeScript for Hybrid implementations).
Check Out the Pluralsight Course!
If you like this series, be sure to check out my course on Pluralsight – Building Android Apps with Kotlin: Getting Started where you can learn more while building your own real-world application in Kotlin along the way. You can also join the conversation and test your knowledge throughout the course with learning checks through each module!
Watch it here: https://app.pluralsight.com/library/courses/building-android-apps-kotlin-getting-started/table-of-contents
Kotlin Extension Functions and Properties
If you’ve come from a C# background this introduction to Kotlin extensions will feel like home.
Kotlin extensions allow for us developers to extend the functionality of a given type, whether it be a class, interface, or object. These extensions are resolved statically meaning that they are essentially added as static functions and members of the given type that is being extended.
It’s important to note that Java does not have a way to build extension methods, so in this case, we won’t be able to compare how it is done in Kotlin and Java since this is only possible in Kotlin. However, it IS possible to use Kotlin extension methods in your Java code that is referencing it.
Extension Functions
Let’s take a look at what an extension function looks like. Let’s first define a simple class Dog
, and then we will add extensions to it.
Dog.kt
class Dog { var name: String = "" var breed: String = "" }
DogExtensions.kt
fun Dog.printNameAndBreed() { println(this.name + " " + this.breed) }
Now in our consumer code, we can use it like so:
MainActivty.kt
class MainActivity: Activity() { override fun onCreate(savedInstance: Bundle?) { val dog = Dog() dog.printNameAndBreed() } }
Note the use of the keyword this
within our extension method. this
refers to the instance of the class that the extension method is being invoked in. However, this
is not required unless you have naming conflicts with other local variables. So it could also be written as:
DogExtensions.kt
fun Dog.printNameAndBreed() { println(name + " " + breed) }
This allows for a shorter syntax for writing the extension. Compare that to a C# extension method:
DogExtensions.cs
public static class DogExtensions { public static void PrintNameAndBreed(this Dog dog) { Console.WriteLine($"{dog.Name} {dog.Breed}"); } }
Skipping the need for the parameter for the extension type allows for the signature of the signature to be the same as when it is invoked, which C# does not do.
Extension Properties
Just like extension methods, Kotlin supports creating extension properties. However, these extension properties cannot contain intializers like we use when initializing our properties on a class. Extension properties do not create an actual member of the class and thus need explicit “getters” and “setters” on the property (or just one or the other if you want to restrict it). Let’s see a quick example using our existing Dog
class:
DogExtensions.kt
val Dog.nameAndBreed : String get() = this.name + " " + this.breed set(value: String) { var nameAndBreedArray = value.split(" ") name = nameAndBreedArray[0] breed = nameAndBreedArray[1] // note the absence of the "this" keyword since it is optional }
Notice, that we cannot have to explicitly define get()
and set()
within our nameAndBreed
extension property. Then within these, we access the fields on the class.
If we try to instantiate an extension property with an initializer, we will get a compile-time error. For example, this is not allowed:
val Dog.nameAndBreed : String = "Ryder Labrador" // <- not allowed!
Extensions with Nullables and “Any” Types
With Kotlin extensions, you can also add nullable types:
fun Dog?.printNameAndBreed() { if (this == null) return; // just return out if it is null println(name + " " +breed) }
This means you can also use it with the Any
type in Kotlin:
fun Any?.print() { if(this == null) return; // now print out the string version of the object println(toString()) }
We’ll get a little more into the Any
type in another post of this series, but the short version is that it is a valid Kotlin type that is not restrained to an actual pre-existing or new type. This works the same way as the TypeScript any
and is most useful in functional programming when using type inference more.
That’s about it for Kotlin extensions! Extensions are great – they allow for separating some concerns and keep your actual model class definitions short and clean and put some other logic around it in a restrained location. Or to help extend the functionality of a third party library that you don’t control. All in all, it was a great design decision that the Kotlin team made to make building our applications even cleaner and easier!
If you like what you see, don’t forget to follow me on twitter @Suave_Pirate, check out my GitHub, and subscribe to my blog to learn more mobile developer tips and tricks!
Interested in sponsoring developer content? Message @Suave_Pirate on twitter for details.