Nonexistent compilation error in string expression

A: Right

         n =  (if (true) "" else 'a')                  
         n +=  (if (true) "b"  else "")

B: Wrong:

        n =  (if (true) "" else 'a') +  (if (true) "b"  else "")

Notice that I just have joined the 2 lines of the right option A.
It gives an error in + character (marked with red and underlined red in module tab).
Updated Android Studio 3.4.1 stays blinking when cursor over + in a weird pattern.

Notice that n = 'a' + "b" that concatenates char with string is OK.

You can solve all those problems yourself by checking the types of 'a' and "b" literals.

1 Like

I know that there isn’t smart mix types, but it’s a contradition the compiler accepts the first option and refuses the second one. concatenation between chars and strings is officially accepted in Kotkin.

The compiler accepts since the construct itself is allowed. It infers its type. Guess which one.

Yes, but there is no sense because the same if when separated don’t give an error.
Kotlin Playground also refuses the option A. It’s the bigger error message that I’ve ever seen in Kotlin.

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: @InlineOnly public inline operator fun BigDecimal.plus(other: BigDecimal): BigDecimal defined in kotlin @InlineOnly public inline operator fun BigInteger.plus(other: BigInteger): BigInteger defined in kotlin public operator fun <T> Array<???>.plus(elements: Array<out ???>): Array<???> defined in kotlin.collections public operator fun <T> Array<???>.plus(elements: Collection<???>): Array<???> defined in kotlin.collections public operator fun <T> Array<String>.plus(element: String): Array<String> defined in kotlin.collections public operator fun BooleanArray.plus(element: Boolean): BooleanArray defined in kotlin.collections public operator fun BooleanArray.plus(elements: BooleanArray): BooleanArray defined in kotlin.collections public operator fun BooleanArray.plus(elements: Collection<Boolean>): BooleanArray defined in kotlin.collections public operator fun ByteArray.plus(element: Byte): ByteArray defined in kotlin.collections public operator fun ByteArray.plus(elements: ByteArray): ByteArray defined in kotlin.collections public operator fun ByteArray.plus(elements: Collection<Byte>): ByteArray defined in kotlin.collections @InlineOnly public inline operator fun Char.plus(other: String): String defined in kotlin.text public operator fun CharArray.plus(element: Char): CharArray defined in kotlin.collections public operator fun CharArray.plus(elements: CharArray): CharArray defined in kotlin.collections public operator fun CharArray.plus(elements: Collection<Char>): CharArray defined in kotlin.collections public operator fun DoubleArray.plus(element: Double): DoubleArray defined in kotlin.collections public operator fun DoubleArray.plus(elements: DoubleArray): DoubleArray defined in kotlin.collections public operator fun DoubleArray.plus(elements: Collection<Double>): DoubleArray defined in kotlin.collections public operator fun FloatArray.plus(element: Float): FloatArray defined in kotlin.collections public operator fun FloatArray.plus(elements: FloatArray): FloatArray defined in kotlin.collections public operator fun FloatArray.plus(elements: Collection<Float>): FloatArray defined in kotlin.collections public operator fun IntArray.plus(element: Int): IntArray defined in kotlin.collections public operator fun IntArray.plus(elements: IntArray): IntArray defined in kotlin.collections public operator fun IntArray.plus(elements: Collection<Int>): IntArray defined in kotlin.collections public operator fun LongArray.plus(element: Long): LongArray defined in kotlin.collections public operator fun LongArray.plus(elements: LongArray): LongArray defined in kotlin.collections public operator fun LongArray.plus(elements: Collection<Long>): LongArray defined in kotlin.collections public operator fun ShortArray.plus(element: Short): ShortArray defined in kotlin.collections public operator fun ShortArray.plus(elements: ShortArray): ShortArray defined in kotlin.collections public operator fun ShortArray.plus(elements: Collection<Short>): ShortArray defined in kotlin.collections public operator fun String?.plus(other: Any?): String defined in kotlin public operator fun String?.plus(other: Any?): String defined in kotlin @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun UByteArray.plus(element: UByte): UByteArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun UByteArray.plus(elements: UByteArray): UByteArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes public operator fun UByteArray.plus(elements: Collection<UByte>): UByteArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun UIntArray.plus(element: UInt): UIntArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun UIntArray.plus(elements: UIntArray): UIntArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes public operator fun UIntArray.plus(elements: Collection<UInt>): UIntArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun ULongArray.plus(element: ULong): ULongArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun ULongArray.plus(elements: ULongArray): ULongArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes public operator fun ULongArray.plus(elements: Collection<ULong>): ULongArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun UShortArray.plus(element: UShort): UShortArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes @InlineOnly public inline operator fun UShortArray.plus(elements: UShortArray): UShortArray defined in kotlin.collections @SinceKotlin @ExperimentalUnsignedTypes public operator fun UShortArray.plus(elements: Collection<UShort>): UShortArray defined in kotlin.collections public operator fun <T> Collection<???>.plus(elements: Array<out ???>): List<???> defined in kotlin.collections public operator fun <T> Collection<???>.plus(elements: Iterable<???>): List<???> defined in kotlin.collections public operator fun <T> Collection<???>.plus(elements: Sequence<???>): List<???> defined in kotlin.collections public operator fun <T> Collection<String>.plus(element: String): List<String> defined in kotlin.collections public operator fun <T> Iterable<???>.plus(elements: Array<out ???>): List<???> defined in kotlin.collections public operator fun <T> Iterable<???>.plus(elements: Iterable<???>): List<???> defined in kotlin.collections public operator fun <T> Iterable<???>.plus(elements: Sequence<???>): List<???> defined in kotlin.collections public operator fun <T> Iterable<String>.plus(element: String): List<String> defined in kotlin.collections public operator fun <K, V> Map<out ???, ???>.plus(pairs: Array<out Pair<???, ???>>): Map<???, ???> defined in kotlin.collections public operator fun <K, V> Map<out ???, ???>.plus(pair: Pair<???, ???>): Map<???, ???> defined in kotlin.collections public operator fun <K, V> Map<out ???, ???>.plus(pairs: Iterable<Pair<???, ???>>): Map<???, ???> defined in kotlin.collections public operator fun <K, V> Map<out ???, ???>.plus(map: Map<out ???, ???>): Map<???, ???> defined in kotlin.collections public operator fun <K, V> Map<out ???, ???>.plus(pairs: Sequence<Pair<???, ???>>): Map<???, ???> defined in kotlin.collections public operator fun <T> Set<???>.plus(elements: Array<out ???>): Set<???> defined in kotlin.collections public operator fun <T> Set<???>.plus(elements: Iterable<???>): Set<???> defined in kotlin.collections public operator fun <T> Set<???>.plus(elements: Sequence<???>): Set<???> defined in kotlin.collections public operator fun <T> Set<String>.plus(element: String): Set<String> defined in kotlin.collections public operator fun <T> Sequence<???>.plus(elements: Array<out ???>): Sequence<???> defined in kotlin.sequences public operator fun <T> Sequence<???>.plus(elements: Iterable<???>): Sequence<???> defined in kotlin.sequences public operator fun <T> Sequence<???>.plus(elements: Sequence<???>): Sequence<???> defined in kotlin.sequences public operator fun <T> Sequence<String>.plus(element: String): Sequence<String> defined in kotlin.sequences

