Default getter/setter versus normal function in Kotlin


#1

Hi, I am very new to Kotlin, probably two weeks ago, I would not even have guessed myself developing softwares other than in Java. Guessed now who I am?

Here is my question.

public class Hello {

val name: String
    get() = "Hi"

fun getName():String {
    return "Hi"
}

}

I know this will give you compile time error. But I would be happy to have a function getName() that looks easy to invoke than property ‘name’ which has custom getter like the above. Please help me understand why i should go for custom getters and setters, and when i would be using hard-core functions.

Thanks,
Abu A


#2

There is a section at the end of the Kotlin Coding Conventions which says this:

"In some cases functions with no arguments might be interchangeable with read-only properties. Although the semantics are similar, there are some stylistic conventions on when to prefer one to another.

Prefer a property over a function when the underlying algorithm:

  • does not throw
  • has a O(1) complexity
  • is cheap to calculate (or caсhed on the first run)
  • returns the same result over invocations"

So, the answer here is that you should prefer the name property to a getName() method.

Incidentally, you could simplify the property to just this:

public class Hello {
    val name = "Hi"
}

This initializes it, infers its type to be String and creates a default getter.


#3

This version creates instance attribute.

This version creates only getter.


#4

But both will be invoked in the same manner, i.e Hello().name right?

Looking outward when there is no access to the source code, developers may not know whether its just a instance attribute or just getter. Is there any way we can find it if the source is not open?


#5

The algorithm seems to be same for all languages. When its cheap to calculate or same result over multiple invocations, all language prefers to property I guess. Thanks @alanfo


#6

Yes, this doesn’t change the public interface.

Reflection, class decompilation or checking memory footprint.


#7

Thanks @fvasco


#8

Also remember that the JVM applies various optimizations. For even the most minimally optimized code it is likely that any trivial getters (those that only return a field) will be inlined to direct field accesses. As such you would not choose a direct field access just for optimization purposes as the JVM will happily do so for you, but without having to worry about binary compatibility if you choose to have a non-trivial getter in the future.

Kotlin properties are designed with this in mind and will (for non-private properties) always create getters and setters. Optimization is left to the JVM that will do this anyway.


#9

You have right, but define an instance attribute may have memory impact (it depends by padding).

For a constant getter doesn’t declare attribute can have a memory benefit (no allocation/initialization), in other case save a computed value in an instance attribute may lower cpu load.

In any way “fun getName” isn’t the right way, others solution may become only a premature optimization.


#10

I am starting to feel Kotlin has some restrictive style in using the properties and its getters and setters in the sense that both are closely tied up.

private var name: String

I can not have public custom getter for this. If i want to declare a fun that returns this property, i must name something else; getName() clashes with get-name() (jvm thing). Or I must explicitly define this variable as public.


#11

If you want to have a property which can be accessed outside of a class but modified only inside the class, you can do this by defining a custom visibility for the setter:

var name: String
   private set

You’re never supposed to write functions that return values of properties; if you feel the need to do that, then most likely you aren’t using properties correctly.


#12

There are many Java Frameworks that needs class that hides the property and opens up public accessors for the property, a typical POJO. Wouldnt be needed in Kotlin as such?


#13

A regular property in Kotlin is compiled to a private field and public accessor methods. This is exactly what the Java frameworks need.


#14

var name:String = “Hi”

This will be treated as field with public accessors by Kotlin? I am curious about the regular property modifier in this case.


#15

This Kotlin property declaration is equivalent to the following Java code:

 private String name;

 public String getName() { return name; }

 public void setName(String name) { this.name = name; }

Not sure what you mean by “the regular property modifier”.


#16

Ok I think public modifier is default in the declaration:

var name:String = “Hi”

Hence i thought this would be converted like this in Java Equivalent. (Note the public modifier in the java property)

 public String name;

 public String getName() { return name; }

 public void setName(String name) { this.name = name; }

So i explicitly put private before the declaration. Are you trying to explain?

private var name:String = "Hi"

will be converted to this below.

private String name;

public String getName() { return name; }

public void setName(String name) { this.name = name; }

#17

The backing field of a property is always private. The visibility modifier of a property determines the visibility of its accessor methods. If you have a private var name, the getName() and setName() methods will also be private.


#18

I see. It makes sense now. Thanks for your time. @yole

I think i am gonna love Kotlin


#19

If the return value doesn’t change the value can be stored as a static field (or field a companion in Kotlin). Of course if the value is a string or primitive it will be able to live in the constant pool and a static field is a repetition.


#20

Now that 1.1 had been released there are some changes affecting this.

First in a case like this types can be inferred in 1.1:

 val name get() = "Hi"

Also property accesors in 1.1 can be inline. You can declare it on the accessor or the whole property:

inline val name get() = "Hi"

I would also ask if this is a constant value would you not want a const val (which would go at top level or in a companion object):

const val name = "Hi"

If you did go this route in 1.1 this will now be inlined