ArunM
ArunM

Reputation: 2314

kotlin access property of anonymous object

How do I access the property word of the object of the anonymous object

 fun main(args: Array<String>) {

        val sentence = "this is a nice sentence"

        val wordLengths: List<Any> = sentence.split(' ').map {
            object {
                val length = it.length
                val word = it
            }
        }

        wordLengths.forEach { it:Any -> println(it) }
    }

Upvotes: 2

Views: 2647

Answers (2)

gidds
gidds

Reputation: 18567

This can be made to work as intended — but it's probably not a good approach.

The immediate issue is that the code specifies the type of wordLengths as List<Any>Any is the top type*; every type is a subtype of it, and so you can only safely access things that every type has (such as the toString() method).

However, you don't need to specify the type; you can leave that to Kotlin's type inference.  If you do, it infers the type that you've defined with the object keyword.  That type is anonymous — you can't write down its name — but Kotlin knows about it, and can access its fields:

fun main() {
    val sentence = "this is a nice sentence"

    val wordLengths = sentence.split(' ').map {
        object {
            val length = it.length
            val word = it
        }
    }

    wordLengths.forEach{ println(it.word) }
}

That said, it's a bit awkward and fragile.  You'd be better off defining a class for the type.  In fact, that's shorter overall:

fun main2() {
    val sentence = "this is a nice sentence"

    class Word(val length: Int, val word: String)

    val wordLengths = sentence.split(' ').map{ Word(it.length, it) }

    wordLengths.forEach { println(it.word) }
}

(In practice, you'd probably want to use the new class elsewhere, and move it outside the method.  But Kotlin lets you define local classes if you need to.)

———

(* Actually, the top type is nullable Any: Any?.  But I'm ignoring nullability as it's not relevant to this.)

Upvotes: 1

Slaw
Slaw

Reputation: 45806

You are explicitly declaring wordLengths to be List<Any>, and Any doesn't have a word or length property. You should let Kotlin infer the type from map.

fun main() {
    val sentence = "This is a nice sentence"

    val wordLengths = sentence.split(' ').map {
        object {
            val word = it
            val length = it.length
        }
    }

    wordLengths.forEach {
        println("[${it.length}] ${it.word}")
    }
}

If you plan on needing this object outside of the method then you should create the necessary class or use an existing class (e.g. Pair or String itself). See Object expressions:

Note that anonymous objects can be used as types only in local and private declarations. If you use an anonymous object as a return type of a public function or the type of a public property, the actual type of that function or property will be the declared supertype of the anonymous object, or Any if you didn't declare any supertype. Members added in the anonymous object will not be accessible.

Upvotes: 6

Related Questions