What version of the compiler do you use? Because even your first example does not compile in 1.3.40.

I use Android Studio 3.4.1 fully updated. No separeted Kotlin compiler.

In fack, in Kotlin Playground the B option also gives an error.
However, the message is smaller

The character literal does not conform to the expected type String

But is weird because mixing type is IF expression is not a problem.

var s: Long=0L
s +=  (if (true) 5L else 5)    

The above code runs well.

This code runs well because you explicitly declare the type and literal 5 is automatically coerced. It is explained in the documentation.

I run again in Kotlin Playground

The below code runs well

var s: String="ar"
s +=  (if (true) "" else 'a')    
s +=  (if (true) "b"  else "")

And this below code fails, with a very big error message

var s: String="ar"
s  +=  (if (true) "" else 'a')    +   (if (true) "b"  else "")

No sense for me. The first sum parcel run and the second also runs. concatenation accepts mixed types.

You obviously run in type inference problem. The type could be inferred for individual operations, but not for the chain, because you can add a char to string, but you can’t add string to Any.

That said, you should not use such operations on strings anyway.

My example is very schematic, in my real program make sense. The char is a fixed delimiter.

Just use one-letter string instead. Also, in most cases, it is better to use string interpolation instead of concatenation.

a) char is not my choice. It’s a parameter constant in Android. It’s clumsy to use parameter.toString().
b) I don’t like strict rules. I use + for concatenation since forever. It’s very short and clear.
c) I like string interpolation, but not for big expressions. It’s confuse.

1 Like

You can use + for concatenation, but first left-hand operand must be a string. In this fragment:

var s: String="ar"
s +=  (if (true) "" else 'a')    
s +=  (if (true) "b"  else "")

you always add something (Any on line 2 and String on line 3) to a string. While in this fragment:

var s: String="ar"
s  +=  (if (true) "" else 'a')    +   (if (true) "b"  else "")

before appending to a string you try to add a String (right-hand) to Any (left-hand).

If you really want it to work that way in your project, you can define

operator fun Any.plus(other: String) = toString() + other

But that may come with strange effects like ambiguities or

var i: Any = 1
i += "1"

Perhaps it is easier to just write s += "" + (if (true) "" else 'a') + (if (true) "b" else "")

Well, inside Kotlin Playground, the 2 below options works fine.

println('a'+"b")
println("a"+'b')

Yes, you can also add a String to a Char. Still, you can’t add a String to Any.

Technically, it may be any type, but from the point of view of the final programmer, not acquainted with the language design, this does not make sense. Some construct that has the hypothesis of being char or string, to be considered internally as any is an inaccessible stuff for mortals.