Thread: Hopping Islands from Java to Kotlin Part 5

Results 1 to 2 of 2
  1. #1 Hopping Islands from Java to Kotlin Part 5 
    Extreme Donator

    nbness2's Avatar
    Join Date
    Aug 2011
    Posts
    692
    Thanks given
    274
    Thanks received
    139
    Rep Power
    430
    Hopping Islands: From Java to Kotlin Part 5

    This series is aimed at existing Java developers that might feel tempted to switch over.
    The goal of this series is to introduce Kotlin as a language you can use in tandem with Java, or even as a complete replacement.
    Across the series, I will be covering a multitude of topics (usually with a few topics per part) on the benefits of using Kotlin over Java.

    Here are the topics I picked out for Part 5 (open class got merked and replaced by functional interfaces)
    • lateinit modifier
    • Functional Interface
    • delegation


    lateinit modifier
    In Kotlin, things are meant to be as intuitive as possible. That means requiring your properties to return something! However, even at jetbrains they know that you aren't always instantiating every property and will often let them be nullable types.
    You know how jetbrains feels about null... so they created lateinit variable modifier, it stands for "late initialization" and functions like a normal variable (unless you are using it improperly!!).
    lateinit allows ​a variable to remain uninitialized until you set it. However, you should be wary, if you try to access the value when nothing has been set you will get an exception thrown at you, so ONLY USE LATEINIT IF YOU ARE 100% SURE YOU WILL HAVE SET THE VALUE BEFORE YOU EVER ACCESS IT!!!

    There are a few built-in rules to use lateinit
    • You can only use lateinit with a var, this is because you cannot set a val
    • You cannot use lateinit with primitives, this is because you cannot find an invalid value for any primitive in kotlin.
      • You can however use the Delegates.notNull() property delegate to achieve the same functionality
      • var lateInt: Int by Delegates.notNull()
    • You cannot use lateinit with nullable types, this is because that is essentially how it works under the hood but without requiring you to deal with the nullable type



    Functional Interface
    This is the Kotlin implementation of Single Abstract Method Interface conversion that they introduced when using Java classes.
    This is a very useful piece of functionality that really avoids a lot of boilerplate code for simple things.
    You define a functional interface just like any other interface, except fun is in front of interface!
    To instantiate an instance of a functional interface, you simply call the type and put your braces just like a last parameter lambda and put your code in! Your lambda will have the same signature as the one abstract function in the interface.
    There are a few rules to fun interface
    • You can only define a single abstract function, this is for extremely convenient syntax purposes and boilerplate elimination
      • You can define as many functions as you want, but only ONE of them may be abstract (no implementation provided)
    • You cannot define any abstract properties. This is because there is no way to do it via SAM lambda syntax!


    Here is an example usage from one of my more recent personal projects

    Code:
    fun interface AcceptsItemPolicy<T> {
        fun test(item: T): Boolean
    }
    
    val generalStorePolicy = AcceptsItemPolicy<Item> { item -> // This lambda is (Item) -> Boolean, so item is an Item
        item.isTradable()
    }
    Delegation
    Delegation is a very extremely powerful feature that will obliterate boilerplate code all over the place!

    First off, let's talk property delegation! You may have noticed some weird syntax in the lateinit modifier. What is by? Well, that's the delegation keyword! It's how you delegate a property (or class!) type to a separate class without sacrificing API readability and confusing types.
    There are 4 parts to a property delegate. Let's take the lateinit example: var lateInt: Int by Delegates.notNull()
    • var lateInt -- This is the property itself
    • : Int -- This is the provided type (can be ommitted but you must provide a type to the delegate provider if your delegate is generic like Delegates.notNull())
    • by -- This is the keyword to provide a delegate for the left side from the right side
    • Delegates.notNull() -- This is the delegate provider!

    The power is in the delegate provider. So how do I make a delegate provider? Your delegate provider must do 2 things
    • Implement override fun getValue(thisRef: Any?, property: KProperty<*>): T // T can be whatever type you are returning if you have a specifically typed delegate
      • This is REQUIRED in delegates for both var and val.
      • thisRef is going to be the type of the "receiver" if any, this is only not Any? if you are making an extension delegate. For example a delegate delegating hasSkull for a Player to an Attribute<T> would look like: val Player.hasSkull: Boolean by Attribute("HasSkull")
      • property is going to be the actual property, so in this case lateInt. You can access the property's setter, getter, name, basically anything reflection would allow you to get from the property
      • this does NOT have to return the value you set it to, you can transform it in any way you'd like before giving the value back!
    • Implement public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T)
      • This is REQUIRED in delegates for only var, as you cannot set a val, but you can still use a delegate with setValue for val.
      • [inline]thisRef[inline] and property are going to be the same as getValue
      • value this will be what you put after lateInt =, in this case an Int
    • It is recommended for the delegate to implement the interface ReadOnlyProperty<Any?, T> or ReadWriteProperty<Any?, T> where Any? is the receiver type and T is the take\return type.


    With this information, let's create a delegate that takes an Int and when you get it, it will actually give you back that number but doubled! Try it out before you sneak a peek

    Spoiler for solution:

    Code:
    class DoubleDelegate(private var intValue: Int): ReadWriteProperty<Any?, Int> {
        override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
            return intValue * 2
        }
        override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
            intValue = value
        }
    }


    It's seriously that easy!

    Now on to another really nice feature: Class delegation!

    Class delegation lets you delegate any class to an interface via a property in the constructor or an expression by using the same by keyword but in the place where you declare what interface(s) you are implementing.
    You don't have to write any special code to delegate an interface for a class like you did with the properties! It's as easy as having an interface and a value that is of the same type.

    Here's an example where you provide 3 values to a class and make that class a list comprised of those 3 values!

    Code:
    class ThreeValueList<T>(val firstValue: T, val secondValue: T, val thirdValue: T): List<T> by listOf(firstValue, secondValue, thirdValue)
    ThreeValueList<T> is now a List<T>! No overriding all the functions or having the IDE do it for you. It just works!

    There are 3 rules to keep in mind when using class delegation
    • You can ONLY delegate to an interface! No open or abstract classes.
    • You CANNOT delegate a inline class\value class (as of kotlin 1.5, inline class has been replaced with value class) to an interface. As of Kotlin 1.7, you CAN do this.
    • You MUST manually override any functions or properties that have multiple declarations from multiple delegated interfaces!


    I hope you found this useful and learned more about kotlin!
    KT/JAVA - NBX 637 - HERE!
    KT - Drop table 4: Flexible, Powerful - HERE!
    KT - Command: Simplify writing commands - HERE
    KT - NbUtil: Make your kotlin easier - HERE
    KT - Hopping Islands: From Java to Kotlin - P1 - P2 - P3 - P4 - P5
    Reply With Quote  
     

  2. Thankful users:


  3. #2  
    Extreme Donator

    nbness2's Avatar
    Join Date
    Aug 2011
    Posts
    692
    Thanks given
    274
    Thanks received
    139
    Rep Power
    430
    tiny update to `value class` and interface delegation section. you can actually delegate value classes to interfaces now. love that.
    KT/JAVA - NBX 637 - HERE!
    KT - Drop table 4: Flexible, Powerful - HERE!
    KT - Command: Simplify writing commands - HERE
    KT - NbUtil: Make your kotlin easier - HERE
    KT - Hopping Islands: From Java to Kotlin - P1 - P2 - P3 - P4 - P5
    Reply With Quote  
     


Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. Hopping Islands: From Java to Kotlin Part 1
    By nbness2 in forum Application Development
    Replies: 6
    Last Post: 06-20-2019, 04:58 AM
  2. Hopping Islands: From Java to Kotlin Part 4
    By nbness2 in forum Application Development
    Replies: 0
    Last Post: 05-30-2019, 01:58 PM
  3. Hopping Islands: From Java to Kotlin Part 3
    By nbness2 in forum Application Development
    Replies: 0
    Last Post: 04-11-2019, 01:09 PM
  4. Hopping Islands: From Java to Kotlin Part 2
    By nbness2 in forum Application Development
    Replies: 4
    Last Post: 04-07-2019, 11:06 AM
  5. From .class to .java.
    By Xot Tzox in forum Requests
    Replies: 9
    Last Post: 07-26-2009, 11:04 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •