Implementing a container like java's object

Hello,

I need to use something like a union data type which can hold either a string, bool, int or double.
I implemented it like this:

data class ValueContainer(val int:Int?, val bool:Boolean?, val double: Double?,
    val string: String?) {
    var int_value:Int? = null
    var bool_value:Boolean? = null
    var double_value:Double? = null
    var string_value: String? = null

    // but how do I model the return type? it varies from string to int to double to bool
    fun get_value():{
        when {
            int_value != null -> return int_value,
            bool_value != null -> bool_value
        }
    }
}

The best you can do at the moment is to use sealed classes I guess. An another strategy is to use sealed interfaces as markers but this is by no means an elegant solution in bigger projects.

What is your expected behavior for this get_value function, what should it do? You realized already that the Kotlin doesn’t support union types and you decided to use a container object. Now you ask to return the union type again. It feels you got into an infinite recursion :wink:

How do you plan to consume this union value? Whatever solution you use: real union types (not possible in Kotlin), your container object, sealed types, etc., the consumer has to check what is the type and react to it.

Or maybe you actually don’t need a union type, but generics. But it is hard to tell without knowing your use case.

I decided to write a sealed class that has a subtype for every value covered. I try to fix an issue with the inherited get() method.

You can potentially do this:

sealed interface Value<T> {
    val value: T
}

data class StringValue(override val value: String) : Value<String>
data class IntValue(override val value: Int) : Value<Int>

But I’m not sure there is too much benefit of having this base property. After we cast to a specific type, we have access to its props anyway, so we can simply create an entirely separate value prop for each subtype.

1 Like

there is one problem I have: I use the visitor pattern and have a method evaluate() that evaluates nodes of the syntax tree. It returns a ValueContainer object akin to your Value interface.
But it needs to be known in the evaluate method what kind of type it contains because it is a generic method. However, this can only be decided once the node is evaluated. How would you solve this?

sealed interface ValueContainer<T> {
    val value:T
    fun get():T

    class IntContainer(override val value: Int):ValueContainer<Int> {
        override fun get(): Int {
            return value
        }
    }
...
class Interpreter():Visitor() {

    // the generic type needs to be known here but it is determined inside the
    // evaluate method.
    fun evaluate(expr:Expression):ValueContainer {
        return expr.accept(this)
    }
...
```

Why the above code needs to know what is the type of the value? The whole point of generics is to write a code which is not fully aware of types as they are dynamic.

Usually, at some point we need to determine specific types and act accordingly. Then we simply check the type:

fun doSomethingWithValue(value: ValueContainer<*>) {
    when (value) {
        is ValueContainer.IntContainer -> println("Value is integer: ${value.value}")
        is ValueContainer.StringContainer -> println("Value is string: ${value.value}")
    }
}