Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin - Expectations vs Reality

M2mobi
April 21, 2017

Kotlin - Expectations vs Reality

We will be exploring the reasons why we adopted Kotlin, our expectations going in, our practical findings along the way, and the impact on our way of coding and the impact on the team.

M2mobi

April 21, 2017
Tweet

More Decks by M2mobi

Other Decks in Programming

Transcript

  1. Kotlin - Expectations vs Reality • What compelled us to

    adopt Kotlin • How we went about this • What we learned
  2. About us • Small team of dedicated Android developers •

    Share and develop knowledge • Often working on different projects • Projects are frequently long-term
  3. Kotlin package com.m2mobi.example import android.content.Context import com.m2mobi.example.R class ExampleKotlinClass(context: Context)

    : ExampleSuperClass(context), ExampleKotlinInterface { // a non-null, read only value val myBoolean: Boolean = context.resources.getBoolean(R.bool.my_boolean) // a nullable variable var myInt: Int? = null override fun onSomethingHappened(text: String): Boolean { myInt = text.toIntOrNull() return myBoolean } }
  4. Null safety • In the Android SDK, the dreaded null

    is everywhere • This makes NullPointerExceptions a common concern • Easy to fix, right? Just add more 'if'...
  5. Null safety class NullabilityExample { var nonNullableString: String = ""

    var statusCode: Int? = 0 fun updateString(nullableString: String?): Int { // this won't fly nonNullableString = nullableString // and neither will this return statusCode } }
  6. Conciseness • Boilerplate reduces readability • Code you don’t write,

    you won’t have to read • Code you don’t write, you won’t have to maintain
  7. Conciseness public class Person {
 
 private String name;
 


    public Person(String name) {
 this.name = name;
 }
 
 public String getName() {
 return name;
 }
 
 public void setName(String name) {
 this.name = name;
 }
 }
  8. Conciseness class PersonAdapter: RecyclerView.Adapter<ViewHolder>() {
 
 var viewModels: List<Person> =

    emptyList()
 set(value) {
 field = value
 notifyDataSetChanged()
 }
 
 override fun getItemCount(): Int = viewModels.size
  9. Interoperability class Person(var name: String?) // from Java...
 public void

    greetPerson(Person person) {
 Toast.makeText(context, "Hello, " + person.getName(), Toast.LENGTH_SHORT).show();
 } person.getName()
  10. Interoperability class Person(var name: String?) // from Java...
 public void

    greetPerson(Person person) {
 Toast.makeText(context, "Hello, " + person.getName(), Toast.LENGTH_SHORT).show();
 } person.getName()
  11. Interoperability class Person(var name: String?) // from Java...
 public void

    greetPerson(Person person) {
 Toast.makeText(context, "Hello, " + person.getName(), Toast.LENGTH_SHORT).show();
 } person.getName()
  12. Compatibility public String readFirstLineFromFile(String path) { BufferedReader br = null;

    FileReader fr = null; String result = null; try { fr = new FileReader(path); br = new BufferedReader(fr); result = br.readLine(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (br != null) br.close(); if (fr != null) fr.close(); } catch (IOException ex) { ex.printStackTrace(); } } return result; }
  13. Compatibility public String readFirstLineFromFile(String path) {
 try (BufferedReader br =

    new BufferedReader(new FileReader(path))) {
 return br.readLine();
 } catch(IOException ioe) {
 return "";
 }
 }
  14. Awesome fun getAverageAgeOfJakesOver67(): Double { return listOfPeople .filterNotNull() .filter {

    it.name == "Jake" && it.age >= 67 } .map { it.age } .average() }
  15. Awesome /**
 * Extension method that generates a Toast and

    shows it
 *
 * @param[text] Text to display
 * @param[duration] Duration of [Toast] (defaults to [Toast.LENGTH_SHORT])
 */
 fun Activity.showToast(text: String, duration: Int = Toast.LENGTH_SHORT) {
 Toast.makeText(this, text, duration).show()
 } // Bye bye makeText, say hello to
 showToast("NEVER FORGETTING TO CALL show() AGAIN")
  16. How we introduced Kotlin • Discussed within Android team •

    Started with isolated classes within a Java project • Evaluated along the way • Slowly migrated classes over as project progressed
  17. Our experiences - The Good • Surprisingly easy to pick

    up • Excellent IDE support (not entirely unexpected) • Language features such as higher-order functions are a game changer • Standard library full of extremely useful helpers • Zero NullPointerExceptions
  18. Our experiences - The Meh • There is always a

    learning curve • Writing idiomatic Kotlin takes practice • Code reviews can be tricky with evolving conventions • Refactoring in AS seemed less smart than for Java • Standard library is currently ~10% of the dex limit • With great power…
  19. …comes some really dubious code? fun getStringLength(input: String?): Int {


    return when (input) {
 null -> 0
 else -> input.length
 }
 }
  20. Our experiences - The Bad • Annotation processing needed work

    • Dagger + Databinding = pain • Failure to compile can in cases be difficult to debug • That’s it?
  21. Overall • Not as difficult to wrap your head around

    as RxJava • As of 1.1, annotation processing should be significantly improved • Java is difficult to go back to • I barely remember what a semicolon looks like ;-)
  22. Recommended reading Kotlin website Pushing the limits of Kotlin annotation

    processing - Eugenio Marletti Advancing Android Development with Kotlin - Jake Wharton