Dick Lucas
Dick Lucas

Reputation: 12639

Alternative to function overloads

The below code

fun getValue(): Int {
   return 42
}

fun getValue(): String {
   return "Foo"
}

gives the following error:

Conflicting overloads: local final fun getValue(): String defined in main, local final fun getValue(): Int defined in main.

Is there any way to get around this without renaming one of the functions?

Upvotes: 0

Views: 2606

Answers (4)

s1m0nw1
s1m0nw1

Reputation: 82007

How should the client specify which value he actually wants to get out of an instance of your class? These method names are ambiguous.

Look at the method signatures, only the return types differ, which is insufficient.

The rules for overloaded methods for Java also apply to Kotlin:

Overloaded methods are differentiated by the number and the type of the arguments passed into the method.

In your case, just give appropriate distinguishable names. You could also simply make those values properties if your class, no need to explicitly define default getters.

Upvotes: 1

Willi Mentzel
Willi Mentzel

Reputation: 29864

Short answer: No.

Long anser: A function signature consists of the name of that function and its parameter list.

Since the return type does not belong to the signature the compiler can not distinguish which function to use when you call:

val v = getValue() // should v be inferred to Int or String?

Not even specifying the return type explicitely solves the problem:

val v: Int = getValue() 

because getValue() is evaluated first without "knowing" where the return value will be assigned.

So, the best option you have is to choose a different name for one of the functions.

Upvotes: 2

msrd0
msrd0

Reputation: 8390

First of all, writing explicit getters in Kotlin is discouraged and it is suggested to use the following instead:

val value : Int get() = 42
val value : String get() = "Foo"

However, this still doesn't solve your problem. Since you did not give us any information why you need a declaration like this I can only give you some suggestions:

  1. Find a more meaningful name for both variables other than value. For example:

    val intValue get() = 42 // note that you can omit :Int in this case
    val textValue get() = "Foo"
    
  2. If both values are bound together, you can use a Pair:

    val value get() = 42 to "Foo"
    

    Now, you can access the two values via value.first and value.second. Note that to is an infix function that creates a Pair, so the above is equivalent to the more verbose notation

    val value : Pair<Int, String> get() = Pair(42, "Foo")
    
  3. If value is something that's worth storing in its own object rather than using a Pair, you could create your own data class for it:

    data class MyData(val intVal : Int, val textVal : Text)
    val value get() = MyData(42, "Foo")
    

With solutions 2 and 3 it will be possible to use a destructuring declaration, like this:

val (intVal, textVal) = value

Upvotes: 2

Rene
Rene

Reputation: 6258

inline fun <reified T> getValue(): T =
        when (T::class) {
            Int::class -> 42 as T
            String::class -> "foo" as T
            else -> throw IllegalArgumentException()
        }

You could use a generic inline function with a reified type parameter. The given code block is inlined on each invocation.

The drawback is that the compiler can't check for wrong type parameters. You will get an IllegalArgumentException.

Upvotes: 2

Related Questions