kotlin get static type of a class property - kotlin

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.

Related

Kotlin: does it make sense a property with private get and public set?

I am new to Kotlin, and I have been experimenting with the language. In Kotlin in Action, it says the following:
The accessor’s visibility by default is the same as the property’s. But you can change
this if you need to, by putting a visibility modifier before the get or set keyword.
I have tried to create a property that has a private getter and a public setter, as follows:
class BackingField {
var aProperty = 1
private get
set(value) {
field = value + 1
}
}
However, IntelliJ is suggesting me to remove the private modifier before get. Is is possible to have a public property with a private getter and a public setter? If so, what are some common applications of such entity? If not, could we conclude that what is stated in the book is partially wrong?
The book is not wrong per se. Because you can actually change the visibility on both the get and set but the set can't be more visible than the get according to this question:
Private getter and public setter for a Kotlin property
Remember that books and IDEs offer recomendations and not good design based on what you do.
The set can't be more visible than the get, as other said, but then remember that properties and backing fields is just an abstraction. You can have no backing field and declare your interface setter and getter methods with the access restrictions you wish for.
Given this use case, it's obvious that you have special requirements. I.e. the data is not just set, but also incremented by 1. So your external interface would probably have another name for it as well.
Having the syntac object.field = x invoke a setter function is suspect as well, cause the syntax implies no function invocation, as in java or C/C++ structs. it can bite you horribly and make you miss the fact that the assignment invokes a setter somewhere in your code - I would consider it bad design.
The feature of properties and getters/setters works mostly if you are working with data objects and pokos (plain old kotlin objects) only. It's very good for those cases, and can save you time, but once you stray off into more complex scenarios, as you are doing, it's weakness will begin to show.
In this case you don't need a setter, because the class will have access to it privately. The getter though, is something you have to define, and perhaps give a more apropriate name, like setAndIncrement.
class BackingField {
private var aProperty = 1
fun setAProperty(value:Int) { aProperty=value+1}
private fun getAProperty():Int { return aProperty }
fun print() {println(aProperty)}
}
fun main() {
var f = BackingField()
f.print()
f.setAProperty(10)
f.print()
println(f.aProperty) // Won't compile
}

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

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?

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?

Should we avoid naming a function same as an existing class in Kotlin? Why?

Kotlin allows to name a function same as an existing class, e.g. HashSet with initializer function could be implemented like this:
fun <T> HashSet(n : Int, fn: (Int) -> T) = HashSet<T>(n).apply {
repeat(n) {
add(fn(it))
}
}
When used, it looks like a normal HashSet constructor:
var real = HashSet<String>()
var fake = HashSet(5) { "Element $it" }
Should this be avoided or encouraged and why?
UPD
In the updated coding conventions, there's a section on this topic:
Factory functions
If you declare a factory function for a class, avoid giving it the same name as the class itself. Prefer using a distinct name making it clear why the behavior of the factory function is special. Only if there is really no special semantics, you can use the same name as the class.
Example:
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}
The motivation I described below, though, seems to still hold.
As said in documentation about the naming style:
If in doubt default to the Java Coding Conventions such as:
methods and properties start with lower case
One strong reason to avoid naming a function same to a class is that it might confuse a developer who will use it later, because, contrary to their expectations:
the function won't be available for super constructor call (if the class is open)
it won't be visible as a constructor through reflection
it won't be usable as a constructor in Java code (new HashSet(n, it -> "Element " + it) is an error)
if you want to change the implementation later and return some subclass instance instead, it will get even more confusing that HashSet(n) { "Element $it" } will construct not a HashSet but, for example, a LinkedHashSet
It's better to show it explicitly that it's a factory function, not a constructor, to avoid this confusion.
Naming a function same to a class is generally avoided in stdlib, too. Given SomeClass, in stdlib a preferred naming style for factory functions is someClassOf, someClassBy or whatever explains the semantics of the function best. The examples:
generateSequence { ... } and sequenceOf(...)
lazy { ... } and lazyOf(...)
compareBy { ... }
listOf(...), setOf(...), mapOf(...)
So, one should definitely have strong reason to have a function mimic a constructor.
Instead, a function's name might tell a user more (even everything) about its usage.
I agree with +hotkey. It's probably best to avoid confusion in this case.
If it's only used internally and all the other devs (if any) are okay with it, though, I'd say to go for it. Python acknowledges that idea and I love it. Heck, they go both ways, being okay with you naming a class in function case, too, if it feels more like it's acting like a function. But, Python doesn't have to deal with Java interop, so definitely don't do it for public code.