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

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")
}

Related

Jackson Databind not setting default value

In my quarkus application I have an endpoint that takes in a DTO, with a field that has a default value. When I don't send that field, I still get the exception
com.fasterxml.jackson.databind.exc.ValueInstantiationException: Cannot construct instance of
`FooDTO`, problem: Parameter specified as non-null is null: method
io.otherstuff.FooDTO.<init>, parameter someListVariable
at [Source: (io.quarkus.vertx.http.runtime.VertxInputStream); line: 4, column: 1]
The class looks like this:
class FooDTO(
override var someStringVar: String,
override var someListVariable: List<Int> = emptyList(),
): BarDTO
---------------------------------------------
interface BarDTO {
var someStringVar: String
var someListVar: List<Int>
}
Now if I send a payload like this
{
"someStringVar": "Hello Stackoverflow",
"someListVar": []
}
it is working perfectly fine, but when I drop "someListVar" I get the exception from above, even though it should just initialize it as an empty list.
Any help is much appreciated!
The problem is, that during desalinization, the library (fasterxml) calls the primary constructor with null: FooDTO("Hello Stackoverflow", null). The call ends up with the exception as the someListVariable parameter is not nullable (default value is used only when the paremeter is not provided at all, not when it's null).
One option of solving the problem would be providing an explicit JsonCreator:
class FooDTO(
override var someStringVar: String,
override var someListVariable: List<Int> = emptyList()) : BarDTO {
companion object {
#JvmStatic
#JsonCreator
fun of(
#JsonProperty("someStringVar") someStringVar: String,
#JsonProperty("someListVariable") someListVariable: List<Int>?) =
FooDTO(someStringVar, someListVariable ?: emptyList())
}
}
Another posibility is using secondary constructor instead of the default value:
class FooDTO : BarDTO {
override var someStringVar: String
override var someListVariable: List<Int>
#JsonCreator
constructor(
#JsonProperty("someStringVar") someStringVar: String,
#JsonProperty("someListVariable") someListVariable: List<Int>?) {
this.someStringVar = someStringVar
this.someListVariable = someListVariable ?: emptyList()
}
}
Both options are unfortunately a bit verbose.

How to use get() with backing fields in kotlin

in the below code I am trying to create a getter method as a backing field.
so that, when the getLastNameLen property is invoked it should return the length of the lastNameset.
please refer to the code below and help me to fix the bug.
how to display output of the backing fields
code:
class Thomas (val nickname: String?, val age : Int?) {
//backing field 1
var lastName : String? = null
set(value) {
if (value?.length == 0) throw IllegalArgumentException("negative values are not allowed")
field = value
println("lastname backing field set: ${field} ")
}
val getLastNameLen
get() = {
this.lastName?.length
}
}
output
lastname backing field set: jr.stephan
lastName is jr.stephan
lastNameLen is () -> kotlin.Int?
This is because you are using the = operator which is setting the getter to be a lambda.
You have two options:
val getLastNameLen
get() {
return this.lastName?.length
}
OR
val getLastNameLen
get() = this.lastName?.length
basically use the brackets right after get() to make a getter function, or if you can do it in one line use an = right after the get() but don't include the {} otherwise it will treat it like its a lambda

Overwrite self with extension property setter

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

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()

Can a field be cast to non null version of itself?

I have a data class
data class MyModel(private val _data: MyData? = null)
And I want to ensure my data is only accessible when it is not null, else throw.
I use the below which is good.
fun getData(): MyData {
return checkNotNull(_data) { "data shouldn't be null" }
}
However, if I follow the guide as per Override getter for Kotlin data class, the below complaints I need to return MyData? instead of MyData
val data = _data
get(): MyData {
return checkNotNull(field) { "data shouldn't be null" }
}
Is it true that field can't be cast to the Non-null version of it when return?
If your goal is to declare a getter for a Any? property that returns a Any, it's not possible. You'll get the following error:
Getter return type must be equal to the type of the property
So attempting to do something like
val test : String?
get() : String = "hi"
Wouldn't work.
However, you could hide the nullable property and expose a non-nullable property which references the nullable value via casting:
private val test : String? = "hi"
val testNotNull : String = test as String
If test referenced null, an exception will be thrown.
For example:
fun main(args: Array<String>) = print(Demo().testNotNull)
class Demo(private var test: String? = "hi") {
val testNotNull : String
. get() = test as String
}
You can test this snippit out at try.kotlin.org
Although this is not safe. You should rethink your design. If you're not interoping with Java, you shouldn't punish yourself with nullable types.
I don’t think you can. What you did with the fun getData() is a valid approach IMO. Or you could just not use a data class and create a normal class, obviously.
What I think it may work is with something like this:
typealias notNullType = MyData
data class Test(private val _value: MyData? = null) {
val v: notNullType = _value as notNullType
get() { return field }
}
This would totally allow you to do:
fun play() {
val t = Test(null)
print(t.v) //see what I did? :-)
}
THAT BEING SAID… I don’t think “hiding” the ? optional is necessarily a good idea.
It doesn't necessarily mean that the MyData class is null if you cast it like MyData?
The '?' Just allows the object to be null in the instance that it actually becomes null to avoid an exception at runtime.
You can make your class nullable and it can still contain your data.