3

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?

hotkey
  • 140,743
  • 39
  • 371
  • 326
Kevin van Mierlo
  • 9,554
  • 5
  • 44
  • 76
  • Does this actually compile (either of your snippets)? `time` field on a `Calendar` object is of type `int`, but looks like you're assigning a `Date` value to it. And then again you're returning `cal.time` as `Date`, while it's an `int`. – Marcin Koziński Jul 11 '16 at 13:45
  • @MarcinKoziński, both have no errors on my side, and `cal.time` is `java.util.Date`. – hotkey Jul 11 '16 at 13:56
  • @MarcinKoziński Yes both compile, but the 2nd one can't be used on a `Date` object. `cal.time` returns a `Date` – Kevin van Mierlo Jul 11 '16 at 13:56
  • Yes, sorry, I just couldn't read documentation straight and got confused! – Marcin Koziński Jul 11 '16 at 14:14

2 Answers2

3

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
}
Marcin Koziński
  • 10,835
  • 3
  • 47
  • 61
  • I can't believe I haven't done this.. That would fix my entire issue, thanks! – Kevin van Mierlo Jul 11 '16 at 14:16
  • While this fixes my issue, the answer from @hotkey answers my question. So I'll have to accept his answer as the right one. But thank you so much for this answer, this fixes a lot of issues I had. – Kevin van Mierlo Jul 11 '16 at 14:21
1

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.

hotkey
  • 140,743
  • 39
  • 371
  • 326
  • The first option looks good enough to use, unfortunately I cannot get it to work. It has a receiver type mismatch. It also doesn't pop up in the auto completion. I'm using the date in a function, so I'm creating a var which is a date and try to call the extension function. Any clue what I'm doing wrong? – Kevin van Mierlo Jul 11 '16 at 14:06
  • @KevinvanMierlo, did you change the extension signature to `fun KMutableProperty1.addDays(...)`? Works fine for me, the call is `C::date.addDays(c, 123)`. – hotkey Jul 11 '16 at 14:08
  • Yeah I did change the signature. Did something else wrong, it's working now. It's not ideal, but it's something. Thanks for the answer! – Kevin van Mierlo Jul 11 '16 at 14:13
  • Thank you for all the information! Hope that the bound callable references are released soon. I've accepted your answer because it answers my question. I also wanted to note the answer of @MarcinKoziński because that answer fixed my issue. – Kevin van Mierlo Jul 11 '16 at 14:31