BitSet array access notation misleading

val b = BitSet(2) b[1] = 1 // should be = true println(b)

Will print {}, as it won’t set anything in the bit set. The reason is that b[1] = 1 desugars into b.set(1, 1), which sets a range. However the syntax suggests the 1th bit will be set. Not sure how to address this, perhaps a warning?

It seems to work OK if you call the set() method which takes one parameter directly:

val b = BitSet(2)
b.set(1) 
println(b)

This prints {1} as expected.

Perhaps best to do this when you find a ‘set’ method with several overloads.

I’ve just checked the operator overloading secion of the documentation and it does imply there that:

b[1] = 1

maps to:

b.set(1, 1)

The behavior is therefore as expected though it’s unfortunate that the second parameter is exclusive and so no bit is actually set.

I doubt whether it’s practicable to issue a warning for something like this (except possibly for a few frequently used classes). You just have to think about which overload will actually be called.

Other ways of avoiding the problem:

b[1] = true

or

b[1] = 2 // don't care for this one much!

You misunderstand, it’s clear why kotlin behaves like this, my issue is that the [i] = value syntactic sugar can be very misleading in cases where the set() parameters don’t actually encode an index-value pair

The problem seems to be with Java interop. BitSet is a Java type and as such it attempts to detect operators instead of requiring a keyword. I don’t think that BitSet is common enough for a compiler/library workaround. It would be a prime candidate for a lint style tool though.

Sorry, if I misunderstood your point at first but, yes, I do agree that the use of Kotlin’s indexer syntax is misleading in these circumstances.

However, it’s difficult to see how the Kotlin compiler could identify such cases without knowing what the parameters actually represent. One thing that might be possible would be to issue a warning when several overloads of ‘set’ exist so you can make sure you’re actually calling the one which does what you want.

It would be useful to have a comment from JetBrains on the problem.

@alanfo And for classes in the wild there is no way for the compiler to know so. Even for the java standard library it’s a stretch. This is stuff that is normally better placed in a static analysis tool than a compiler. That analysis tool could even allow users to configure the list (add their own items).

I strongly suspect that beyond special casing there is little that can be changed in the language at this point as anything would also imply breaking stuff. The main “issue” is that the syntactic sugar applied to Java classes uses “duck typing” rather than work on specific interfaces. There are probably good reasons for the duck typing approach. In this particular case, the set(first, last) has a rather dodgy name anyway as developers can be just as easily confused as syntactic sugarifiers. Unfortunately in terms of the standard library this is not that big an example of poor design.

We’re definitely not going to make any changes in the compiler related to this problem, but it’s definitely possible to implement an inspection to warn about this situation. Feel free to file a feature request in YouTrack.