Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Private getter and public setter for a Kotlin property

How to make a property in Kotlin that has a private getter (or just do not have it) but has a public setter?

var status
private get

doesn't work with an error: Getter visibility must be the same as property visibility

In my case, the reason is for Java interop: I want my Java code to be able to call setStatus but not getStatus.

like image 354
Randy Sugianto 'Yuku' Avatar asked Jul 07 '16 10:07

Randy Sugianto 'Yuku'


People also ask

Does Kotlin use getters and setters?

In programming, getters are used for getting value of the property. Similarly, setters are used for setting value of the property. In Kotlin, getters and setters are optional and are auto-generated if you do not create them in your program.

How do I add getter and setter to Kotlin?

Getter in kotlin is by default public, but you can set the setter to private and set the value by using one method inside a class. Like this. Show activity on this post. There is not much code, but lots of things are happening behind the scenes.

Should getters and setters be public or private?

Usually you want setters/getters to be public, because that's what they are for: giving access to data, you don't want to give others direct access to because you don't want them to mess with your implementation dependent details - that's what encapsulation is about.

What are properties getter and setter methods in Kotlin?

Kotlin | Properties Getter and Setter Methods: Here, we are implementing a Kotlin program to demonstrate the example of properties getter and setter methods. Variable having a class-level scope, declared inside the class body but outside the functions called property. Property can be declared with var (mutable) and val (read-only).

How to declare properties in Kotlin?

Kotlin properties can be declared either as mutable using the “var” keyword or as immutable using the “val” keyword. Here, property initializer, getter and setter are optional. Following is an example of the same: By default, all properties and functions in Kotlin are public. But in case of private and protected, you have to add it explicitly.

What is the difference between private and protected properties in Kotlin?

By default, all properties and functions in Kotlin are public. But in case of private and protected, you have to add it explicitly. Also, all properties in Kotlin are final by default.

How do you implement access pattern in Kotlin?

Using a public getter method and a private or protected setter method achieves this. Kotlin provides a succinct way to implement this access pattern by allowing visibility modifiers on a property’s set () method: Now any consumers of the book class can read the inventory property, but only the Book class can modify it.


3 Answers

It's impossible at the moment in Kotlin to have a property with a setter that is more visible than the property. There's a language design issue in the issue tracker on this, feel free to watch/vote for it or share your use cases: https://youtrack.jetbrains.com/issue/KT-3110

like image 65
Alexander Udalov Avatar answered Sep 23 '22 10:09

Alexander Udalov


In current Kotlin version (1.0.3) the only option is to have separate setter method like so:

class Test {     private var name: String = "name"      fun setName(name: String) {         this.name = name     } } 

If you wish to restrict external libraries from accessing the getter you can use internal visibility modifier allowing you to still use property syntax within the library:

class Test {     internal var name: String = "name"     fun setName(name: String) { this.name = name } }  fun usage(){     val t = Test()     t.name = "New" } 
like image 21
miensol Avatar answered Sep 25 '22 10:09

miensol


Write-only properties with compile-time errors can be achieved since Kotlin 1.0, using a workaround based on @Deprecated.

Implementation

Kotlin allows to mark functions deprecated with level ERROR, which leads to a compile-time error when called. Annotating the get accessor of a property as error-deprecated, combined with a backing field (so that private reads are still possible), achieves the desired behavior:

class WriteOnly {
    private var backing: Int = 0

    var property: Int
        @Deprecated("Property can only be written.", level = DeprecationLevel.ERROR)
        get() = throw NotImplementedError()
        set(value) { backing = value }

    val exposed get() = backing // public API
}

Usage:

val wo = WriteOnly()
wo.property = 20         // write: OK

val i: Int = wo.property // read: compile error
val j: Int = wo.exposed  // read value through other property

The compile error is quite helpful, too:

Using 'getter for property: Int' is an error. Property can only be written.


Use cases

  1. The main use case are obviously APIs that allow properties to be written, but not read:

    user.password = "secret"
    val pw = user.password // forbidden
    
  2. Another scenario is a property which modifies the internal state, but is not stored itself as a field. (Could be done more elegantly using different design).

    body.thrust_force = velocity
    body.gravity_force = Vector(0, 0, 9.8)
    // only total force accessible, component vectors are lost
    val f = body.forces
    
  3. This pattern is also useful for DSLs of the following kind:

    server {
        port = 80
        host = "www.example.com"
    }
    

    In such cases, values are simply used as one-time settings, and the write-only mechanism described here can prevent accidentally reading a property (which might not be initialized yet).


Limitations

Since this feature was not designed for this use case, it comes with certain limitations:

  • If accessed using a property reference, the compile-time error turns into a runtime error:

    val ref = wo::property
    val x = ref.get() // throws NotImplementedError
    
  • The same is true for reflection.

  • This functionality cannot be outsourced into a delegate, because an error-deprecated getValue() method cannot be used with by.

like image 45
TheOperator Avatar answered Sep 26 '22 10:09

TheOperator