Default getter/setter versus normal function in Kotlin

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

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.

1 Like

This version creates instance attribute.

This version creates only getter.

1 Like

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?

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

Yes, this doesn’t change the public interface.

Reflection, class decompilation or checking memory footprint.

Thanks @fvasco

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.

1 Like

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.

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.

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.

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?

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

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.

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”.

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; }

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.

1 Like

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

I think i am gonna love Kotlin

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.

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

1 Like