70 lines
2.3 KiB
Plaintext
70 lines
2.3 KiB
Plaintext
== Why is this an issue?
|
|
|
|
Kotlin provides the operators `as` and `as?` to cast an expression to a specific type,
|
|
and `is` to check the assignment compatibility with a type.
|
|
These operators are used for downcasts, smart casts, and run-time type checking.
|
|
|
|
In case the `as` or `as?` operator is used for upcasting from a subtype to a supertype,
|
|
the cast is redundant as it has no effect and can never fail.
|
|
If a specific type is expected, an expression of a subtype can always be inserted
|
|
without casting (Substitution Principle and Assignment Compatibility).
|
|
|
|
Likewise, the `is` operator is redundant and will always return `true` if the type of the expression on the left
|
|
side is assignment compatible with the type on the right.
|
|
|
|
=== What is the potential impact?
|
|
|
|
==== Code redundancy
|
|
|
|
Since the operation will always succeed and has no side effects, it is pointless to use it.
|
|
Conditions with `is` will lead to dead code branches because they will always or never be satisfied.
|
|
|
|
== How to fix it
|
|
|
|
Remove the operator and all dead code branches that result from it, or investigate why the expression that is cast or checked has
|
|
an unexpected compile-time type.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,kotlin,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
fun types(value: Int, elements: List<Number>) {
|
|
val a: Number = value as Number // Noncompliant, Int instance is always a Number
|
|
val b: Number = value as? Number // Noncompliant, Int instance is always a Number
|
|
|
|
val text = if (value is Number) { // Noncomplient, else-branch is dead code
|
|
"happens always"
|
|
} else {
|
|
"impossible"
|
|
}
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,kotlin,diff-id=1,diff-type=compliant]
|
|
----
|
|
fun types(value: Number, elements: List<Number>) {
|
|
val a: Int = value as Int // Compliant, Number instance could be an Int
|
|
val b: Int = value as? Int // Compliant, Number instance could be an Int
|
|
|
|
val text = if (value is Int) { // Compliant, both branches reachable
|
|
"impossible"
|
|
} else {
|
|
"happens always"
|
|
}
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://kotlinlang.org/docs/typecasts.html[Kotlin API Docs, Type checks and casts]
|
|
|
|
=== Articles & blog posts
|
|
|
|
* https://en.wikipedia.org/wiki/Liskov_substitution_principle[Wikipedia, Liskov substitution principle]
|