Collection<KProperty1<I,*>> How to get the property instance - kotlin

I'm currently using Reflection to inspect an element at runtime using the class.memberProperties function. The type of properties is collection<KProperty1<I, *>> so I run through each of the KProperty objects to find the one that I want by checking if the name is equal to "nameIWant", though I would much rather be able to get the instance of the property from the KProperty by using the .get() method on the property, so that then I could do a check such as:
if (property.get(receiver) is ClassIWant) {
//Do something
}
My code looks like this:
val properties = request.payload::class.memberProperties
properties.forEach { property ->
run {
if (property.name.equals("nameIWant")) {
}
}
}
So far I've been trying to use the .get() method on the KProperty1 type but it takes an argument receiver of type Nothing. I'm not able to work out what I need to pass in order to call the .get() method and get the particular instance of the property. I've also checked the documentation here: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-property1/index.html but it hasn't really helped at all.

justPassingBy is right. but the more simple way is to use:
myObj.javaClass.kotlin.memberProperties.foreach { property ->
property.get(myObj)
}

If you want to get the value of the property, cast the class into invariant type.
instance::class.memberProperties.first() // returns KProperty1<out Instance, *>
(instance::class as KClass<Instance>).memberProperties.first() // returns KProperty1<Instance, *>
If your KClass<Instance> is KClass<*>, use Any as Instance.
Why did the KProperty.call take Nothing as receiver?
Because instance::class returns KClass<out Instance>, which propagates the covariant type argument down to the property, which it becomes KProperty<out Instance, *>, which narrows down the possible method receiver to any subtype of Instance, but because we do not know which, we can not safely supply any instance of Instance, as show by the rules of variance, which here limit the generic type argument to Nothing, which means it is impossible to call the method at all.
Why is ::class designed to be covariant?
To guarantee safety. This has been an issue of great debates as it seems somewhat illogical.
If you want to know the type of the value that the property can return, use
property.returnType
It returns a KType, wich is Kotlin's version of Java's Type, which is a more generic concept of a Class (which is one of the implementations of Type).
If you need to 'convert' the KType to a KClass, you need to do the same as if you needed to convert Type to a Class, which is get the raw type of the type. Raw type is type stripped of the any generic information, yes, an erased type. The way to do this is (seemingly) more complicated (involves handling each possible KType/Type implementation) and I recommend checking for answer to this problem separately.
You will be able to reuse Java implementation (that you will surely find on your own) using:
kType.javaType.covertJavaTypeToJavaClass().kotlin // returns KClass<*>
Corrections in your question. I recommend using the proper terms if you wish to receive proper answers:
* I in your question is type of the method receiver, not the value of the property
* collection is not a type, Collection is
* property is ClassIWantis ambiguous as property.type is type of the value in the property and property::class is simply the property implementation, is is also an instanceof check, but in reflection, you need to use KClass.isSubclassOf, or what is known in Java as type.isAssignableFrom (watch the call order), which then makes your condition to be ClassIWant.isSuperclassOf(property.type.getRawType())
* instance of the property properties have values, not instances. Only classes have instances. Instances are values and values are instances (of some class), but you must still say instance representing the value of the property

You can create a KType for your ClassIWant and then check the property's returnType. It will be something like this:
val properties = request.payload::class.memberProperties
val desiredType = ClassIWant::class.createType()
properties.forEach { property ->
if (property.name == "nameIWant" && property.returnType == desiredType) {
//todo
}
}
btw you can cast your property variable to correct type and use get
val properties = request.payload::class.memberProperties
properties.forEach { property ->
val value = (property as KProperty1<Payload, *>).get(request.payload)
if (property.name == "nameIWant" && value is ClassIWant) {
//todo
}
}

prop.getter.call(obj) as String?

Related

kotlin get static type of a class property

