After starting my work on Kotlin, I realized that this language will change my life, and you know what? I was totally right. Here is my list of five less known things about Kotlin and I hope you will find at least three worth knowing.
Name your imports
In Kotlin, imports are used by the compiler to let you name your classes by their unqualified name. What happens if you have naming conflict? Sad things happen!
package com.code.sliski.userinfoscreen.ui import ... import android.view.View // Conflict class UserInfoFragment : Fragment(), com.code.sliski.userinfoscreen.ui.View { // Conflict override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, state: Bundle?): View = // Conflict inflater.inflate(user_info_fragment, container, false) } interface View // Conflict
Personally, I hate using fully qualified package names in my code as it lowers readability and clarity. In Python, you can name your imports to fix the conflicts and Kotlin supports it as well ❤.
import android.view.View as AndroidView // Named import class UserInfoFragment : Fragment(), View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, state: Bundle?): AndroidView = // Using named import }
Read this : What’s new in Kotlin 1.1.2 version
Change companion object name
Companion object was introduced to replace static members. It is not only for declaring static properties but also to name them. How? Let’s have a look at this example.
// Using in Java CustomButton button = new CustomButton(context); button.setVisibility(CustomButton.Companion.getGONE()); // Using in Kotlin val button = CustomButton(context) button.visibility = CustomButton.VISIBLE class CustomButton(context: Context?) : View(context) { companion object { // Visibility val GONE = 1 val VISIBLE = 2 val INVISIBLE = 3 } }
By default, Kotlin creates a static nested class Companion for every companion object. That is why you need to use CustomButton.Companion to access static members from Java code(you can also use it in Kotlin but it is not necessary). Kotlin lets you change the default name of companion object to whatever name you want. Refactored code looks like this.
// Using in Java CustomButton button = new CustomButton(context); button.setVisibility(CustomButton.Visibility.getGONE()); ... class CustomButton(context: Context?) : View(context) { companion object Visibility { val GONE = 1 val VISIBLE = 2 val INVISIBLE = 3 } }
The biggest drawback is that Kotlin does not support multiple companion objects for a class. It would be great for grouping static properties.
val button = CustomButton(context) button.visibility = CustomButton.Visibility.VISIBLE button.foregroundGravity = CustomButton.ForegroundGravity.LEFT class CustomButton(context: Context?) : View(context) { companion object Visibility { val VISIBLE = 1 val INVISIBLE = 2 } companion object ForegroundGravity { val LEFT = 1 val RIGHT = 2 } }
Note : This code does not compile because Kotlin supports only one companion object per class.
You must read : What is Disadvantage or Cons of Kotlin?
Compose functions
I bet you used function references before but have you ever tried to use them to compose functions? Imagine that you want to map an array of prices to prices that are taxed, discounted and rounded. Using common approach you will end up with something like this.
val prices = listOf(21.8, 232.5, 231.3) prices.map(::taxed) .map(::discounted) .map(::rounded) fun taxed(value: Double): Double = value * 1.4 fun discounted(value: Double): Double = value * 0.9 fun rounded(value: Double): Double = Math.round(value).toDouble()
This example is begging for composition so do not disregard it and make the code better place. Abracadabra!
val prices = listOf(21.8, 232.5, 231.3) val taxedDiscountedRounded = compose(::taxed, ::discounted, ::rounded) prices.map(taxedDiscountedRounded) fun <A, B> compose(f: (A) -> A, g: (A) -> A, h: (A) -> B): (A) -> B = { x -> h(g(f(x))) } fun taxed(value: Double): Double = value * 1.4 fun discounted(value: Double): Double = value * 0.9 fun rounded(value: Double): Double = Math.round(value).toDouble()
Functions composition not only makes your code cleaner but also faster. Once you understand it, you will be able to compose almost everything.
Start with baby step : Create Reddit like Android Kotlin app Step by Step
Change name of generated class
Extension functions are one of the most attractive features in Kotlin but using them in Java code can give you a serious headache. It is ugly and besides is nothing else like invoking a static method.
// Main.java public static void main(String[] args) { String name = null; AnyKt.ifNull(name, new Function1<Object, Unit>() { @Override public Unit invoke(Object o) { return null; } }); } // Any.kt inline fun <T> T?.ifNull(function: (T?) -> Unit) { if (this == null) function(this) }
Kotlin generates class AnyKt with a static method so you can use it in Java. There is an option to change the name of generated class to achieve better readability.
// Main.java public static void main(String[] args) { String name = null; Nullcheck.ifNull(name, new Function1<Object, Unit>() { @Override public Unit invoke(Object o) { return null; } }); } // Any.kt @file:JvmName("Nullcheck") package ... inline fun <T> T?.ifNull(function: (T?) -> Unit) { if (this == null) function(this) }
Recommended article : What is Kotlin Anko?
Validate an assignment and “veto” it
The way in which Kotlin handles delegation is pretty spectacular so if you are not familiar with it, you should totally check my article: “Zero boilerplate delegation in Kotlin”.
Besides of “class delegation”, there is an interesting mechanism called “delegated properties” which is used for lazy property initialization. How would you solve scenario in which you need to be able to intercept an assignment and “veto” it? Is there any clean way to do it? Yes, there is!
var price: Double by Delegates.vetoable(0.0) { prop, old, new -> validate(new) } fun validate(price: Double) : Boolean { // Validation checks }
Sample shows usage of a built-in vetoable delegate. Lambda passed to the vetoable is called before the assignment of a new value to property. Returning false from the lambda allows you to “veto” the assignment but if you want to pass it through return true.
If this was interesting to you, please comment us!!
Share your thoughts