Overwrite self with extension property setter - kotlin

I want a Kotlin property that can replace the original value. For example:
var String.setString
get() = "ignorethis"
set(value) = this = value
(I'm actually using it on UBytes to add getters and setters for the upper and lower nibbles).
However, in my example above I get Variable expected. Is it possible to modify this with an extension property?

String is immutable, and you can only do that on mutable types like this:
fun main() {
val x = mutableListOf("old")
x.setString = mutableListOf("New Pro Max Extra Large Plus")
println(x)
}
var <T> MutableList<T>.setString
get() = this
set(value) = value.forEachIndexed { idx, it -> this[idx] = it } ```

Related

what is the difference between var and val in extension properties?

I created extension properties and I'm having this problem
fun main(args: Array<String>) {
println(Animal("Mia",1,1.0))
}
class Animal(var name : String, var age : Int, var weight : Double)
var Animal.getXXX : String // compiler : Property must be initialized
get() = "$name, $age, $weight"
val Animal.getXXX : String // the compiler is running properly
get() = "$name, $age, $weight"
in the code above. why should i use val instead of var?
The error message is perhaps a bit confusing. For extension fields using var they are expected to have both a getter and a setter. Fields using val only need to have a getter (and can't have a setter). The following code works:
var Animal.getFoo : String
get() = "$name, $age, $weight"
set(value) { /* do something */ }
var is mutable and we can reassign or change its value. But we can't change val value.
The difference between var and val in extension properties is that while writing extension property if you use val you can only use get because you can not set value to it as it is immutable constant variable you can not use set() in val extension property
For Example
val String.extensionProperty
get() = "Value"
And if you want to make an extension property with var which you want to be mutable so you can set value into it as well and perform any other action while updating varaible.
For Example
var String.extensionProperty
get() = "Value"
set(value) {
println("variable has been updated with this data $value")
}

Kotlin DSL variable imitation

Using Kotlin type-safe builders one might end up writing this code
code {
dict["a"] = "foo"; // dict is a Map hidden inside that can associate some name to some value
println(dict["a"]); // usage of this value
}
This code is ok, but there is a problem: "a" is just a string. I want it to be like a user-defined variable - an identifier that is recognized by the compiler, auto-complete enabled.
Is there a way to turn it into something like this?
code {
a = "foo"; // now 'a' is not a Map key, but an identifier recognized by Kotlin as a variable name
println(a);
}
I can do this if I make code's lambda an extension function over some object with a field a defined inside. This is not what I want. I want to be able to use other variables (with unknown names) as well.
A possible workaround could be
code {
var a = v("a", "foo");
println(a);
}
Where v is a method of the extension's object, that stores value "foo" inside "dict" and also returns a handle to this value.
This case is almost perfect, but can it be clearer/better somehow?
You can use property delegation:
class Code {
private val dict = mutableMapOf<String, String>()
operator fun String.provideDelegate(
thisRef: Any?,
prop: KProperty<*>
): MutableMap<String, String> {
dict[prop.name] = this
return dict
}
}
Use case:
code {
var a by "foo" // dict = {a=foo}
println(a) // foo
a = "bar" // dict = {a=bar}
println(a) // bar
}

Use an anonymous function when setting the return value for a getter in Kotlin

In Kotlin when you create a getter/setter pair, you typically set the getter using inline code. But I am wondering if it is possible to replace the inline code with an anonymous function:
var UserSettings: UserSettings?
get() = getUserSettings() // Replace this with an anonymous function?
set(value) {
putPref(USER_SETTINGS, Json.stringify(UserSettings.serializer(), value!!))
}
private fun getUserSettings(): UserSettings? {
val info = getPref(KEY_USER_SETTINGS)
return Json.parse(UserSettings.serializer(), info!!)
}
Can the getUserSettings() be replaced with an anonymous function? In the code above I have a separate function getUserSettings that I would like to place right after the get() =
Yes, you can. Just have a look at getters and setters - backing properties, where there is (the first and only example), mentioning get() { instead of get() =. Your sample would then look as follows:
var UserSettings: UserSettings?
get() {
val info = getPref(KEY_USER_SETTINGS)
return Json.parse(UserSettings.serializer(), info!!)
}
set(value) {
putPref(USER_SETTINGS, Json.stringify(UserSettings.serializer(), value!!))
}
i don't know this is what you asking for but it might be helpful
var v: Int? = null
get() = run {
return field
}
set(value) = run {
field = value
}
in this case getter must be equel to Int? and setter allways must be equel to Unit. so in the run we return that types
I think the answer of #Roland is valid.
Be aware that maintaining the = before the anonymous function the compiler returns an error as you are describing.
Can you double check that you are NOT writing something like this?
var UserSettings: UserSettings?
get() = { ... }
And that you are writing:
var UserSettings: UserSettings?
get() { ... }

Kotlin - extension property setter for mutable subclass

Assume that I want to have a property for List and then extend this property with setter for MutableList. For example, I want to have a getter for last element in the list, and also a setter if the list is mutable. So I want the following:
val <T> List<T>.myLast
get() = this.last()
var <T> MutableList<T>.myLast: T
set(value) {
this[this.size - 1] = value
}
But this doesn't compile. Can this be achieved? The closest things I can do:
Declare another property:
val <T> List<T>.myLast
get() = this.last()
var <T> MutableList<T>.myMutableLast: T
get() = this.last()
set(value) {
this[this.size - 1] = value
}
I don't like this because I want to have the same name.
Create getter and setter explicitly:
fun<T> List<T>.getMyLast() = this.last()
fun<T> MutableList<T>.setMyLast(value : T) {
this[this.size - 1] = value
}
I don't like it because it doesn't have property syntax.
Just add a getter to the second property which calls the first one:
val <T> List<T>.myLast
get() = this.last()
var <T> MutableList<T>.myLast: T
#JvmName("someName")
get() = (this as List<T>).myLast
set(value) {
this[this.size - 1] = value
}
In this case you could equally do get() = this.last(), but this way changing the first definition automatically affects the second one.
It'll get resolved like method overloading does, so e.g.
val x: List<String> = mutableListOf("")
val y: MutableList<String> = mutableListOf("")
x.myLast // calls List<T>.myLast.get()
y.myLast // calls MutableList<T>.myLast.get()

Kotlin Data class copy extension

I am trying to find a solution for a nice kotlin data class solution. I have already this:
data class Object(
var classMember: Boolean,
var otherClassMember: Boolean,
var example: Int = 0) {
fun set(block: Object.() -> kotlin.Unit): Object {
val copiedObject = this.copy()
copiedObject.apply {
block()
}
return copiedObject
}
fun touch(block: Object.() -> kotlin.Unit): Object {
return this.set {
classMember = true
otherClassMember = false
block() }
}
}
val test = Object(true,true,1)
val changedTest = test.touch { example = 2 }
the result of this method is that the changedTest object has classMember = true, otherClassMember = false and example = 2
The problem with this solution is, the class properties are not immutable with var declaration. Does somebody have an idea how to optimize my methods to change var to val?
val says that a variable can't change it's value after initialization at the definition point. Kotlin's generated copy method does not modify an existing copy after construction: this method actually uses retrieved values from an object, replaces these values with ones that provided in copy method (if any), and after that just constructs a new object using these values.
So, it is not possible to perform such an optimization if you are going to change object's state after construction.
If I understood what you want correctly, you can do
data class Object(
val classMember: Boolean,
val otherClassMember: Boolean,
val example: Int = 0) {
fun touch(example: Int = this.example): Object {
return copy(
classMember = true,
otherClassMember = false,
example = example)
}
}
val test = Object(true,true,1)
val changedTest = test.touch(example = 2)
Though you need to repeat parameters other than classMember and otherClassMember but without reflection you can't do better.