Hi there! I got this code: ``` @OptIn(Experimen...
# announcements
j
Hi there! I got this code:
Copy code
@OptIn(ExperimentalContracts::class)
    private fun OriginQueryNode.isSimpleQuery(): Boolean {
        contract {
            returns(true) implies (this@isSimpleQuery is OriginQueryNode.FilterAttributes)
        }
        return this is OriginQueryNode.FilterAttributes && ...
    }

    private fun calculateMembersLocallyIfPossible(originQuery: OriginQueryNode): MemberGaussCollection? =
        if (originQuery.isSimpleQuery()) {
            println(originQuery.fieldOnlyFilterAttributes)
        }
In the `calculateMembersLocallyIfPossible`fun I try to access the field `fieldOnlyFilterAttributes`after checking
isSimpleQuery
is true. The contract should let me access the field but it's not working (marks
fieldOnlyFilterAttributes
as not existent.
If I change the check to this:
Copy code
if (originQuery.isSimpleQuery() && originQuery is OriginQueryNode.FilterAttributes) {
then it works.
Why is the contract not working?
n
kinda seems like the contract isn't doing anything at all from here
j
Yep, but I don't know why... I tried a similar example:
Copy code
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract


sealed class A(val a: String) {
	class B(val b: String): A("a")
}

@OptIn(ExperimentalContracts::class)
fun A.isNice(): Boolean {
    contract {
        returns(true) implies (this@isNice is A.B)
    }
    return this is A.B && b == "nice"
}

fun A.printIfNice() {
    if (isNice())
    	println("It's nice! ${this.b}")
}

fun main() {
    val someB = A.B("nice")
    
    someB.printIfNice()
}
And this works as expected
n
those do indeed look equivalent to me. is OriginQueryNode also a sealed class?
j
Yep, the simple example mimics the real code
Copy code
sealed class OriginQueryNode {

    class FilterAttributes(
        val attributeName: String,
        val operator: ComparisonOperator,
        val comparables: List<String>,
        val comparablesAsExpression: List<String>
    ) : OriginQueryNode()

    class SetOperation(...) : OriginQueryNode()
}
Ok... This fun was inside a class, if I put it outside the class it works
Copy code
@OptIn(ExperimentalContracts::class)
    private fun OriginQueryNode.isSimpleQuery(): Boolean {
        contract {
            returns(true) implies (this@isSimpleQuery is OriginQueryNode.FilterAttributes)
        }
        return this is OriginQueryNode.FilterAttributes && ...
    }
So as extension function inside class the contract does not work or it's not properly specified (probably the last)
n
huh. that's...unexpected. does that sound like a bug to you?
j
Probably not, I'll play a little more with the simple example to be sure
n
I'd double-check that the correct
this
is being checked in the contract block
👍 1
the contract says
this@isSimpleQuery
but then the code right after just says
this
j
Full simple example that replicates the problem in my original code:
Copy code
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract


sealed class A(val a: String) {
    class B(val b: String) : A("a")
}

class OtherClass {
    fun someTest(a: A) {
        a.printIfNice()
    }

    @OptIn(ExperimentalContracts::class)
    private fun A.isNice(): Boolean {
        contract {
            returns(true) implies (this@isNice is A.B)
        }
        return this is A.B && b == "nice"
    }

    private fun A.printIfNice() {
        if (isNice()) {
            println(this.b)
        }
    }
}

fun main() {
    val someB = A.B("nice")
    val c = OtherClass()
    c.someTest(someB)
}
Converting isNice() receiver to parameter makes the example work
n
weird