What is the best way (for performance and readabil...
# codingconventions
s
What is the best way (for performance and readability) to check for multiple equalities? Option 1:
if(string !in arrayOf("str1", "str2", "str3"...)) foo()
Option 2:
if(string != "str1" && string != "str2" ...) foo()
Option 3:
when(string)  { "str1", "str2", "str3" -> {} else -> foo())
The bytecode for option 3 uses `string`’s hashcode in something like:
Copy code
label20: {
         switch(string.hashCode()) {
            case 3541024:
               if (string.equals("str1")) {
                  break label20;
               }
               break;
            case 3541025:
               if (string.equals("str2")) {
                  break label20;
               }
               break;
            case 3541026:
               if (string.equals("str3")) {
                 break label20;
               }
            }
        foo()
}
e
performance, 2; readability, 1; no
s
Maybe it should?
Or maybe some other language construct should be introduced?
r
pro tip, unless you're doing something that is known to be performance intensive - never! ask what is best for performance, never! Look up premature optimization for further details. In short multiple points the two main ones are - 1. the bad performance is often never where people predict it might be (before you have actual data with a profiler you are most likely guessing) 2. the compiler is more clever than you and any of use. Write idiomatic code whenever possible, because if it is can be recognized and optimized by a compiler (if it is worth it) in short it is almost certainly a waste of time and effort to think in those terms (disclaimer: of course you shouldn't blindly do
O(n^n)
algorithms either, don't take the premature optimization point to its absurd extreme)
k
Readability is subjective. In my view, when there are only 2 strings to check, I find option 2 more readable, as it only has one
&&
operator and it's perfectly clear. For 3 or more strings, I find option 1 more readable. But if you have more than one such
if
check in a function, and one of them has 2 strings and the other 3 strings, I would make both of them use option 2 for consistency.
p
I assume
Copy code
when(string) {
    "str1", "str2" -> //...
}
is also a viable option - the downside being needing two nested blocks
r
Construct a Trie! 😄 #premature-optimization-ftw (outside of the function ofc) But yeah, don't worry about performance in cases like this. Unless you know your array is gonna be of size 10k-100k or more, then it's really not worth it. But in that case you would not be asking this question 😛
e
I don't particularly like the use of
arrayOf
- throughout all Kotlin code, using it instead of
listOf
is an intentional decision. it is understandable in this usage but as a reader of the code it takes me longer to check than otherwise
after we get collection literals in Kotlin, I think it would be more fair to expect an optimization for
Copy code
if (string in ["str1", "str2"...])
similar to the feature request for https://youtrack.jetbrains.com/issue/KT-36184
which would also be the most readable option as well
m
Hmm, in such cases I don't even write `arrayOf`nor `listOf`but `setOf`as it feels most natural
k
If you're using
if (str in setOf("a", "b"))
in a performance-critical loop, then be aware that
setOf
can be inefficient: 1. It creates a new array in every loop 2. For each element of the array, it adds it to a LinkedHashSet (and thus spends time calculating a hash and creating next and previous links) On the other hand,
arrayOf
just creates a new array.
s
if (string in "str1str2str3")
🧌
s
@phldavies interesting bytecode generated from your suggestion. OP updated.
@elizarov what do you think of @ephemient’s idea as another possible use case? I was going to formally comment on KT-43871 (Collection-literals) but I thought it more ergonomic to comment here asking for your input, partially because it provides context and other possible solutions.