How to get names and values of method's parameters? - kotlin

Is there possibility to get names of method's parameters inside method code? Can anyone show example of it?
I found only this solution at this time, but dislike it..:
class Greeter() {
fun greet(name: String) {
val c = Greeter::class;
for (m in c.memberFunctions) {
if (m.name == "greet") {
val p = m.parameters
println(p.toString())
}
}
println("Hello, ${name}");
}
}
fun main(args: Array<String>) {
Greeter().greet("UserName")
}
update: i found another solution, but now i have one more question:
How to get pairs of ParamName, ParamValue at function greet?
class Greeter() {
fun greet(name: String) {
val p = Greeter::greet.parameters
println(p.toString())
println("Hello, ${name}");
}
}
fun main(args: Array<String>) {
Greeter().greet("UserName")
}

Parameter names are available through the KParameter.name property:
class Greeter() {
fun greet(name: String) {
val p = Greeter::greet.parameters
println("Hello, ${p[0].name}")
}
}
Parameter values, on the other hand, cannot be obtained reflectively easily on JVM.

Related

Kotlin: Programing is printing kotlin.unit

My Kotlin Class will run but it prints out the words: kotlin.Unit. What do I need to change?
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack())
}
class Duck() {
fun quack () {
println("Quack, Quack, Quack")
}
}
It is printing that because you are printing the return type of a function that does not return any value. If you are familiar with other languages it is the same as having a void return type.
In kotlin a funtion without a return type returns a unit type, and so when you print the return value of Duck::quack you are printing the string value of a Unit value.
The simplest solution is to not print the return value of Duck::quack; however, if you would like the prinlt to print the return of Duck::quak, it needs to return a useful value. For examle:
class Duck() {
fun quack(): String {
return "Quack, Quack, Quack"
}
}
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack())
}
or more idiomatically:
class Duck() {
val quack: String = "Quack, Quack. Quack"
}
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack)
}
It's anought to call
myDuck.quack()
wich has already println inside. Calling println(myDuck.quack()) prints type of myDuck.quack because it doesn't return any value.
1.prints "kotlin.Unit" if you don't specify the type
fun main(args: Array<String>) {
var myDuck = Duck()
println(myDuck.quack())
}
class Duck():String {
fun quack () {
return "Quack, Quack, Quack"
}
}
Also as shortly:
fun main() {
println(Duck.quack())
}
class Duck() {
fun quack () = "Quack, Quack, Quack"
}

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}

How to pass is operator parameter through function in Kotlin

val k = " asdfasdf "
fun test() {
if(k is String) {
// Do something
}
}
So, how do I pass that String through the function calls
eg:
fun test(xxxx) {
if(k is xxxx) {
// do something
}
}
Like this:
inline fun <reified T> testType(k: Any) {
if(k is T) {
println("is a ${T::class.simpleName}")
} else {
println("is not a ${T::class.simpleName}")
}
}
Call it like this:
test<String>("Hello") // is a String
test<String>(1) // is no String
Here some further reading.
There are two possibilities, depending on your needs.
1. Use inline and a reified type parameter
You can use the reified keyword on the type parameter in combination with an inline function:
inline fun <reified T> test(k: Any) {
if (k is T) {
println("k is a T!")
}
}
See the documentation on reified.
2. Use KClass<T>
If you do not want to or cannot make your function inline you can use a KClass parameter:
fun <T : Any> test(k: Any, type: KClass<T>) {
if (type.isInstance(k)) {
println("k is a T!")
}
}
You can either use a predicate, e.g.:
fun testIt(predicate: (Any?) -> Boolean) {
if (predicate(k)) {
println("matches!")
} else println("nope")
}
and call it as follows:
testIt { it is String }
testIt { it is Int }
Or you can use a reified type:
inline fun <reified T> testIt() {
when (k) {
is T -> println("matches!")
else -> println("nope")
}
}
and call it like:
testIt<String>()
testIt<Int>()
For simplicity I kept your current variable inside the testIt-method... you may want to redesign that ;-)
I basically assumed a member variable as follows: var k : Any? = null
inline fun <reified T> isType(obj: Any): Boolean {
return obj is T
}
fun main(args: Array<String>) {
val test = "This is a String"
if (isType<String>(test)) {
println("Success")
} else {
println("Failure")
}
}

Kotlin - get name from lambda expression

I want to get the name of a parameter passed into a lambda expression in Kotlin. In C# I would use an Expression<Func<T, ...>> to get the parameter name, but I'm not sure whether this is possible in Kotlin
import java.util.*
fun main(args: Array<String>) {
val foo = Foo<Model>()
foo.bar { it.age }
// Should print "age"
}
data class Model(val id: UUID, val name: String, val age: Int)
class Foo<T> {
fun bar(expression: (x: T) -> Any) {
println(/*The name of the parameter*/)
}
}
Is this possible in Kotlin?
If you want to pass around properties and print their names, you can do it by using KProperty:
fun main(args: Array<String>) {
val foo = Foo<Model>()
foo.bar(Model::age)
}
class Foo<T> {
fun bar(p: KProperty<*>) {
println(p.name)
}
}

Is possible to change dynamically method for an instance?

I wrote down this code:
open class Test(){
override fun toString(): String {
return "This is test!"
}
}
fun createTestX(): Test {
return object : Test() {
override fun toString(): String {
return super.toString() + "XXX"
}
}
}
fun main(args: Array<String>) {
val x = createTestX()
println(x)
}
It works as expected but I am curious whether is it possible to change method of instance using for example lambda like this:
val x = Test()
x.toString = () -> x.toString() + "XXX"
What you can do
class C {
var example:()->String = this::toString
}
fun main(args: Array<String>) {
val c = C()
println(c.example())
c.example = {"ABCDEF"}
println(c.example())
}
Limitations
Although this works for swapping fields, you cannot use it to override methods. This can be worked around by defining the method to invoke the field.
class C {
var example:()->String = {"ABC"}
override fun toString() = example()
}
fun main(args: Array<String>) {
val c = C()
println(c)
c.example = {"DEF"}
println(c)
}
Output:
ABC
DEF