Is this the best way to provide read only access t...
# announcements
m
Is this the best way to provide read only access to a mutable list:
Copy code
class C {
    private val _elementList = mutableListOf<Element>()

    val elementList: List<Element>
         get() = _elementList
}
Taken from https://kotlinlang.org/docs/reference/coding-conventions.html#property-names
🎉 1
It can be written as two lines which is a little nicer
Copy code
class C {
    private val _elementList = mutableListOf<Element>()
    val elementList: List<Element> get() = _elementList
}
b
Depends on what's important to you: • Performance -> yes • Safety ->
Copy code
class C {
    private val _elementList = mutableListOf<Element>()
    val elementList: List<Element> get() = _elementList.toList()
}
// This will create a copy of the current state of your mutable list
m
ah, so the reference is to the mutable list which means calling code could cast to mutable and change it
v
Exactly
e
on the JVM, you could wrap it in a
Collections.unmodifiableList()
if you're concerned about it being treated as a
MutableList
or write your own wrapper with
class UnmodifiableList<T>(private val delegate: List<T>) : List<T> by delegate
âž• 1
m
good ideas
n
Calling code could, but it would require a deliberate downcast
m
this is for internal code so the original way should be fine, I just want to constrain the responsibility modifying a list to a single class but allow access to other code
n
I probably wouldn't worry about this personally, Kotlin allows for much more innocuous ways to mutate date you might not expect to
Yeah I think it's fine. Protect against Murphy, not Machiavelli.
e
Java code could cast without being intentional about it, as kotlin.collections.List and kotlin.collections.MutableList are the same java.util.List type
but if you don't interop with java code, you don't have to worry about that case
m
that's interesting as I have both java and kotlin in this project right now
n
ah interesting
TIL
m
java code might end up accessing this list
if so, I will wrap it as you suggested
e
in that case you may want to be more defensive
m
I would like to convert it all to kotlin but no time for that yet
n
doing a copy on every single access is pretty harsh though
even if performance isn't super critical, you could imagine someone not realizing this, creating super insane performance pitfalls. calling
elementList
in a loop for example; it's not at all obvious they need to cache it outside the loop
m
indeed
I wonder if this would work:
Copy code
class C {
    private val _elementList = mutableListOf<Element>()
    val elementList: List<Element> = Collections.unmodifiableList(_elementList)
}
Not sure if _elementList changes if elementList reflects those changes, I exepect it would
looking at the java doc, it would work since
unmodifiableList
provides a read only "view" of the underlying list
e
yes, there's no copying involved there, it's a wrapper view
updates to the underlying list will be visible in the unmodifiable wrapper
n
This may be too far out from what you want, but an alternative would also be to have a
var ImmutableList
, using kotlinx.immutable
instead of a
val MutableList
ImmutableList
inherits from
List
, so you can just return a
List
directly in the getter. I don't imagine that people can mutate it on the Java side (maybe I'm wrong). And your class won't mutate it either, just reassign. So it will never mutate the data of the clients of the class either.
That's kind of the problem for me, in a GC language if you have mutability there's potential headaches no matter what.
e
but that doesn't provide read only access to a mutable list, that provides an immutable list that the owner can't mutate either
n
yes, but the owner declares it
var
but doesn't expose the setter (as before)
then the owner can effectively mutate his own state via reassignment
but that will not affect anyone downstream who's cached the reference
m
it will affect anyone who expects the reference to reflect the current contents though, but calling code should not expect it to change if its a true kotlin immutable list
if I'm trying to create kotlin specific code (can't rely on JVM) then I would go the route of creating an UnmodifiableList implementation that delegates to List and override/hide the mutable functions
as @ephemient suggested above
which is basically what the JVM unmodifiableList does
n
I guess it depends which one you expect it to be
personally I think it's far preferable for the getter to give people back something that doesn't reflect the current contents
that's a simple contract for users; they can't count on cache and should just do an explicit, fresh call whenever they want to access the current state of the object.
If you want the first element in a list, you ask for it, you don't get it once and then assume that it's always at the front of the list
if you return a List, that reflects later mutation, then eventually somebody else puts that list inside their own class, not expecting it to change, and then it does