2

In javascript we can do something like this

function putritanjungsari(data){
 console.log(data.name)
}

let data = {
 name:"putri",
 div:"m4th"
}
putritanjungsari(data)

In kotlin, i'am creating a function that accept an object as parameter then read it's properties later, how to do that in kotlin that targeting JVM?

  • While this is possible (e.g. using a Map), you should be aware that it has many disadvantages: it's likely to be slower and take more memory than standard properties; you lose lots of compile-time checking, making several types of bug much more likely; users/callers of your code won't be able to tell what properties are available; inheritance is much harder, as is customising getters/setters, quality, and comparison…  Sometimes it's needed, but very rarely IME — if you're coming from a dynamic language, please ensure you're not just doing so because it's more familiar. – gidds Oct 03 '19 at 08:28

5 Answers5

6

If I understood your question correct, you are trying to have a variable that associates keys with some value or undefined(null in kt) if none are found. You are searching for a Map If you don't know what types you want, you can make a map of type Any? So

Map<String, Any?>

Which is also nullable

Map<String, Any>

If you don't want nullables

Your code for example:

fun putritanjungsari(data: Map<String, Any?>){
print(data["name"]) 
}

val data: Map<String, Any?> =mapOf(        
"name" to "putri",
"div" to "m4th" 
)
putritanjungsari(data)

Note that you can't add new keys or edit any data here, the default map is immutable. There is MutableMap (which is implemented the same, only it has a method to put new data)

DownloadPizza
  • 3,307
  • 1
  • 12
  • 27
4

You can apply the property design pattern to solve your problem.

Here is its implementation in Kotlin:

interface DynamicProperty<T> {
    fun cast(value: Any?): T
    fun default(): T

    companion object {
        inline fun <reified T> fromDefaultSupplier(crossinline default: () -> T) =
            object : DynamicProperty<T> {
                override fun cast(value: Any?): T = value as T
                override fun default(): T = default()
            }

        inline operator fun <reified T> invoke(default: T) = fromDefaultSupplier { default }

        inline fun <reified T> required() = fromDefaultSupplier<T> {
            throw IllegalStateException("DynamicProperty isn't initialized")
        }

        inline fun <reified T> nullable() = DynamicProperty<T?>(null)
    }
}

operator fun <T> DynamicProperty<T>.invoke(value: T) = DynamicPropertyValue(this, value)

data class DynamicPropertyValue<T>(val property: DynamicProperty<T>, val value: T)

class DynamicObject(vararg properties: DynamicPropertyValue<*>) {
    private val properties = HashMap<DynamicProperty<*>, Any?>().apply {
        properties.forEach { put(it.property, it.value) }
    }

    operator fun <T> get(property: DynamicProperty<T>) =
        if (properties.containsKey(property)) property.cast(properties[property])
        else property.default()

    operator fun <T> set(property: DynamicProperty<T>, value: T) = properties.put(property, value)
    operator fun <T> DynamicProperty<T>.minus(value: T) = set(this, value)
}

fun dynamicObj(init: DynamicObject.() -> Unit) = DynamicObject().apply(init)

You can define your properties these ways:

val NAME = DynamicProperty.required<String>() // throws exceptions on usage before initialization
val DIV = DynamicProperty.nullable<String>() // has nullable type String?
val IS_ENABLED = DynamicProperty(true) // true by default

Now you can use them:

fun printObjName(obj: DynamicObject) {
    println(obj[NAME])
}

val data = dynamicObj {
    NAME - "putri"
    DIV - "m4th"
}
printObjName(data)

// throws exception because name isn't initialized
printObjName(DynamicObject(DIV("m4th"), IS_ENABLED(false)))

Reasons to use DynamicObject instead of Map<String, Any?>:

  1. Type-safety (NAME - 3 and NAME(true) will not compile)
  2. No casting is required on properties usage
  3. You can define what the program should do when a property isn't initialized
IlyaMuravjov
  • 2,352
  • 1
  • 9
  • 27
0

Kotlin is statically typed language, so it required a param type to be precisely defined or unambiguously inferred (Groovy, for instance, addresses the case by at least two ways). But for JS interoperability Kotlin offers dynamic type.

Meanwhile, in your particular case you can type data structure to kt's Map and do not argue with strict typing.

lotor
  • 1,060
  • 7
  • 18
-1

You have to use Any and after that, you have to cast your object, like this

private fun putritanjungsari(data : Any){
    if(data is Mydata){
        var data =  data as? Mydata
        data.name
    }
}
Akshay Raiyani
  • 1,243
  • 9
  • 21
  • 1
    it seems closest approach, how to know where is data inherit from, or what kind of instance is data – Matius Nugroho Aryanto Oct 03 '19 at 07:29
  • you are calling this function using different object then you know that I am calling this function using that all object so you can differentiation that all objects and find all member of that object – Akshay Raiyani Oct 03 '19 at 07:51
-1

Just for the sake of inspiration. In Kotlin, you can create ad hoc objects:

val adHoc = object {
    var x = 1
    var y = 2
}
println(adHoc.x + adHoc.y)
skrymir1
  • 557
  • 6
  • 5