4

I have a

class Foo { lateinit var property1: String lateinit var property2: Int lateinit var property3: Long } 

Then is it possible to pass a property of the class in a function like this one?

fun bar(fooProperty: FooProperty) { println( when(fooProperty) { Foo.property1 -> "Property1" Foo.property2 -> "Property2" Foo.property3 -> "Property3" } ) } 

This is invalid code however. I was just wondering if that is achievable.

2 Answers 2

9

Yes, this is possible, just use ClassName::propertyName to get a reference to the property and KProperty1<ClassName, *> as the parameter type.

So, a full working example with your example class (changed a bit to make the class compile) would look like:

import kotlin.reflect.KProperty1 class Foo { lateinit var property1: String var property2: Int = 0 var property3: Long = 0 } fun bar(fooProperty: KProperty1<Foo, *>) { println( when(fooProperty) { Foo::property1 -> "Property1" Foo::property2 -> "Property2" Foo::property3 -> "Property3" else -> throw IllegalArgumentException("Not a known property") } ) } fun main() { bar(Foo::property2) } 

This prints

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

Comments

0

There are a few options. The simplest approach is to use a wrapper class (#1); you can even use a sealed class (#2) so that when doesn't require an else branch. The downside of using a wrapper class is that wrapper classes can be far less efficient than using primitive types. That said, primitive types cannot be lateinit and a delegated property would probably be necessary in this use case, so a wrapper class could be a good idea.

The best answer is probably Option #3 - using inline classes. Inline classes should be optimised as if you were using the underlying primitive type, while providing the full benefits of OOP (unlike just using reflection). The downside of this is that they can't be sealed (so they'll require an else branch when using them with when) and that they're experimental.

Note that the code in the questions has a number of issues including missing is and else in the when expression and using lateinit with a primitive type.

Option #1:

class Foo { lateinit var property1: Foo.Property1 lateinit var property2: Foo.Property2 lateinit var property3: Foo.Property3 abstract class FooProperty class Property1(val value:String):FooProperty() class Property2(val value:Int):FooProperty() class Property3(val value:Long):FooProperty() } fun bar(fooProperty: Foo.FooProperty) { println( when(fooProperty) { is Foo.Property1 -> "Property1" is Foo.Property2 -> "Property2" is Foo.Property3 -> "Property3" else -> error("Impossible") } ) } 

Option #2:

class Foo { lateinit var property1: FooProperty1 lateinit var property2: FooProperty2 lateinit var property3: FooProperty3 } sealed class FooProperty class FooProperty1(val value: String) : FooProperty() class FooProperty2(val value: Int) : FooProperty() class FooProperty3(val value: Long) : FooProperty() fun bar(fooProperty: FooProperty) { println( when (fooProperty) { is FooProperty1 -> "Property1" is FooProperty2 -> "Property2" is FooProperty3 -> "Property3" } ) } 

Option #3:

inline class FooProperty1(val value:String) inline class FooProperty2(val value:Int) inline class FooProperty3(val value:Long) class Foo { var property1: FooProperty1 by Delegates.notNull() var property2: FooProperty2 by Delegates.notNull() var property3: FooProperty3 by Delegates.notNull() } fun bar(fooProperty: Any) { println( when(fooProperty) { is FooProperty1 -> "Property1" is FooProperty2 -> "Property2" is FooProperty3 -> "Property3" else -> error("") } ) } 

1 Comment

Thanks for your answer! But I have a few things to point out. All your solutions require me to double define all the properties. And this is not exactly what I wanted. But it's a simple solution, thanks anyway!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.