Has this ever been officially suggested? To allow something like Python’s __bool__
?
class BooleanThing{
operator fun bool() = true
}
fun main() {
if (BooleanThing()) {
println("Hello World")
}
}
Has this ever been officially suggested? To allow something like Python’s __bool__
?
class BooleanThing{
operator fun bool() = true
}
fun main() {
if (BooleanThing()) {
println("Hello World")
}
}
Idk. I bet many people would agree that truthy-ness isn’t a great language feature fit for Kotlin especially if implementers could override it with even more risk.
IMHO For some languages (like Groovy), truthy-ness is one of those features that, if removed from those languages, would immediately improve.
Instead of
if (Repository()) ...
if (response) ...
if (blob.groupId) ...
if (code) ...
I much prefer
if (Repository().isActive) ...
if (response.isSuccess) ...
if (blob.groupId != null) ...
if (code != 0) ...
The main that I’ve seen for truthiness seems to be that you don’t have to write the != null
or != 0
. Which can often be a negative thing.
For example, take if (code)
.
What I really mean under the hood is if (code != 0)
. Now things are more clear that I care about the code being zero and not some other value like null
or another special truthy condition.
Even better than that, now that I’m forced to write the zero I might notice that what I really mean is
if (code != OrderCode.CANCELLED)
I’d say that is much more expressive than if (code)
, which can end up concealing the meaning in order to save characters.
If you do think truthy-ness is a good fit for Kotlin, a good way of demonstrating that is to find some use-cases of Kotlin that are particularly painful to use and that truthy-ness would solve better than alternative solutions.
@arocnies , thanks for your thoughts. I actually feel similarly that I wouldn’t want truthy-ness for most objects. For example, I would never want if (Repository())
instead of if (Repository().isActive)
. I like code to be easy to read and also to make sense, like reading english. if (Repository())
could just as easily mean if (Repository().isNotEmpty())
, and that creates lots of confusion.
The reason I brought this is up is because I have the following:
class TestSwitch(val key: String) {
val isEnabled by lazy { System.getProperty(key, "false").toBoolean() }
}
val ManualTests = TestSwitch("DO_MANUAL_TESTS")
val StageTests = TestSwitch("DO_STAGE_TESTS")
val ChromeTests = TestSwitch("DO_CHROME_TESTS")
This is just some code to help me control which tests I am running during a particular test execution. I saw if (StageTests.isEnabled)
and thought to myself that in this particular case, if (StageTests)
made sense to me.
But given this is such an isolated example, and also that if (StageTests.isEnabled)
doesn’t actually look that bad and reads well, I’m happy to accept the way it is
And of course, there’s always:
inline fun ifTestSwitchEnabled(testSwitch: TestSwitch, op: () -> Unit) {
if (testSwitch.isEnabled) op()
}
And similar variations.
Gotcha Sometimes I reply expecting that in the future there may be people finding the post and not just one person.
I wish I had a half-decent argument in favor of truthy-ness in a language, just to cover all the perspectives… The best I might be able to do is an argument for limited truthy-ness, or a very specific mix of language features (i.e. DSL-like language).
It is nice to see use-cases. And yeah I would agree and say the counter option of if (testSwitch.isEnabled) ...
is pretty good.
If someone did want to use a form of truthy-ness in Kotlin now to get a feel, it is possible to reduce the typing to a single character. For example if (+myObject)
with overriding unary plus.
Another alternative ask is some other language feature like type-classes (or some other feature). Which would enable writing your own toBoolean()
function just like toString()
.
^ I’m not a fan of that specific potential use but maybe someone else is.
For your specific use case, property delegation works pretty well:
import kotlin.reflect.*
class TestSwitch(val key: String) {
val isEnabled by lazy { System.getProperty(key, "false").toBoolean() }
operator fun getValue(thisRef: Any?, prop: KProperty<*>) = isEnabled
}
val ManualTests by TestSwitch("DO_MANUAL_TESTS")
val StageTests by TestSwitch("DO_STAGE_TESTS")
val ChromeTests by TestSwitch("DO_CHROME_TESTS")
fun main() {
if (StageTests) {
println("staging tests")
} else {
println("not staging tests")
}
}
@kyay10 thanks for the suggestion. Sorry I didn’t make this clear but I actually need to access the key
and other properties as well. The code is located with a common library. The library is used by gradle like so:
jvm {
testRuns.create(StageTests.taskPrefix) { test ->
test.executionTask.configure {
it.systemProperty(StageTests.key, "true")
}
}
}
If I used delegation, I would need to do something like:
val ManualTests = TestSwitch("DO_MANUAL_TESTS")
val ManualTestsProp by ManualTests
val StageTests = TestSwitch("DO_STAGE_TESTS")
val StageTestsProp by StageTests
val ChromeTests = TestSwitch("DO_CHROME_TESTS")
val ChromeTestsProp by ChromeTests
This is because I would need the original object to be available too, so I could access keys
and taskPrefix
So I’m not sure delegation would be worth the trouble.
Yeah sadly rn there’s no way to access the delegate of a property easily. I believe it’s something the kotlin team is looking at.