is it possible to make a class property that only ...
# getting-started
y
is it possible to make a class property that only the class itself can mutate, but is public to other classes? without making a getter? I expected
private set
to do this, but it seems like I can still mutate the value from outside the class.
s
private set
should indeed do this. can you provide the code? I hope you mean outer mutability (/reassignability)
x.list = otherList
, not inner mutability
x.list.clear()
Making the setter private will block the first one, but not the second one (since it only invokes the getter)
y
something like:
Copy code
class Foo() {
    private var bar: Bar = Bar()
    
    class Bar() {
        var items: MutableList<Int> = mutableListOf()
            private set
    }

    fun doTheThing() {
        bar.items.clear() //compiles and works
    }
}
y
so
private set
is just for the binding, the value itself is still mutable
n
You have to use "val items:List<Int> = mutable"
s
As @Stephan Schroeder was alluding to, “mutable” kind of means two different things. Mutating a property is different from mutating the contents of an array/collection.
s
private set
makes the setter private, but
bar.items.clear()
doesn't invoke the setter.
y
yeah.
s
additionally Bar is an inner class, so I'm not even sure that this restricts the access by the containing class.
l
You can create an interface that exposes items: List<Int>, and implement it in a class as override items: MutableList<Int>. Anything that references your interface will have access to the immutable list, but inside your class, it’s mutable
y
seems like it does restrict access.
l
I do this with StateFlow/MutableStateFlow for UI view models all the time.
s
what you can do is
Copy code
class Bar() {
   private var _items: MutableList<Int> = mutableListOf()
   val items: List<Int> get() = _items // is typesafe but could run into ConcurrentModificationExcaption in multithreaded code, if the read-only copy is iterated on while the mutable version is changed
}
or harden this approach (the former approach still allows casting the reference back to
MutableList
) like this
Copy code
class Bar() {
   private var _items: MutableList<Int> = mutableListOf()
   val items: List<Int> get() = _items.toImmuatableList() //return only a static snapshot
}
with
toImmuatableList
coming from this lib https://github.com/Kotlin/kotlinx.collections.immutable
y
that’s an accpetable solution in my opinion, since it’s essentially a desugaring of the solution referenced in the issue tracker.
👍 1
@Landry Norris can you clarify? I’m struggling to implement this
(also, thanks everyone for being helpful as always!)
s
wait, i made a mistake
l
Copy code
interface Bar {
    val items: List<Int
}

class Foo: Bar {
    override val items: MutableList<Int> = mutableListOf(0)
}
Any usage of Bar#items will be immutable.
s
it shouldn't be
var
but
val
I updated the code.
👍 1
y
@Landry Norris oh, I understand. nice. too much boilerplate for my throwaway class, but it’s something to keep in mind.