Condition operators for If expression

We need Condition operators to get Inline classes behave as Boolean values.

Now:

value class FeatureSwitch(/*CAN'T BE private*/ val enabled: Boolean) {
    val isEnabled: Boolean get() = enabled
}

fun doFeature(val sw: FeatureSwitch) {
    if (sw.enabled) {  // needs to access to the backing field
        println("Do something")
    }
    if (sw.isEnabled) {  // ... or define a redundant property
        println("Do something")
    }
}

Proposal:

value class FeatureSwitch(private val enabled: Boolean) {  // <-- The backing field can be private
    operator fun condition() = enabled  // the Condition operator
}

fun doFeature(val sw: FeatureSwitch) {
    if (sw) {  // <-- We wonna write like this
        println("Do something")
    }
}

Also, we think it’s useful that If-condition operators can be defined for any classes.

1 Like

I think the fear would be of repeating JS all over again with something like:

operator fun Any?.condition() = this != null

While I understand your point about a need for condition operator, I don’t really get your enabled vs isEnabled examples. Isn’t this:

value class FeatureSwitch(private val enabled: Boolean) {
    val isEnabled: Boolean get() = enabled
}

exactly the same as:

value class FeatureSwitch(val isEnabled: Boolean)

?

1 Like

Thank you for your replies!

to: kyay10
An idea to avoid recursive call is that it’s limited just one time to call the condition operator.
(This limitation implies that the return type of Condition operator mube be Boolean.)

to: broot
Sorry that my example is confusing. Let me explain our issue again.

The our goal is just giving a specific type to Boolean.
And we guess Inline class is suitable in Kotlin.

Then I want to make the backing field private to hide implementation details of the class.
Because Inline class is a kind of ADT (Abstract Data Type),
I think the details should not be open to others.
(i.e. Information Hiding of OOP)

value class FeatureSwitch(private val enabled: Boolean)

In short, I expect that a Inline class of Boolean behaves as same as Boolean.

But currently, to use in If expression, I must add a redundant property.

value class FeatureSwitch(private val enabled: Boolean) {
    val isEnabled: Boolean get() = enabled
    // I must type 'enable' 3 times.
    // And caller's must know 'isEnabled'.
}

Inline classes of Boolean is very frequently appeared with well-typed software design.
So we’d like to reduce that repeating coding.

I didn’t take part in designing the Kotlin language, so I may be wrong, but I believe above assumption is incorrect. Inline classes are conceptually just classes, you should think of them and use them as any ordinary class. Inlining enables performance optimization, but even if in practice you work on unwrapped values, you should still think of them as they are actually wrapped.

Maybe typealias is closer to your needs:

typealias FeatureSwitch = Boolean

But this is far from perfect, because it is truly an alias, not a new type, so it does not provide a type safety.

This is the part that is really confusing to me. You say that you would like your class to behave like a boolean and at the same time you say you would like to hide its boolean value to outside world, because it is implementation details. Don’t you think these expectations contradict?

Of course, if there would the condition operator then you could hide internal boolean and expose it through the operator. But still, you would have to write the same amount of code as in your 3 times enable example.

1 Like

Thanks for your reply!

Our needs are not satisfied by using typealias because it doesn’t provide type safety you mentioned.

You say that you would like your class to behave like a boolean and at the same time you say you would like to hide its boolean value to outside world, because it is implementation details. Don’t you think these expectations contradict?

No, I didn’t.

I think that it’s is important that the users of FeatureSwitch don’t care of how to implement.
As you said, for this point only, I can use typealias FeatureSwitch = Boolean because
users don’t need to know what FeatureSwich actually is.

But type alias is not type safety then users may passing wrong typealias-ed Boolean values.
For example, users can pass a FeatureSwitch value as a ExperimentalFeatureFlag value
where typealias ExperimentalFeatureFlag = Boolean.

Thanks to you, I think I sorted out my issues:

  • Type safety
  • Users don’t need to know how the class is implemented (Inline class or Boolean type alias)
  • Users can’t access to implementation details such as backing fields.
  • Users can use the class without knowing it’s accessor such as isEnabled.

If you just like syntactic sugar, you can do that:

@JvmInline
value class FeatureSwitch(val enabled: Boolean) {
    operator fun unaryPlus() = enabled
    operator fun not() = !enabled
}

fun doFeature(switch: FeatureSwitch) {
    if (+switch) {
        println("Do something")
    }
    if (!switch) {
        println("Do something else")
    }
}

I didn’t mean that the issue is recursive calls at all, but that if a person makes this extension fun that I mentioned, then we have the issue of JS considering everything to be a valid boolean when it really, really shouldn’t. Type coercion always causes a bunch of nasty, undetectable issues

1 Like