Search code examples
propertieskotlinkotlin-extension

Kotlin extension function on mutable property


I'm trying to set an extension function on a mutable property so I can reassign the property in the extension function. I wanted to know if it was possible.

My goals is to make Date extensions for easy access. For example:

fun Date.addDays(nrOfDays: Int): Date {
    val cal = Calendar.getInstance()
    cal.time = this
    cal.add(Calendar.DAY_OF_YEAR, nrOfDays)
    return cal.time
}

This function adds number of days to a date using a Calendar object. The problem is each time I have to return a new date which can be confusing to reassign each time you use this function.

What I've tried:

fun KMutableProperty0<Date>.addDays(nrOfDays: Int) {
    val cal = Calendar.getInstance()
    cal.time = this.get()
    cal.add(Calendar.DAY_OF_YEAR, nrOfDays)
    this.set(cal.time)
}

Unfortunately this can't be used on a Date object.

Is it possible to do this?


Solution

  • Unfortunately, you cannot define an extension on a member property and call it fluently in Kotlin 1.0.3.

    Your extension can be rewritten to work like this:

    fun <T> KMutableProperty1<T, Date>.addDays(receiver: T, nrOfDays: Int) {
        val cal = Calendar.getInstance()
        cal.time = this.get(receiver)
        cal.add(Calendar.DAY_OF_YEAR, nrOfDays)
        this.set(receiver, cal.time)
    }
    

    with the following usage:

    class C(var date: Date) { ... }
    val c = C(someDate())
    
    C::date.addDays(c, 123)
    

    With bound callable references (likely supported in Kotlin 1.1) this will be possible with the following syntax:

    c::date.addDays(123)
    

    As @MarcinKoziński suggests, you can also mutate your Date objects without reassigning the property:

    fun Date.addDays(nrOfDays: Int) {
        val cal = Calendar.getInstance()
        cal.time = this
        cal.add(Calendar.DAY_OF_YEAR, nrOfDays)
        this.time = cal.timeInMillis
    }
    

    with usage:

    class C(var date: Date)
    val c = C(someDate())
    
    c.date.addDays(123)
    

    With this solution, you have to control the references to the Date object which is mutated. This solution works good with mutable objects, though it is not suitable for a property storing immutable ones.