Proposal: allow shorthand reflective property access when extension receiver is a KClass

Right now, it’s possible to access properties reflectively from outside the class by prepending its name, like MyClass::someProp. You can also access the property within the class definition, simply as ::someProp. My proposal is to make the shorthand version possible when the current extension or context receiver is a KClass, like so:

fun KClass<MyClass>.foo() {
    ::someProp // do something with it
}

The use case is builders that are abstracted away from any particular instance of MyClass, but still operate on a given instance’s properties. For example, I’m working on an animation DSL that I’d like to look as follows:

private val animOpen = buildAnimation<GuiMenu>("open", duration=400.milliseconds) {
    motion(by={ it.pow(0.5) }) {
        ::lblTitle { ::foregroundColor[Color32.CLEAR, foregroundColor] }
        ::btnResume { ::x[0.0, 500.0] }
    }
    atEnd { btnResume.acquireFocus() }
}

With the desired syntax, animations could live separately from specific GUI instances and be reused between them, or designed for classes which the user isn’t the author. But right now, accessing properties in this way is impossible (i.e. results in compilation error), even though theoretically all the information is available to make this happen. So I either have to settle for relatively clunky syntax that’s also error prone, or drop reusability entirely, tying animations to specific instances despite the overhead.

Current possible (clunky) syntax, that doesn’t produce compile error even if class IDs are wrong:

private val animOpen = buildAnimation<GuiMenu>("open", duration=400.milliseconds) {
    motion(by={ it.pow(0.5) }) {
        GuiMenu::lblTitle { LabelComponent::foregroundColor[Color32.CLEAR, foregroundColor] }
        GuiMenu::btnResume { ButtonComponent::x[0.0, 500.0] }
    }
    atEnd { btnResume.acquireFocus() }
}

Thoughts, concerns, ideas? I’d love it if there were an even better way of designing this DSL.

4 Likes