Infix call corresponds to a dot-qualified call 'charMap.get(c).and(mask)' which is not allowed on a nullable receiver 'charMap.get(c)'


#1

Dear developers,

Please help me to fix compilation problem of my class Base32.

The code is:

import java.nio.charset.Charset
import java.util.HashMap

class Base32 private constructor(alphabet:String) {
private val digits:CharArray
private var mask:Int = 0
private var shift:Int = 0
private val charMap:Map<Char, Int>
init{
digits = alphabet.toCharArray()
mask = digits.size - 1
shift = Integer.numberOfTrailingZeros(digits.size)
charMap = HashMap<Char, Int>()
var index = 0
while (index < digits.size)
{
charMap.put(digits[index], index)
index += 1
}
}
private fun decodeInternal(encoded:String):ByteArray {
if (encoded.length == 0)
{
return ByteArray(0)
}
val encodedLength = encoded.length
val outLength = encodedLength * shift / 8
val result = ByteArray(outLength)
var buffer = 0
var next = 0
var bitsLeft = 0
for (c in encoded.toCharArray())
{
if (!charMap.containsKey©)
{
throw DecodingException("Illegal character: " + c)
}
buffer = buffer shl shift
buffer = buffer or (charMap.get© and mask)
bitsLeft += shift
if (bitsLeft >= 8)
{
result[next++] = (buffer shr (bitsLeft - 8)).toByte()
bitsLeft -= 8
}
}
return result
}
private fun encodeInternal(data:ByteArray):String {
if (data.size == 0)
{
return “”
}
val outputLength = (data.size * 8 + shift - 1) / shift
val result = StringBuilder(outputLength)
var buffer = data[0].toInt()
var next = 1
var bitsLeft = 8
while (bitsLeft > 0 || next < data.size)
{
if (bitsLeft < shift)
{
if (next < data.size)
{
buffer = buffer shl 8
buffer = buffer or (data[next++] and 0xff)
bitsLeft += 8
}
else
{
val pad = shift - bitsLeft
buffer = buffer shl pad
bitsLeft += pad
}
}
val index = mask and (buffer shr (bitsLeft - shift))
bitsLeft -= shift
result.append(digits[index])
}
return result.toString()
}
class DecodingException(message:String):RuntimeException(message)
companion object {
private val UTF_8 = Charset.forName(“UTF-8”)
private val INSTANCE = Base32(“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef”)
fun decode(encoded:String):String {
return String(INSTANCE.decodeInternal(encoded), UTF_8)
}
fun encode(data:String):String {
return INSTANCE.encodeInternal(data.toByteArray(UTF_8))
}
}
}

The error messages are:

Compilation failure: Compilation failure:
[ERROR] Base32.kt:[64,4
2] Infix call corresponds to a dot-qualified call ‘charMap.get©.and(mask)’ which is not allowed on a nullable receiver
‘charMap.get©’. Use ‘?.’-qualified call instead
[ERROR] Base32.kt:[91,4
4] Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
[ERROR] @SinceKotlin @InlineOnly public inline infix fun BigInteger.and(other: BigInteger): BigInteger defined in kotlin

64,4:

  buffer = buffer or (charMap.get(c) and mask)

91,4:

      buffer = buffer or (data[next++] and 0xff)

Sincerely, Valentyn


#2

I think the error messages are quite clear. The first tells you that you try to use the infix operation on a nullable type. HashMap.get returns a Nullable type. You could for example use charMap.get(c)!! and mask. That way the code throws an exception if the result of get is null. I think you check that the element exists so this should be save.

The second error message is maybe a bit harder to understand. What it tries to tell you that it can not resolve the and. The reason for this is a bit hidden. The documentation for Byte is not very clear about this. The only hint is that, it’s an extension function. If you go into the documentation of and it tells you that it’s part of the kotlin.experimental package. So you will need to import this.

Once you do this you will also most likely get another type missmatch error, because kotlin does not automatically convert number types and buffer is of type Int while data is of type Byte, so you will need to fix this.


Also friendly advise for when you ask for help next time. Don’t post your entire code. Just show us the 3 or 4 lines of code where you have the problem.
For example for the second error you could have just posted this:

var buffer: Int = someValue
val data: ByteArray = someValue
buffer = buffer or (data[next++] and 0xff)

Sure, that way I would not have seen your imports, which are the problem in this case, but I could have guessed. This way I would have spent far less time, reading and trying to understand your code.

Also you can format your code by using a single ` at the start and end of your code (when formatting in line) or 3 of them to format multiple lines of code (In that case they have to be on their own line).


#3

It was solved.

@@ -61,7 +60,7 @@ class Base32 private constructor(alphabet:String) {
throw DecodingException("Illegal character: " + c)
}
buffer = buffer shl shift

  •  buffer = buffer or (charMap.get(c) and mask)
    
  •  buffer = buffer or (charMap.getValue(c) and mask)
     bitsLeft += shift
     if (bitsLeft >= 8)
     {
    

@@ -88,7 +87,7 @@ class Base32 private constructor(alphabet:String) {
if (next < data.size)
{
buffer = buffer shl 8

  •      buffer = buffer or (data[next++] and 0xff)
    
  •      buffer = buffer or (data[next++].toInt() and 0xff)