1
votes

I would like to offer two methods with the same name which can accept optional or non-optional input:

class Formatter {
    fun format(input: Number?) : String? {return number?.toString()}
    fun format(input: Number) : String {return number.toString()}
}

Apparently this is not possible due to JVM limitations:

Platform declaration clash: The following declarations have the same JVM signature (test(Lorg.example.Number;)Ljava/lang/String;):

Is there a readable workaround to achieve the same goal? My current solution is to rename one method (e.g. formatNonNull(input: Number)).

Bonus: My Formatter-class is actually written in Java and looks like this:

class Formatter {
    @Nullable String format(@Nullable Number input) : String {return number != null ? number.toString(): null;}
}

It shall be extended by the non-null variant:

@NonNull String formatNonNull(@NonNull Number input) : String {return number.toString();}

Is there a way to improve this i.e. without introducing a new name (e.g. with kotlin extension)?

1
do you need the 2 alternatives just to have an appropriate nullable or non-nullable return type? If that's the case maybe contracts can help you - user2340612
A contract wouldn't work for this currently. As of now, we can only write contracts that make implications off the return value (which we already have), and the number of times a lamba is to be executed. We would need to be able to specify a contract based on the inputs to a function which we can't do (yet?). - Todd
Even if you can avoid these methods being confusing to the compiler, they're still likely to be confusing to anyone reading the code. And there's a real risk of the 'wrong' method being called, if e.g. a value doesn't get smart-cast when you expect it to. I'd strongly suggest either making the two equivalent -- in which case the non-nullable one isn't needed -- or giving them different names to resolve the ambiguity. - gidds

1 Answers

4
votes

There's a neat hack to fix this on the JVM:

class Formatter {
    fun format(input: Number?) : String? {return number?.toString()}
    @JvmName("-formatNonNull") fun format(input: Number) : String {return number.toString()}
}

The reason this works is that - is a valid identifier character in the JVM bytecode, but not in the Java language. This means that the code will compile and you'll be able to call both methods in Kotlin, but you won't be able to call a method that has - in its name from Java. This also eliminates the name clash since the methods will have different names in bytecode.