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

Kotlin: More than meets the eye

Kotlin: More than meets the eye

There is no doubt that Kotlin is here to stay for a long time, it is a modern programming language with a lot of modern features. In this talk I will try to show some ‘hidden’ gems of Kotlin such as: reified, delegates or operator overloading.

GDG Porto - Android Sessions 2020 - #1 AddCode (Porto-Portugal)
https://www.meetup.com/pt-BR/GDG-Porto/events/268930032

Avatar for Filipe Batista

Filipe Batista

March 10, 2020
Tweet

More Decks by Filipe Batista

Other Decks in Programming

Transcript

  1. I AM FILIPE BAPTISTA HELLO! - Android Developer (+8 Years)

    - Coffee lover - Traveler - And music addict
  2. KOTLIN: MORE THAN MEETS THE EYE AGENDA ▸ Reified ▸

    Operator overloading ▸ Delegation ▸ Type aliases
  3. KOTLIN: MORE THAN MEETS THE EYE REIFIED ‣ Generics: Provides

    a way for you to re-use the same code with different inputs public static <T> T parse(String jsonString, Class<T> myClass) { Gson gson = new Gson(); return gson.fromJson(jsonString, myClass); } User user = parse("{ \"name\":\"John\" }", User.class); public static <T> T parse(String jsonString) { Gson gson = new Gson(); return gson.fromJson(jsonString, T.class); } For example: error: cannot select from a type variable
  4. MAKE (SOMETHING ABSTRACT) MORE CONCRETE OR REAL* Reify KOTLIN: MORE

    THAN MEETS THE EYE * from oxforddictionaries.com
  5. KOTLIN: MORE THAN MEETS THE EYE REIFIED Marking with reified,

    gives us the ability to preserve the generic type in runtime. However this can only be achieved by using an inline function. inline fun <reified T> parse(jsonString: String): T { return Gson().fromJson(jsonString, T::class.java) } val user = parse<User>("{ \"name\":\"John\" }")
  6. KOTLIN: MORE THAN MEETS THE EYE REIFIED Some other practical

    examples: inline fun <reified T : Activity> Activity.startActivity( context: Context) { startActivity(Intent(context, T::class.java)) } startActivity<MySuperActivity>(context) inline fun <reified T> FragmentManager.fragmentByTag(tag: String): T? { return this.findFragmentByTag(tag) as? T } val myfragView = supportFragmentManager .fragmentByTag<IFragmentView>(TAG)
  7. KOTLIN: MORE THAN MEETS THE EYE OPERATOR OVERLOADING Kotlin has

    a set of the operators like: minus, plus or equals already defined to work in a subset of predefined types. Expression Translated to a + b a.plus(b) a - b a.minus(b) a == b a?.equals(b) ?: (b === null) (…)
  8. KOTLIN: MORE THAN MEETS THE EYE OPERATOR OVERLOADING /** *

    File: Primitives.kt * Represents a 32-bit signed integer. * On the JVM, non-nullable values of this type are represented as values of the primitive type `int`. */ public class Int private constructor() : Number(), Comparable<Int> { (...) /** Adds the other value to this value. */ public operator fun plus(other: Byte): Int /** Adds the other value to this value. */ public operator fun plus(other: Short): Int /** Adds the other value to this value. */ public operator fun plus(other: Int): Int /** Adds the other value to this value. */ public operator fun plus(other: Long): Long /** Adds the other value to this value. */ public operator fun plus(other: Float): Float /** Adds the other value to this value. */ public operator fun plus(other: Double): Double (...) }
  9. How to perform operator overloading? KOTLIN: MORE THAN MEETS THE

    EYE OPERATOR OVERLOADING data class Money(val value: Int) (...) val five = Money(5) val seven = Money(7) val total = five.value + seven.value val total = five + seven
  10. How to perform operator overloading? KOTLIN: MORE THAN MEETS THE

    EYE OPERATOR OVERLOADING data class Money(val value: Int) { operator fun plus(money: Money): Money { return Money(value + money.value) } } operator fun Money.plus(money: Money): Money { return Money(value + money.value) }
  11. KOTLIN: MORE THAN MEETS THE EYE OPERATOR OVERLOADING data class

    Page(var pageContent: String) data class Book(val pages: MutableList<Page>) (...) val book = Book(arrayListOf(Page("cover"), Page("inside front cover"))) val firstPage = book.pages[0]
  12. KOTLIN: MORE THAN MEETS THE EYE OPERATOR OVERLOADING data class

    Page(var pageContent: String) data class Book(val pages: MutableList<Page>) { operator fun get(number: Int) = pages[number] operator fun set(number: Int, page: Page) = pages.set(number, page) } (...) val book = Book(arrayListOf(Page("cover"), Page("inside front cover"))) val first = book[0] book[1] = Page("new inside cover")
  13. Other Operators: KOTLIN: MORE THAN MEETS THE EYE OPERATOR OVERLOADING

    Expression Translated to a * b a.times(b) a / b a.div(b) a % b a.rem(b), a.mod(b) (deprecated) a..b a.range(b) a++ a.inc() a-- a.dec() (…) https://kotlinlang.org/docs/reference/operator-overloading.html
  14. KOTLIN: MORE THAN MEETS THE EYE DELEGATION The Delegation pattern

    is a good alternative to implementation inheritance. Kotlin supports it natively requiring almost zero boilerplate code. A class can implement an interface Base by delegating all of its public members to a specified object. Let’s see how!
  15. KOTLIN: MORE THAN MEETS THE EYE DELEGATION interface Printer {

    fun print() } class SuperPrinter : Printer { override fun print() { println("I'm a SuperPrinter") } } class AwesomePrinter : Printer { override fun print() { println("I'm a AwesomePrinter") } }
  16. KOTLIN: MORE THAN MEETS THE EYE DELEGATION class PrinterController(private val

    printer: Printer) : Printer { override fun print() { printer.print() } } fun main(){ val superPrinterController = PrinterController(SuperPrinter()) superPrinterController.print() }
  17. KOTLIN: MORE THAN MEETS THE EYE DELEGATION fun main(){ val

    superPrinterController = PrinterController(SuperPrinter()) superPrinterController.print() } class PrinterController(private val printer: Printer) : Printer by printer Using the keyword by we can easily delegate the implementation of the interface to another object. All the method implementations in the class are gone, the compiler will take care of generate them.
  18. KOTLIN: MORE THAN MEETS THE EYE DELEGATED PROPERTIES The general

    syntax of a delegated property is this: class Foo { var p: Type by Delegate() } The property p delegates the logic of its accessors to another object: in this case, a new instance of the Delegate class. The compiler creates a hidden helper property, initialized with an instance of the delegate object.
  19. KOTLIN: MORE THAN MEETS THE EYE DELEGATED PROPERTIES The general

    syntax of a delegated property is this: class C { var prop: Type by MyDelegate() } // this code is generated by the compiler instead: class C { private val prop$delegate = MyDelegate() var prop: Type get() = prop$delegate.getValue(this, this::prop) set(value: Type) = prop$delegate.setValue(this, this::prop, value) }
  20. KOTLIN: MORE THAN MEETS THE EYE DELEGATED PROPERTIES Kotlin standard

    library provides some factory methods for several useful kinds of delegates: ‣ lazy() ‣ Delegates.observable() ‣ Delegates.vetoable() https://kotlinlang.org/docs/reference/delegated-properties.html
  21. KOTLIN: MORE THAN MEETS THE EYE TYPE ALIASES Type aliases

    is a good way to provide alternative names for existing types. If the type name is too long or complex you can introduce a different shorter or meaningful name and use that new one instead.
  22. KOTLIN: MORE THAN MEETS THE EYE TYPE ALIASES For example:

    val userPass1 = Pair("username1","myhashpassword1") typealias Credentials = Pair<String, String> val credentials1 = Credentials("username1","myhashpassword1") Type aliases do not introduce new types. They are equivalent to the corresponding underlying types.
  23. KOTLIN: MORE THAN MEETS THE EYE TYPE ALIASES When you

    have two or more classes with the same name but different package name and you need to use both in the same place, the second one needs to be referenced by its fully-qualified class name. With type aliases we can work around this situation. typealias MyCustomView = com.filipebaptista.demoapp.customviews.View
  24. KOTLIN: MORE THAN MEETS THE EYE TYPE ALIASES Type aliases

    can also be used to name function types and also use them together with function type parameter names. typealias ClickHandler = (View) -> Unit typealias OnElementClicked = (position: Int, view: View) -> Unit
  25. KOTLIN: MORE THAN MEETS THE EYE AGENDA ▸ Reified ▸

    Operator overloading ▸ Delegation ▸ Type aliases ▸ Inline classes
  26. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES Inline classes

    provide us a way to wrap a type without adding the runtime overhead due to additional heap allocations. This is possible because the data is inlined into its usages, in fact the object instantiation is skipped. Inline classes must have a single property initialized in the primary constructor. Experimental Feature ⚠ since Kotlin 1.3
  27. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES For example:

    data class User(val name: String, val age: Int, val height: Int) val ageUser1 = 36 val heightUser1 = 170 val user1 = User("Username1", ageUser1 , heightUser1)
  28. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES For example:

    data class User(val name: String, val age: Int, val height: Int) val ageUser1 = 36 val heightUser1 = 170 val user1 = User(“Username1", heightUser1 , ageUser1)
  29. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES For example:

    inline class Age(val value:Int) inline class Height(val value:Int) data class User(val name: String, val age: Age, val height: Height) val ageUser1 = Age(36) val heightUser1 = Height(170) val user1 = User("Username1",ageUser1 ,heightUser1)
  30. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES For example:

    inline class Age(val value:Int) inline class Height(val value:Int) data class User(val name: String, val age: Age, val height: Height) val ageUser1 = Age(36) val heightUser1 = Height(170) val user1 = User("Username1",ageUser1 ,heightUser1) val ageUser1 = Age(36) val heightUser1 = Height(170) No actual instantiation of the classes Age & Height happens, at runtime ageUser1 and height1 contains just Int
  31. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES Inline classes

    can also have properties, functions and can inherit from interfaces like regular classes, however there are some restrictions: ‣ cannot have init blocks ‣ properties cannot have backing fields ‣ cannot participate in a class hierarchy, this means that they are not allowed to extend other classes, they must be final.
  32. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES VS TYPE

    ALIASES Aren’t Inline classes the same as Type Aliases?
  33. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES VS TYPE

    ALIASES Indeed they seem to appear to be very similar since both seem to introduce a new type and both will be represented as the underlying type at runtime. However they are different, inline classes introduce a truly new type, unlike type aliases which only introduce an alternative name (alias) for an existing type.
  34. KOTLIN: MORE THAN MEETS THE EYE INLINE CLASSES Inline classes

    are available since Kotlin 1.3 which added the inline keyword to the language. Since they are still experimental, Android Studio will display some warnings when you use of them. The warnings can be disabled by defining explicit compiler flags in your grade file. compileKotlin { kotlinOptions.freeCompilerArgs += ["-XXLanguage:+InlineClasses"] }