`let` inside `let` in Kotlin: how to access the first `it` - kotlin

I have one let inside another one
someMethodCall()?.let{
// ....
// some code here
// ....
val resultCall = it
someMethod2Call()?.let {
// ...
val myVariable = it + resultCall
// ...
}
}
Is it possible in Kotlin inside the second let get access to it of first let and avoid using resultCall variable?

it is a default name for the lambda argument. it is convenient for short lambdas, but you should not use it for longer lambdas. For longer lambdas make the code more readable by specifying an explicit argument name:
someMethodCall()?.let {
resultCall ->
// ... some code that uses "resultCall" instead of "it" ...
}
Use different names to avoid shadowing of the variable in the inner block as in your example:
someMethodCall()?.let {
resultCall ->
// ... some code here ...
someMethod2Call()?.let {
resultCall2 ->
// ...
val myVariable = resultCall2 + resultCall
// ...
}

No it's not possible and you should definitely use explicit names for the parameters in such use cases:
someMethodCall()?.let{ v1->
// ....
// some code here
// ....
someMethod2Call()?.let { v2->
}
}

It helps if you name your variables.
someMethodCall()?.let { resultCall ->
// ....
// some code here
// ....
someMethod2Call()?.let { otherResult ->
// ...
val myVariable = resultCall + otherResult
// ...
}
}

you can use this way
someMethodCall()?.let{ nameOne ->
// ....
// some code here
// ....
val resultCall = nameOne
someMethod2Call()?.let { -> nameTwo
// ...
val myVariable = nameTwo + resultCall
// ...
}
}

Related

Kotlin Reflection on Object Expression

I have a top level kotlin object with various constants declared in it. How can I iterate and reflect on those properties/fields?
object Foobar {
val MEANINGFUL_CONSTANT = SomeClass(...)
#JvmStatic
val getConstants: List<SomeClass>
get() {
val props = Foobar::class.staticProperties
return props.mapNotNull { property ->
val p = property.get()
if (p is SomeClass) {
p
} else {
null
}
}
}
}
No matter what I put in for Foobar::class.staticProperties, I get an empty list back. How do I properly reflect on Foobar?
According to the doc of staticProperties
Only properties representing static fields of Java classes are considered static.
That is why staticProperties on Foobar isn't returning anything.
You can use memberProperties and have a condition to match the KType of SomeClass as below. Maybe that helps.
val getConstants: List<Any>
get() {
val props = Foobar::class.memberProperties
val someClassType = SomeClass::class.createType()
return props.mapNotNull { property ->
if (property.returnType == someClassType) {
property.getter.call(this)
} else {
null
}
}
}

ktor plugins: require configuration values

I was wondering if there is a way to require configuration parameters when making custom plugins? My current hack around is to catch it at runtime
class PluginConfiguration {
var someConfig: String? = null
}
val MyPlugin =
createApplicationPlugin(name = "MyPlugin", createConfiguration = ::PluginConfiguration) {
val someConfig = pluginConfig.someConfig
pluginConfig.apply {
if (someConfig == null) { // catch here
throw java.lang.Exception("Must pass in someConfig")
}
onCallReceive { call ->
// do stuff
}
}
}
but it would be nice if there was a way for the compiler to catch.
My use case for not wanting defaults is that I want to pass in expensive objects that are managed with dependency injection
I think it's not possible with PluginConfiguration API.
But there should be no problem in converting MyPlugin to a function, which will require a parameter to be specified:
fun MyPlugin(someRequiredConfig: String) =
createApplicationPlugin(name = "MyPlugin", createConfiguration = ::PluginConfiguration) {
val someConfig = someRequiredConfig
pluginConfig.apply {
onCallReceive { call ->
// do stuff
}
}
}
// ...
install(MyPlugin("config"))

[Kotlin][Best Practice] How to pass receiver object in parameter function's parameter in Kotlin

I have below code:
internal data class DataClass(
val name: String
)
internal fun DataClass.defineService() {
//Some code
val config = this
return SomeOtherClassB.someAPI() { () ->
createService(config)
}
}
internal fun SomeOtherClassA.createService(
config: DataClass
){
//Some code
}
What's the best way to pass DataClass from defineService() to createService()? I don't want to assign val config = this, doesn't feel right.
You can skip the intermediate variable and put createService(this#defineService). This allows you to specify the this of the scope of defineService.
What's the best way to pass DataClass from defineService() to createService()?
Use a qualified this statement:
internal fun DataClass.defineService() {
//Some code
return SomeOtherClassB.someAPI() { () ->
createService(this#defineService)
}
}

Kotlin: How to get a type of a method parameter

I know I can get the type of a method parameter by using "Method#parameters#name".
However, my parameters are all the subclass of A and I dont want to get the type A. I want to get the subclass name.
if (checkMethod(i)) {
val type = i.parameters[0].simpleName
if (!functions.containsKey(type)) {
functions[type] = HashMap()
}
if (!functions[type]?.containsKey(identifier)!!) {
functions[type]?.put(identifier, ArrayList())
}
functions[type]?.get(identifier)?.add(i)
}
Final Solution:
private fun analysis(clazz: KClass<EventHandler>, identifier: String) {
clazz.members.forEach {
if(it is KFunction) {
if(checkMethod(it)) {
val type = methodEventType(it)
if(!invokeMethods.containsKey(type)) invokeMethods[type] = HashMap()
if(!invokeMethods[type]!!.containsKey(identifier)) invokeMethods[type]!![identifier] = ArrayList()
invokeMethods[type]!![identifier]!!.add(it.javaMethod)
}
}
}
}
private fun checkMethod(method: KFunction<*>): Boolean {
method.annotations.forEach {
if(it is EventSubscriber) {
val type = method.parameters[1].type.classifier
if(type is KClass<*>) {
if(method.parameters.size == 2 && type.superclasses.contains(Event::class)) {
return true
}
}
}
}
return false
}
And notice here. I dont know why the method`s first parameter is allways a instance of its class. So the real parameter is start from 1 instead of 0.
Maybe you'll find this example useful (works with kotlin-reflect:1.4.21)
import kotlin.reflect.full.createType
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.jvm.reflect
open class A
val aType = A::class.createType()
class B: A()
class C: A()
val foo = { b: B, c: C ->
println(b)
println(c)
}
println(foo.reflect()!!.parameters[0].type.classifier == B::class) // true
println(foo.reflect()!!.parameters[1].type.classifier == C::class) // true
println(foo.reflect()!!.parameters[0].type.isSubtypeOf(aType)) // true
To get all subclasses
println((foo.reflect()!!.parameters[0].type.classifier as KClass<*>).allSuperclasses.contains(A::class)) // true
Try this to get the class of the first parameter:
i.parameters[0]::class.java

Syntax of secondary constructors in Kotlin

I've got this code-snippet. It shall demonstrate the order, in which constructors are executed:
fun main(args: Array<String>) {
Sample("T","U")
}
class Sample(private var s : String) {
constructor(t: String, u: String) : this(t) { // I don't get what "this(t)" is!
this.s += u
}
init {
s += "B"
}
}
What's the ": this(t)" in the declaration of the secondary constructor?
That isn't the return-type? Isn't it?
In this particular case this is a keyword that delegates to the primary constructor. It is mandatory in Kotlin when your class has several ones.
The Java equivalent would be:
class Simple {
private String s;
public Simple(String s) { // Here is your primary constructor
this.s = s;
}
public Simple(String t, String u) { // Here is your secondary constructor
this(t);
this.s += u;
}
{
s += "B"; // Here is the init block
}
}
With
this(t)
you call the primary constructor and passes t as an argument for s.
Instead you could even write something like this:
this(s = "a")
Then you set s to "a".
So the order is: Primary constructor, init, secondary constructor. For more detail: https://kotlinlang.org/docs/reference/classes.html
In addition to the answers. This is a required invocation to the default primary constructor:
class Sample(private var s: String) { }
Like in Java:
public Sample(String s) {
}
public Sample(String t, String u) {
this(t); // invoke constructor Sample(String s)
}
To avoid this invocation, you can write like this:
class Sample {
private var s = ""
constructor(t: String) {
s = ...
}
constructor(t: String, u: String) {
s = ...
}
}