3

In Java, I would do something like this:

class Person {

    private Record record;

    public String name() {
      record().get("name");
    }

    private Record record() {
      if (record == null) {
        refetch();
      }
      return record;
    }

    private void refetch() {
      record = service.doSomething()
    }

}

In Kotlin, I have this equivalent code:

class Person(private var record: Record?) {

    fun name() : String {
      record().get("name");
    }

    private fun record() : Record {
      record ?: refetch()
      return record!!;
    }

    private fun refetch() {
      record = service.doSomething()
    }

}

As you see, I'm using !! operator, and I don't really like. Is there another more idiomatic way to do this?

If I simply follow the Java way (if (record == null)), I get this error:

Smart cast to "Record" is impossible, because "record" is a mutable property that could have been changed by this time

Héctor
  • 24,444
  • 35
  • 132
  • 243

2 Answers2

4

In idiomatic Kotlin, you would use a lazy delegated property:

class Person(private val service: Service) {

    private val record by lazy { service.doSomething() }

    fun name() = record.get("name");
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks. How could force reinitialization? i.e. call again `service.doSomething(). is that possible? – Héctor Nov 24 '18 at 16:16
  • 1
    AFAIK, there is nothing available to do that in the stdlib. You'd need to implement a ResettableLazy by yourself. A quick google search leads to this: https://stackoverflow.com/questions/35752575/kotlin-lazy-properties-and-values-reset-a-resettable-lazy-delegate – JB Nizet Nov 24 '18 at 16:20
  • Thank you so much. I will do that. – Héctor Nov 24 '18 at 16:21
1

You're Java code didn't compile so I mocked up an example.

    class Record {
        String name;
        String address;

        Record(String name, String address) {
            this.name = name;
            this.address = address;
        }

        String getName() {
            return name;
        }
    }

    class Person {

        private Record record;

        public String name() {
            return record().getName();
        }

        private Record record() {
            if (record == null) {
                refetch();
            }
            return record;
        }

        private void refetch() {
            record = new Record("Joe Smith", "101 Broadway, NYC, NY");
        }

    }

Kotlin forces you to DECLARE if a value is nullable by using the '?' char when you define it. So it needs to look like this:

        internal class Record(var name: String, var address: String)

    internal class Person {

        private var record: Record? = null

        fun name(): String {
            return record()!!.name
        }

        private fun record(): Record? {
            if (record == null) {
                refetch()
            }
        return record
        }

        private fun refetch() {
            record = Record("Joe Smith", "101 Broadway, NYC, NY")
        }

    }
Waxhaw
  • 599
  • 5
  • 9