Would it be possible to declare properties (with lifetime bounded by class lifetime) but nested inside a function and only accessible there. If the property is only used in one function then this would both make it obvious, and avoid it being ‘misused’ elsewhere.
eg
fun foo() {
. private var counter = 0
. counter++
}
This would be even more useful when synchronising on lock objects as it is obvious that only the current method uses the lock object and helps to prevent further edits creating deadlocks.
fun restrictedAccess() {
. private val lock = “restrictedAccessLock”
. synchronised (lock) {
. }
}
True, but I am interested in a property whose lifetime is longer than the function within which it is declared. For example the logic for fun restricted access is currently written
private val lock = “restrictedAccessLock”
fun restrictedAccess() {
. synchronised (lock) {
. }
}
Which means that the val ‘lock’ can get separated from the function and misused, possibly causing deadlocks.
Writing the code as this:
fun restrictedAccess() {
. val lock = “restrictedAccessLock”
. synchronised (lock) {
. }
}
would mean that the lock was a new instance every time resulting in no effective lock.
Because the value may need to persist across invocations of the method… for example locking on a new object each call will not enforce single thread access…
“initialisation guaranteed to have been performed before the first read of the value”? I am not a compile writer, so I do not know what that implies
I would like to believe that it is just an instance property (initialised at class initialisation time) but that can only be referenced from one function/block/scope.
val restrictedAccess = object : () -> Unit {
private val lock = Any()
override operator fun invoke() {
synchronized(lock) {
println("locked")
}
}
}
If you’d prefer the API to have an actual method, you could just use private val _restrictedAccess = ... and wrap that with a fun restrictedAccess method.
If you use that pattern often you could always create a helper method:
fun selfSynchronizedInvocable(block: () -> Unit) = object : () -> Unit {
private val lock = Any()
override operator fun invoke() {
synchronized(lock) {
block()
}
}
}
val restrictedAccess = selfSynchronizedInvocable { println("locked") }
Thanks for the suggestion. That certainly looks interesting. I guess that I would simply invoke by:
restrictedAccess()
to print ‘locked’?
In the absence of language support then that provides a more robust solution than leaving the lock object floating around the class definition. It does require more ‘boilerplate’ than my suggested change to the language though. It might be that my use case is not common enough for a language change.
I had thought that the difference between
class Foo {
private val lock = Any() // visible within class
fun bar() {
synchronized(lock){
println()
}
}
}
and
class Foo1 {
fun bar() {
private val lock = Any() // visible within method
synchronized(lock){
println()
}
}
}
would have been quite simple - but I am not a compiler-writer. ‘lock’ would still be a property on the instance of the class treated exactly as normal instance properties The only difference would be that access would be restricted by the compiler.
I don’t see this making beyond the “-100 points rule”.
This use-case is very speficific to ‘a class a memeber that needs to be read by a single method’.
Now kotlin has solutions for that, either defining a new object with encapsulates the logic or what @nickallendev has suggested, which is a way to define that inline.
As soon as you need 2 class methods to ‘see’ this memeber you need to walk back from using static and revert to the “define a new object” approach.
Certainly it is soluble - and I am grateful for the suggested solution. (And grateful for Kotlin too)
Excuse my ignorance, but what is ‘the 100 points rule’?
Basically the idea is that to add a new feature to a language you don’t just need a positive impact, but you need to weigh the cost of having an additional feature as a whole, and that is what these “-100” points are.
So a feature to make the cut needs to be valued more than “100 points”. Note that there is no definition of point.
I’d love to see this feature. While I agree with the issues mentioned above, this comes up in the code so often that it definitely beats the minus 100 points things for me.
I have never felt the need for this, if you have state that is local to one (or few) operations, you can simply create a class for it. That’s how you improve cohesion.
I think it is harder to communicate this approach than wrapping the function and the value in one object.
Because functions didn’t have any fields, private and static won’t communicate enough about the presence of a field.