I'm trying to get the type of some class properties in order to strongly typing my Kotlin Code.
In typescript, we can do this (stupid examplebut this is to explain)
class Test {
private _prop:string
constructor(val:Test["_prop"]){
this._prop = val
}
public get prop():Test["_prop"] { return this._prop}
}
const t:Test["_prop"] = "fdds"
The benefit here is that if I need to chnange the type of "_prop", no need to refactor the whole code, as the type is find thanks to Test["_prop"].
Is there a way to do this in Kotlin ?
I've seen reflection functions in Kotlin, but can't get what I want
Kotlin code :
class Test(val prop:Int) {
fun ppr() {
println(prop)
}
fun getProp():Int {
return prop
}
}
fun main() {
println("Hello, world!!!")
var t:Test = Test(4)
t.ppr()
var a:Int = t.getProp() // how to change :Int by "return type of func Test.prop
}
What you're trying to do is the opposite of strong typing. The point of a strong-typed system is that you're defining exactly what things are, and the system requires you to interact with those things correctly, and prevents you from doing things those types don't support
You're working with specific types and defined type hierarchies, and the way you can interact them is strongly enforced. It's possible to go outside the type system, e.g. with unchecked casts, or by reflection (which can get close to throwing the whole thing out completely) - but that's losing the benefits of strong typing, the guarantees and assistance it can provide, and makes errors a lot more likely
Basically if you want to change the type, you're supposed to refactor it. That lets the system handle it all for you systematically, and it will point out any problems that change might introduce, so you can resolve and handle them. This is another benefit of a strongly typed system - it can help you in this way
If you want to stay within the type system, but just want to update a type and avoid creating changes in a bunch of files, then #Sweeper's typealias approach will work - kinda abstracting a type definition away to one place (and you can give it a more meaningful name that doesn't reflect the specific type it happens to be right now). But if you meaningfully change what that underlying type is, your code will probably have to handle it anyway, unless you're just doing a common call on it like toString().
I might have got what you're asking for wrong, but I wanted to point this stuff out just in case, since you were talking about reflection and all!
You can't do it exactly like that in Kotlin, but you can declare a type alias, which sort of achieves the same result - enabling you to change the type of multiple things by editing only one place.
typealias PropType = Int
class Test(val prop: PropType) {
fun prop(): PropType {
return prop
}
}
To change the type of both, just change the typealias PropType = Int line.
However, note that you don't actually need to do this if you just want to write a getter. You don't need to explicitly write getters if all it does is just returning the property's value. If you want to do something extra in the getter, you can do:
class Test(prop: Int) {
val prop = prop
get() {
// do something extra in the getter
println("getting prop!")
return field // return the underlying field
}
}
The getter will be called whenever you access Test.prop, and again, you only need to change one place to change the type of the property.

Kotlin error Smart cast to 'X' is impossible, because 'state' is a property that has open or custom getter when trying to observe state

I'm try to observe state as you see but when i use when and try to get data, compiler says Smart cast is impossible by casting it solves the problem but It felt like i'm doing it in wrong way, i want to know there is any other solution to fix this error.
sealed class Response<out T : Any> {
object Loading : Response<Nothing>()
data class Success<out T : Any>(val data: T) : Response<T>()
data class Error(val error: ResultError, val message: String? = null) : Response<Nothing>()
}
val userState by userViewModel.userState.collectAsState()
when(userState){
is Response.Error -> userState.error // Smart cast to 'Response.Error' is impossible, because 'userState' is a property that has open or custom getter
Response.Loading -> Unit
is Response.Success -> userState.data // Smart cast to 'Response.Success<User>' is impossible, because 'userState' is a property that has open or custom getter
}
This line:
val userState by userViewModel.userState.collectAsState()
Defines userState through a delegate, so the compiler cannot guarantee that subsequent reads of the property's value will give the same value. In particular here, it means the access in the when() condition and the access within the when's branches might not return the same value from the compiler's point of view, thus it cannot smart cast.
You could use an intermediate variable here:
val userState by userViewModel.userState.collectAsState()
when(val s = userState){
is Response.Error -> s.error
Response.Loading -> Unit
is Response.Success -> s.data
}
Now since s is a local val the compiler can guarantee it will have the same value in the condition and in the when branches, and smart casting works
Compiler can only perform smart casts when it can guarantee that the value won't change with time. Otherwise, we might get into the situation where after the type check the variable changed to another value and does no longer satisfy the previous constraint.
Delegated properties (ones declared with by keyword) are much different than "normal" variables. They don't really hold any value, but each time we access them, we actually invoke getValue() (or setValue()) on their delegate. With each access the delegate may provide a different value. Compiler can't guarantee immutability of the value and therefore smart casts are disallowed.
To fix this problem, we need to create a local copy of the data that is delegated. This is like invoking getValue() and storing the result as a local variable, so it can no longer change. Then we can perform smart casts on this local data copy. It can be understood better with the following example:
fun main() {
val delegated by Delegate()
println(delegated) // 0
println(delegated) // 1
println(delegated) // 2
val local = delegated // `local` set to 3
println(local) // 3
println(delegated) // 4
println(local) // 3
}
class Delegate {
var i = 0
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return i++
}
}
Each time we access delegated it returns a different value. It may change between null and not null or even change the type entirely. When we assign it to local we take "current" value of delegated and store its copy locally. Then delegated still changes with each access, but local is constant, so we can perform smart casts on it.
Depending on your case, if there is a way to acquire "current" or "direct" value of userViewModel.userState.collectAsState() then you can use it when assigning to userState - then it should work as you expect. If there is no such function, then I think the easiest is to use another variable to store a local copy, like this:
val _userState by userViewModel.userState.collectAsState() // delegated
val userState = _userState // local copy, immutable
when(userState){
is Response.Error -> userState.error // Smart cast to 'Response.Error' is impossible, because 'userState' is a property that has open or custom getter
Response.Loading -> Unit
is Response.Success -> userState.data // Smart cast to 'Response.Success<User>' is impossible, because 'userState' is a property that has open or custom getter
}

