In Kotlin, can a property of a data class have multiple types? For example:
val CurrentValue: Double?|String
or
val CurrentValue: String|Array?
I cannot find it in the documentation.
Union types are not a thing in Kotlin.
You may use a sealed class instead.
sealed class CurrentValue<T>(val value: T) {
class TextualValue(value: String) : CurrentValue<String>(value)
class NumericValue(value: Double) : CurrentValue<Double>(value)
}
Which then you can use exhaustive when expressions (similar to switch in other languages) in order to access the value in a type-safe manner:
fun doSomething(value: CurrentValue<*>) {
when(value) {
is TextualValue -> value.value // is recognised as a String
is NumericValue -> value.value // is recognised as a Double
}
}
If creating a type is way too much for you then you can perform a when statement and treat a parameter based on it's type and perhaps normalize it:
fun parseValue(value: Any?): Double? = when(value){
is Double -> value
is String -> value.toDoubleOrNull()
is Int -> value.toDouble()
else -> null
}
Related
I have a function that returns IMyInterface
fun getValue(type: Types): IMyInterface? {}
But I have to always cast the return type in this way before I can use it:
getValue(Types.TypeInt)?.let { value ->
val usableVale = MyInterfaceAsInt.cast(value)
// more code...
}
MyInterfaceAsInt implements IMyInterface and I have no control over them.
The casting always depend of the input, so
Types.TypeInt -> MyInterfaceAsInt.cast(value)
Types.TypeLong -> MyInterfaceAsLong.cast(value)
...etc
Is there a way to define somthing like fun <T = Types> getValue(type: T) in a way that the return type can be inferred from type ?
I would like to do the casting inside getValue.
It looks like Types.TypesInt/Long/etc. are simply instances of the same type Types, not different types; and in fun <T> getValue(type: T), T has to be a type. So it doesn't seem to be possible.
But I would probably go the other way and define functions like
fun getValueAsInt(): MyInterfaceAsInt? = getValue(Types.TypeInt)?.let { MyInterfaceAsInt.cast(it) }
fun getValueAsLong(): MyInterfaceAsLong? = getValue(Types.TypeLong)?.let { MyInterfaceAsLong.cast(it) }
...
Another alternative which could be useful at least when the type can be inferred:
#Suppress("UNCHECKED_CAST")
inline fun <reified T : MyInterface> getValue(): T? = when(T::class) {
MyInterfaceAsInt::class -> getValue(Types.TypeInt)?.let { MyInterfaceAsInt.cast(it) }
MyInterfaceAsLong::class -> getValue(Types.TypeLong)?.let { MyInterfaceAsLong.cast(it) }
...
} as T
I've the following two classes:
class Volume(var value: Double, unit: Unit) {
var unit: Unit = unit
private set
enum class Unit(symbol: String){
MILLILITER("ml"),
CENTILITER("cl"),
DECILITER("dl"),
LITER("l"),
TEASPOON("tsp"),
TABLESPOON("tbsp"),
FLUIDOUNCE("floz"),
SHOT("jig"),
GILL("gi"),
CUP("cup"),
PINT("pt"),
QUART("qt"),
GALLON("gal")
}
}
class Mass(var value: Double, unit: Unit) {
var unit: Unit = unit
private set
enum class Unit(symbol: String){
GRAM("g"),
DECAGRAM("dag"),
HECTOGRAM("hg"),
KILOGRAM("kg"),
OUNCE("oz"),
POUND("lb")
}
}
I want to create operators for both classes for basic arithmetic operations, for example:
operator fun inc(): Mass {
value++
return this
}
Since both classes will have the same operator logics, i don't want to duplicate this part of the code.
My first idea was that Both classes inherit from a PhysicalQuantity interface which contains the operators. In this case the following code doesn't work, because the IDE expects IPhysicalQuantity as return type but the type is Volume:
interface IPhysicalQuantity() {
var value: Double
var unit: IUnit
operator fun inc(): IPhysicalQuantity {
value++
return this
}
}
fun main() {
var vol = Volume(10.0, Volume.Unit.CENTILITER)
vol++
}
Same issue with abstract super class.
The problem with doing this inside the IPhysicalQuantity interface is that you don't want to return the object as the interface type IPhysicalQuantity from the inc method. Instead, you want to keep its original type (Volume or Mass), so you'd have to use generics there. However, I didn't find a way to do this without complex syntax and an unchecked cast:
interface IPhysicalQuantity<T : IPhysicalQuantity<T>> {
var value: Double
operator fun inc(): T {
value++
return this as T
}
}
class Volume(override var value: Double, unit: Unit): IPhysicalQuantity<Volume>
However, you can do this fairly simply with an extension instead without having to make the interface itself generic, if that works for you:
operator fun <T : IPhysicalQuantity> T.inc(): T {
value++
return this
}
I'm learning Kotlin and I have some trouble with functions.
I'm trying to create something like a functional interface with a generic parameter.
In Java I would create something like this:
#FunctionalInterface
public interface Foo<T extends Bar> {
String something(T arg);
}
Then I can use this somewhere else like this (given that Person extends Bar:
Foo<Person> f = p -> p.toString();
How do you write this with Kotlin?
The first thing I tried was to use type-aliases like this:
typealias Foo<T> = (T) -> String
However, it stopped working when I added the bound to the type parameter:
typealias Foo<T: Bar> = (T) -> String // Error: Bounds are not allowed on type alias parameters
The second approach was to write an interface that extends the function type:
interface Foo<T: Bar> : (T) -> String
However, now I don't know how to instantiate a lambda function from with this. It works when I create class from it like this:
class Something: Foo<Person> {
override fun invoke(p: Person): String {
return p.toString()
}
}
val f = Something()
But this is a big overhead and I'm sure there has to be a better solution.
So how can I define a function signature that can be reused by many functions that supports generic parameters with bounds in kotlin?
Most of the time (always?) it is sufficient to define the type of the lambda in the parameter of the function that receives it.
For example:
open class Bar
class Person: Bar()
var f = { p: Person -> p.toString() }
fun <T : Bar> withFoo(block: (T) -> String) { }
fun <T : Bar> otherFoo(block: (T) -> String) { }
fun main() {
withFoo(f)
otherFoo(f)
}
The same way the Kotlin documentation states:
"since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported."
See https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
I'm attempting to write an invocation handler that uses a map (supplied at runtime) to implement an interface's getters.
This very crudely works. I know the basic types that may be returned, so I'm OK with having a when expression.
I haven't found a way to avoid using the name of the class as the subject of the when expression; is there a better way?
class DynamicInvocationHandler<T>(private val delegate: Map<String, Any>, clzz: Class<T>) : InvocationHandler {
val introspector = Introspector.getBeanInfo(clzz)
val getters = introspector.propertyDescriptors.map { it.readMethod }
override fun invoke(proxy: Any, method: Method, args: Array<Any>?): Any? {
if (method in getters) {
// get the value from the map
val representation = delegate[method.name.substring(3).toLowerCase()]
// TODO need better than name
when (method.returnType.kotlin.simpleName) {
LocalDate::class.simpleName -> {
val result = representation as ArrayList<Int>
return LocalDate.of(result[0], result[1], result[2])
}
// TODO a few other basic types like LocalDateTime
// primitives come as they are
else -> return representation
}
}
return null
}
}
You can use the types instead of the class names in the when statement. After a type is matched, Kotlin smart cast will automatically cast it
Example
val temporal: Any? = LocalDateTime.now()
when (temporal){
is LocalDate -> println("dayOfMonth: ${temporal.dayOfMonth}")
is LocalTime -> println("second: ${temporal.second}")
is LocalDateTime -> println("dayOfMonth: ${temporal.dayOfMonth}, second: ${temporal.second}")
}
when expressions support any type (unlike Java's switch), so you can just use the KClass instance itself:
when (method.returnType.kotlin) {
LocalDate::class -> {
...
}
...
}
I'm trying to build a class that has a property of LocalDate type which has setters that accept different types: LocalDate or String. In case of LocalDate, the value gets assigned directly, in case of String, it gets parsed and then assigned.
In Java, I just need to implement two overloaded setters handling both of above mentioned cases. But I have no idea how to handle that in Kotlin. I have tried this:
class SomeExampleClass(var _date: LocalDate) {
var date = _date
set(value) {
when(value) {
is LocalDate -> value
is String -> LocalDate.parse(value)
}
}
}
It doesn't compile. How can I resolve such a problem?
After some time I returned to the problem of overloaded setters and developed the following solution:
class A(_date: LocalDate) {
var date: Any = _date
set(value) {
field = helperSet(value)
}
get() = field as LocalDate
private fun <T> helperSet(t: T) = when (t) {
is LocalDate -> t
is String -> LocalDate.parse(t)
else -> throw IllegalArgumentException()
}
}
So if you just want to construct it (via constructor), just create a secondary constructor
SomeExampleClass(LocalDate.MAX)
SomeExampleClass("2007-12-03")
class SomeExampleClass(var _date: LocalDate) {
constructor(_date: String) : this(LocalDate.parse(_date))
}