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?

1
  • 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. Commented Oct 3, 2019 at 8:28

5 Answers 5

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)

Sign up to request clarification or add additional context in comments.

5 Comments

yes, but since i want everything to be dynamic and we don't know what is its data type, i think it will be better if we use something dynamic class just like in JS
A any map would be better in that case
Or any? If you want nullables
@MatiusNugrohoAryanto I've made some edits, check my answer and also the one above as he might have figured out what you actually meant
can you give an example with my snippet?
6

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

Comments

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.

Comments

-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
    }
}

2 Comments

it seems closest approach, how to know where is data inherit from, or what kind of instance is data
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
-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)

1 Comment

This applies only to local and private scope

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.