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
.
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.
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.
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.
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).
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.
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.
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.
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
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" }
Write-only properties with compile-time errors can be achieved since Kotlin 1.0, using a workaround based on @Deprecated
.
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.
The main use case are obviously APIs that allow properties to be written, but not read:
user.password = "secret"
val pw = user.password // forbidden
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
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).
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With