In Kotlin what does this get() do

Im new to Kotlin and wonder what does the get() = login_email.txt.toString() do?
Does it set email String?
get() and set(value) after a field means the declaration of a custom getter and/or setter. Here's a basic example using default values:
class Demo{
var something: String
get() = field
set(value) {
field = value;
}
constructor(something: String){
this.something = something;
}
}
These two are, however, redundant. You don't actually need them unless you're doing something custom with it. They're automatically added for vars, though that only applies to getters for vals (because they can't be changed, they don't have setters).
The line you were asking about is a custom getter.
get() // declares a custom getter
= // if you don't know how this works, see my explanation below
login_email.text.toString() // you should be familiar with this part already; gets the string value of the field
If you're not familiar with the syntax, this is the equivalent without =:
get(){
return login_email.text.toString()
}
if you have a single return, you can replace the brackets and return keyword with =. If it helps you remember, just remember the alternative to using = (a body + the return keyword)
TL;DR: it declares a custom setter that returns the value of a TextView/EditText (not sure which it is, you didn't include that in the question)
In your case, you're using a custom getter or setter to handle property data. The fields themselves don't actually contain any data, but you have getters for a different object.
Take this as an example:
class Demo(private val someObject: MyCustomObjectWithSomeData){
val text: String
get() = someObject.text
... same for other stuff. Could also have setters, if the properties are mutable
}
Here the object is private, but it could be public or internal for that matter.
Kotlin supports quite a lot with custom getters. For an instance, you can declare a field to display specific fields of a private variable. For an instance, in your case, you have the email. It doesn't need to be a variable, since you have a custom getter, and the field isn't initialized. If you change var email to a val, you can make it non-null:
val email: String
get() = login_email.text.toString()
That also helps with null-safety.
And for the error field, it's slightly more complicated. It can't be a val because you declare a custom setter, but if you add a getter, you can make it non-null:
var error: String
get() = login_error.text.toString()
set(value){
login_error.text = value;
}
Short Answer
get() is used to define a custom getter method. Anytime you access the property you are using the custom getter method
Long Answer
So before we can talk about get(), it is important that we get a proper understanding of what properties actually are.
Properties
We all know that in object oriented programming the main idea of a class is to encapsulate data and code that works on data in a single class. In a language like Java (don't worry we will get back to Kotlin soon), the data of a class is stored in private fields, we then use accessor method (getters and setters) to access the data. In Java the combination of accessor methods and a field is called a property
Now in Kotlin does things a little differently, it entirely replaces the traditional idea of defining accessor methods and fields. By using the val or var keyword Kotlin will automatically generate the corresponding field and appropriate accessor methods for us.
get()
There will come a time when either your code or someone else's code needs a more robust solution to the automatic accessor methods created by Kotlin. This is where get() and set() come into play. By using get() you are defining your own custom accessor method(getter for get()) to be used when you are accessing this property.
I would also like to point out that since val is immutable it does not allow you to define a set() method, only a get()

How can I pass property getter as a function type to another function

How can I pass property getter to a function that accepts function type?
Here is an example of what I want achieve:
class Test {
val test: String
get() = "lol"
fun testFun(func: ()->String) {
// invoke it here
}
fun callTest() {
testFun(test::get)
// error: Type mismatch: inferred type is
// KFunction1<#ParameterName Int, Char> but () -> String was expected
}
}
Is there a way?
You can reference the getter by writing ::test (or this::test).
When you write test::get, you are actually referencing the get method on String. That method takes an index and returns the character at that index.
If the property was a var and you want a reference to its setter, you can write ::test::set.
For more info on property references, see here: https://kotlinlang.org/docs/reference/reflection.html#bound-function-and-property-references-since-11
As already mentioned, you can use this::test to refer to the getter. Alternatively, if you have kotlin-reflect, you can do this::test.getter.
When you pass the field as a function, it assumes you mean the getter. As a result, if you want the setter, you have two options:
this::test::set
or
this::test.setter
The latter, just like this::test.getter requires kotlin-reflect, or the program will crash (tested locally with Kotlin 1.2.50)
You can, however, get the getter in another way. But I recommend you just stick with this::test because it's shorter.
You can do:
this::something::get
With just something::get it refers to the method inside the String class, which returns a char at an index. For reference, the method declaration:
public override fun get(index: Int): Char
If you don't mind, just use { test } (e.g. testFun { test }). This will exactly translate to your () -> String. The next best alternative is probably ::test (or this::test) as was already mentioned.
The second has probably only minor (negligible?) impact on performance. I did not test it myself, nor did I found any source which tells something regarding it. The reason why I say this, is how the byte code underneath looks like. Just due to this question I asked myself about the difference of the two: Is the property reference (::test) equivalent to a function accessing the property ({ test }) when passed as argument e.g. `() -> String`?
It seems that you are doing something wrong on logical level.
If you are overriding get method of a variable, then you can access it's value through this get method. Thus, why bother with test::get (which is totally different method, by the way, all you are doing is trying to access char from string), when you can just access variable by it's name?

What is the purpose of Unit-returning in functions

From the Kotlin documentation:
If a function does not return any useful value, its return type is Unit. Unit is a type with only one value — Unit.VALUE. This value does not have to be returned explicitly:
fun printHello(name : String?) : Unit {
if (name != null)
print("Hello, $name!")
else
print("Hi there!")
// We don't need to write 'return Unit.VALUE' or 'return', although we could
}
What is the purpose of Unit-returning in functions? Why is VALUE there? What is this VALUE?
The purpose is the same as C's or Java's void. Only Unit is a proper type, so it can be passed as a generic argument etc.
Why we don't call it "Void": because the word "void" means "nothing", and there's another type, Nothing, that means just "no value at all", i.e. the computation did not complete normally (looped forever or threw an exception). We could not afford the clash of meanings.
Why Unit has a value (i.e. is not the same as Nothing): because generic code can work smoothly then. If you pass Unit for a generic parameter T, the code written for any T will expect an object, and there must be an object, the sole value of Unit.
How to access that value of Unit: since it's a singleton object, just say Unit
The main reason why Unit exists is because of Generic reasons.
Let's use the example from the Kotlin docs.
class Box<T>(t: T) {
var value = t
}
We can have
var box = Box(Unit)
This is why Unit returns a value so the Kotlin can infer it from the type passed into class initialization. Of course, you could also explicitly write it like this,
var box = Box<Unit>(Unit)
but all the same, it must have a return value.
Now, the void keyword in Java in Kotlin is Nothing. Nothing is the last but one type in the type hierarchy in Kotlin with the last one being Nothing? (Nullable Nothing). This does not return any value at all. Because it doesn't return any value at all, we can't pass it as a type in the above code.
var box = Box(Nothing) //This will return an Error
UNIT actually contains valuable information, it basically just means "DONE". It just returns the information to the caller, that the method has been finished. This is a real piece of information so it can be seen as the return value of a method.