Is it possible to declare a variable with two types in Kotlin, like val x: Int or String?

Ho, I am still wondering if it is possible to do this, for example, that a property can be type Int or String, and that its value can be assigned from either type, and used according to the assigned type.

Declaration:
val name : String or Int

Asignation:
name = R.string.demo // Use Int
name = "Kotlin" // Use string

I was wondering if it is possible to do something similar, I appreciate your answers in advance.

Kotlin doesn’t have union types so can’t do (using pipe from typescript like syntax) var name: Int | String = 5.

You could use an Either class which might allow var name = Either<Int, String>(5) or something like that.

What’s your use case? If you’re making you’re own classes you may want to consider if a sealed class/interface is appropriate. If you’re really wanting a union of Int and String it may be a code smell that there’s a better design.

3 Likes

Thank you very much for your reply.

My use case is the following:
I am creating a utility library for android, in some cases I need to receive text values to display in views. To facilitate the process, I want to admit a string directly, which is the one that it would show to the user, but I also want the possibility of giving me the ID of the resource (which is integer) to obtain the string of the resources within the library.

For Example:

class DemoView {
     var name: Any = "Example"
}

In this case, the user can assign as a string, so I use it directly, but if I assign it as Int I get the value of the resources:

fun show() {
    val finalName = when(name){
        is String -> name
        else -> context.getString(name)
    }
}

The downside is that Any will accept any other type of data, and I would like to restrict it to String and Int.

Another approach that I have thought of is the following

class DemoView {

private var name: Any = "Example"

fun setName(value: String) {
   name = value
}

fun setName(value: Int) {
    name = context.getString(value)
}
}

I don’t know if these approaches are the best, or if it can be done in a better way.

I think you’re on the right lines with your last approach.⠀You just need to fix it by giving your private name field the type String; after all, your setters all set it to a string, so you know it must contain a string — and if you give it that type, the compiler will know too.

Having a property with one type, and extra setter-type methods that convert from other types, is a fairly common pattern.

Another advantage is that if it can’t convert (e.g. if there’s no resource for a number), you can throw an exception (or whatever) in that setter, where it should be much easier to trace the cause.

2 Likes

Thank you.