if I’ve got a function with a `List<String>`...
# getting-started
y
if I’ve got a function with a
List<String>
, can I expect Kotlin to reuse this list, or will it allocate on every call to the function?
j
List<*> is just an interface. You have to be more specific. Are you creating a list inside function or are you passing list as a parameter?
y
I’m doing
listOf("literal1", "literal2", …)
inside the function.
l
every time you call listOf it will create a new list
m
if you have a function like:
Copy code
fun getList() = listOf("literal1", "literal2")
then it will create one every time. It might be better to save the list in the class itself in the companion object.
☝️ 2
y
@Loney Chou @Michael de Kaste thanks!
i
why not use it as a variable?
val list = listOf("literal1", "literal2")
y
because then it gets reallocated on every call, as has been mentioned
m
not if you put it in a variable before like what @Ilya K did. A variable will calculate the value once and then "hold" the value
a function will always recalculate
s
just to be super-clear, what Ilya and Micael are suggesting is something like this
Copy code
private val list = listOf("literal1", "literal2")

fun getList(): List<String> = list
And since
List
is an immutable interface, you're pretty safe that you won't run into multiple parts of the programm modifying their list and screwing up everybody else (they could technically do that by first casting their instance to
MutableList
). Normally this level of contract ("don't cast") is good enough, if it's not, you can use immutable collections from https://github.com/Kotlin/kotlinx.collections.immutable
y
@Stephan Schroeder Thanks for the clarification, I appreciate it. That’s actually the solution I’ve been using, as that is the usual suggestion for people looking for declaring
static
variables.
g
I don't see why you need an intermidiate getList function for this, just expose list property as Ilya suggested I also would argue that in most cases class-level property is better than static (or top-level property in Kotlin), class level list would be allocated only on class creation and garbage collected with class object instead of forever be in heap. Caching forever makes sense only if you have many instances of this class and really want to optimize some hot path code
y
oh yeah, sorry for not being clear. I have a
private val someList = listOf(…)
as a class property. no intermediate function. just like I do for
Regex
objects to avoid recreating them. only issue is that it pollutes the class-level namespace, but eh.
I have a single instance, but it’s a function that is being called many times
👍 1
g
In this case private class-level property is exactly what you need
s
Since you're in a garbage-collected language there is an argument to be made for not caring about allocation of a new list each time. By moving the list out the function that uses it, you violate the code-locality principle a bit, which makes the code a tiny bit harder to read. This is why I rarely employ this optimization. Like I mentioned before, there is also the additional risk of another dev later using casting of
List
to
MutableList
as another optimization thereby opening a can of worms. Simply creating a new list each time protects you of such future optimization interactions.
y
@Stephan Schroeder thanks. I do admit to being used to non garbage-collected languages. I’m also prone to doing premature optimization. is there at least a point in doing this optimization for
Regex
objects? creating these tends to be expensive in other languages.
g
Usually yes, Regex is not so fast on JVM I personally don’t see any issue from caching on class-level, it’s a good trade off, also I believe it’“s not even real code-locality violation as soon as it a part of your class
👍 1
s
I cache Regexes as well. For me it's a question of how high the initialisation cost is. If it's cheap (for some project-specific definition of "cheap") enough to initialise the objects in question, i don't chache them. Of course the decision is on a spectrum. As long as you're aware of the pros and cons, you're good. (I'm currently playing around with Rust, so I'm on my way of caring more about allocations than I used to 😅)
👍 1