Kevin van Mierlo
Kevin van Mierlo

Reputation: 9814

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?

Upvotes: 3

Views: 1153

Answers (2)

hotkey
hotkey

Reputation: 148089

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.

Upvotes: 1

Marcin Koziński
Marcin Koziński

Reputation: 11064

Instead of returning a new Date and trying to update your property, you can just mutate the Date that your property already holds:

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

Upvotes: 3

Related Questions