2

I have a filed bytes in class in Kotlin:

var bytes: ByteArray? = null
    get() = when {
        field != null -> Arrays.copyOf(field, field!!.size)
        else -> field
    }
    set(value) {
        field = when {
            value != null -> Arrays.copyOf(value, value.size)
            else -> null
        }
    }

Why in 3rd line there must be an !! operator for field?

Without !! Idea shows:

Smart cast to 'ByteArray' is impossible, because 'field' is a mutable property that could have been changed by this time

Condition (field != null) ensures that field is null in if body (right side). Or not? Or it can be reassigned to null meanwhile? How is this possible?

   

With above code FindBugs warns:

Redundant nullcheck of com.xy.Some.bytes which is known to be null in com.xy.Some.getBytes()

This method contains a redundant check of a known null value against the constant null.

http://findbugs.sourceforge.net/bugDescriptions.html#RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE

Lukas M.
  • 2,859
  • 23
  • 30

2 Answers2

3

bytes is a var which is mutable and may be changed after the null check (on other thread maybe). You cannot guarantee bytes is non-null, so using !! here is not safe.

Official explanation:

Note that smart casts do not work when the compiler cannot guarantee that the variable cannot change between the check and the usage. More specifically, smart casts are applicable according to the following rules:

  • val local variables - always;
  • val properties - if the property is private or internal or the check is performed in the same module where the property is declared. Smart casts aren't applicable to open properties or properties that have custom getters;
  • var local variables - if the variable is not modified between the check and the usage and is not captured in a lambda that modifies it;
  • var properties - never (because the variable can be modified at any time by other code).

One of the workaround is to use let:

get() = field?.let { Arrays.copyOf(it, it.size) } ?: field

Suggested reading: In Kotlin, what is the idiomatic way to deal with nullable values, referencing or converting them

Community
  • 1
  • 1
BakaWaii
  • 6,732
  • 4
  • 29
  • 41
1

You can't smart cast with nullable mutable properties because in this code:

 if (nullableMutableProp != null) {
   doSomethingWith(nullableMutableProp)
 }

Between line 1 and 2 other code can change the value to null.

You can assign to a local val and smart cast away:

get() {
  val local = field
  return when {
    local != null -> Arrays.copyOf(local, local.size)
    else -> local
  }
}
Strelok
  • 50,229
  • 9
  • 102
  • 115