Understanding extensions

I’m playing around with Kotlin and I recently ran into a strange scenario with extensions. I’m having a hard time understanding why extensions, that are declared inside a class, are unavailable directly unless a with is used. For example:

fun main(args: Array<String>) {
    val john = Person()
    println(john.state.isSingle) // Unresolved reference: isSingle
    println(with(john) { state.isSingle }) // Will need to use this instead
}

class Person(val state: State = State.SINGLE) {   
	val State.isSingle: Boolean
        get() {
            return this == State.SINGLE
        }              
    enum class State {
        SINGLE, MARRIED
    }
}

Furthermore, when an extension is declared as a top level property, direct access to the extension is now possible, i.e:

fun main(args: Array<String>) {
    val john = Person()
    println(john.state.isSingle) // Works
}

class Person(val state: State = State.SINGLE) {  
    enum class State {
        SINGLE, MARRIED
    }
}

val Person.State.isSingle: Boolean
	get() {
    	return this == Person.State.SINGLE
    }

What are the differences between declaring it as top level vs inside another class that makes direct access impossible? If declared inside a class, wouldn’t the extension have access to the instance its inside?

Your first extension is in the scope of the enclosing class and will be resolved in this scope. With with you enter this scope since all methods called inside the with block are resolved against this instance (john) .

From my point of view it doesn’t make much sense to use extension functions/properties like this. You could define a method/property in the enum or in the Person class instead.

You’re right that this doesn’t make much sense. This is a contrived example only to benefit me in learning about Kotlin. I guess i’m confused about the scope here. When I create an instance of Person, wouldn’t the extension be resolved then?

The definition of extension functions inside a class is generally useful when defining a DSL. You don’t really want the dsl extension functions to be in scope outside the dsl context, these extension functions allow that very elegantly.