It depends on how you wrote extension function/property. If they doesn't edit or access shared state i.e. if property and function is clear function: it absolutely not bad practice.
Example 1:
fun String.countSpaces(): Int {
return this.count { c -> c == ' ' }
}
This functions works perfectly in multi-threaded environment, since String
is immutable.
Example 2:
data class MutablePerson(val name: String, var speech: String)
fun MutablePerson.count(nextNumber: Int) {
this.speech = "${this.speech} ${nextNumber}"
}
This function mutates speech
property of MutablePerson
object and assign operation is not atomic. If count
will be called on one object from different threads - inconsistent state possible.
Example:
fun main(args: Array<String>) {
val person = MutablePerson("Ruslan", "I'm starting count from 0 to 10:")
(1..10).forEach { it ->
Thread({
person.count(it)
println(person.speech)
}).start()
}
Thread.sleep(1000)
println(person.speech)
}
Possible output:
I'm starting count from 0 to 10: 1
I'm starting count from 0 to 10: 1 3
I'm starting count from 0 to 10: 1 3 4
I'm starting count from 0 to 10: 1 3 4 2
I'm starting count from 0 to 10: 1 3 4 2 5
I'm starting count from 0 to 10: 1 3 4 2 5 8
I'm starting count from 0 to 10: 1 3 4 2 5 6
I'm starting count from 0 to 10: 1 3 4 2 5 6 7
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9 10
I'm starting count from 0 to 10: 1 3 4 2 5 6 7 9 10
So extension functions and extensions properties not bad practice, they are just like properties and method in classes: depending on how you wrote they thread safe or not.