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

Thinking Functionally 
in Kotlin - JetBrains Night, Bangalore

Thinking Functionally 
in Kotlin - JetBrains Night, Bangalore

We'll talk about the adoption and use of Kotlin at Go-Jek where we've been using it to build our Android app for more than a year now. We recently re-wrote one of our major products from scratch in Kotlin, based on which we would like to share our learnings and tips.

We're going to look at a few real world examples of some of the most talked about features of the language and how it can help you in becoming a better developer.

Hopefully, by the end of this session you'll get a view of how all the amazing features of the language come together to give you a magical feeling about writing code. And happiness.

Abhay Sood

April 27, 2018
Tweet

More Decks by Abhay Sood

Other Decks in Programming

Transcript

  1. Why we chose Kotlin? • Immutability • Functions as first

    class citizens • Compile time safety - nullable types • IDE support • Simple learning curve
  2. Build times • Build times are slightly higher but not

    alarming. Incremental builds take about 25-30 secs. And clean builds take about 1min 30secs • kapt currently doesn’t support compile time avoidance (using gradle 3.4). So if you have annotation processing your code then build times will be higher.
  3. What is immutability? “It's the idea that once something is

    created, then it will always represent the same value”
  4. Risks of mutation public static List<Integer> oneToTen() { return Arrays.asList(1,

    2, 3, 4, 5, 6, 7, 8, 9, 10); } public static List<Integer> oddNumbers(List<Integer> list) { }
  5. Risks of mutation public static List<Integer> oneToTen() { return Arrays.asList(1,

    2, 3, 4, 5, 6, 7, 8, 9, 10); } public static List<Integer> oddNumbers(List<Integer> list) { } public static List<Integer> evenNumbers(List<Integer> list) { }
  6. Risks of mutation public static List<Integer> oneToTen() { return Arrays.asList(1,

    2, 3, 4, 5, 6, 7, 8, 9, 10); } public static void main(args...) { print(oddNumbers(oneToTen())); print(evenNumbers(oneToTen())); }
  7. Risks of mutation public static List<Integer> oneToTen() { return Arrays.asList(1,

    2, 3, 4, 5, 6, 7, 8, 9, 10); } public static void main(args...) { print(oddNumbers(oneToTen())); // 1, 3, 5, 7, 9 print(evenNumbers(oneToTen())); // 2, 4, 6, 8, 10 }
  8. Risks of mutation public static List<Integer> oneToTen() { return Arrays.asList(1,

    2, 3, 4, 5, 6, 7, 8, 9, 10); } public static void main(args...) { List<Integer> list = oneToTen(); print(oddNumbers(list)); print(evenNumbers(list)); }
  9. Risks of mutation public static List<Integer> oneToTen() { return Arrays.asList(1,

    2, 3, 4, 5, 6, 7, 8, 9, 10); } public static void main(args...) { List<Integer> list = oneToTen(); print(oddNumbers(list)); // 1, 3, 5, 7, 9 print(evenNumbers(list)); }
  10. Risks of mutation public static List<Integer> oneToTen() { return Arrays.asList(1,

    2, 3, 4, 5, 6, 7, 8, 9, 10); } public static void main(args...) { List<Integer> list = oneToTen(); print(oddNumbers(list)); // 1, 3, 5, 7, 9 print(evenNumbers(list)); // — fails miserably }
  11. Problems with mutation • Passing around mutable data makes the

    code unreliable. • Code which allows mutation is not thread safe.
  12. Let’s fix it with Kotlin fun oneToTen() : MutableList<Integer> {

    return mutableListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } fun oddNumbers(list: MutableList<Integer>) : MutableList<Integer> { } fun evenNumbers(list: MutableList<Integer>) : MutableList<Integer> { }
  13. Let’s fix it with Kotlin fun oneToTen() : MutableList<Integer> {

    return mutableListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } fun oddNumbers(list: MutableList<Integer>) : MutableList<Integer> { } fun evenNumbers(list: MutableList<Integer>) : MutableList<Integer> { }
  14. Let’s fix it with Kotlin fun oneToTen() : List<Integer> {

    return listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } fun oddNumbers(list: List<Integer>) : List<Integer> { // List in Kotlin is immutable so all safe here } fun evenNumbers(list: List<Integer>) : List<Integer> { // List in Kotlin is immutable so all safe here }
  15. Takeaway • Always question yourself when using mutable data structures.

    • As a rule of thumb try to make everything immutable to begin with.
  16. Null safety public static void main(String []args){ HashMap<String, Long> employees

    = new HashMap<>(); employees.put(“Abhay”, 1); } public static void printEmployeeId( String name, Map<String, Long> employees) { long id = employees.get(name); System.out.println(id); }
  17. Null safety public static void printEmployeeId( String name, Map<String, Long>

    employees) { long id = employees.get(name); System.out.println(id); } public static void main(String []args){ HashMap<String, Long> employees = new HashMap<>(); employees.put(“Abhay”, 1); printEmployeeId(“Abhay”, employees); }
  18. Null safety public static void printEmployeeId( String name, Map<String, Long>

    employees) { long id = employees.get(name); System.out.println(id); } public static void main(String []args){ HashMap<String, Long> employees = new HashMap<>(); employees.put(“Abhay”, 1); printEmployeeId(“Abhay”, employees); // prints 1 }
  19. Null safety public static void printEmployeeId( String name, Map<String, Long>

    employees) { long id = employees.get(name); System.out.println(id); } public static void main(String []args){ HashMap<String, Long> employees = new HashMap<>(); employees.put(“Abhay”, null); printEmployeeId(“Abhay”, employees); }
  20. Null safety public static void printEmployeeId( String name, Map<String, Long>

    employees) { long id = employees.get(name); System.out.println(id); } public static void main(String []args){ HashMap<String, Long> employees = new HashMap<>(); employees.put(“Abhay”, null); printEmployeeId(“Abhay”, employees); // NPE }
  21. Null safety public static void main(String []args){ HashMap<String, Long> employees

    = new HashMap<>(); employees.put(“Abhay”, null); printEmployeeId(“Abhay”, employees); // NPE } public static void printEmployeeId( String name, Map<String, Long> employees) { long id = employees.get(name); // Unboxing null to long System.out.println(id); }
  22. Let’s fix it with Kotlin fun main(…){ val employees :

    Map<String, Long?> = mapOf(); employees.put(“Abhay”, null); printEmployeeId(“Abhay”, employees); } fun printEmployeeId( name: String, employees: Map<String, Long?>) { val id : Long? = employees.get(name); println(id ?: “Cannot find an id for $name”); }
  23. Let’s fix it with Kotlin fun main(…){ val employees :

    Map<String, Long?> = mapOf(); employees.put(“Abhay”, null); printEmployeeId(“Abhay”, employees); } fun printEmployeeId( name: String, employees: Map<String, Long?>) { val id : Long? = employees.get(name); println(id ?: “Cannot find an id for $name”); }
  24. Takeaways • Choose data types carefully. Mark things that can

    be null as nullable. • A lot of folks coming from Java generally work around null types by either making everything nullable or completely ignoring nullable type. Don’t do it.
  25. Takeaways @GET("userProfile/") fun getUserProfile(@Query("userId") userId: String)
 : Observable<UserProfile> data class

    UserProfile( val name: String, val email: String, val phoneNumber: String, val photo: String?, val address: String?)
  26. Functions vs Methods (Member Functions) • Functions and methods are

    two slightly different things. • Method is a function associated to an object. • While a function can be standalone. class A { fun someMethod() {} }
  27. Functions in Kotlin • Kotlin supports functions as first class

    citizens. • Which means they can be passed around, can be stored in variables, can be used as parameters to another functions and even can be returned from other functions.
  28. Building delightful APIs with lambdas val typedArray = context.theme.obtainStyledAttributes( attrs,

    R.styleable.MyCustomView, 0, 0) try { isLoading = a.getBoolean(R.styleable.v_loading, false) } finally { typedArray.recycle() }
  29. inline fun Theme.useTypedArray( attrs: AttributeSet?, block: (a: TypedArray) -> Unit

    ) { val typedArray = obtainStyledAttributes( attrs, R.styleable.MyCustomView, 0, 0) } Building delightful APIs with lambdas
  30. inline fun Theme.useTypedArray( attrs: AttributeSet?, block: (a: TypedArray) -> Unit

    ) { val typedArray = obtainStyledAttributes( attrs, R.styleable.MyCustomView, 0, 0) try { block(typedArray) } finally { typedArray.recycle() } } Building delightful APIs with lambdas
  31. Building delightful APIs with lambdas theme.useTypedArray(attrs) { typedArray: TypedArray ->

    isLoading = typedArray.getBoolean(R.styleable.v_loading, false) if (isLoading) { showLoader() } }
  32. Learn more about functional programming • Why functional programming matters

    - https:// www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf • F# for fun and profit https://fsharpforfunandprofit.com/ • Lambdas: https://www.youtube.com/results? search_query=venkat+subramaniam+design+patterns+la mbdas • For hard core stuff: Learn you a Haskell http:// learnyouahaskell.com/