Search code examples
validationkotlininheritancedefensive-programming

Is there a way to enforce that a kotlin function can be run only in the context of another function?


I'm trying to reply this answer Kotlin: Specify input-constraints in interface and my idea was to create a function that implements some validation and allowing the function to be validated to be called only in the context of the validation function. Is it possible? That's my current code:

interface MathThing {

    fun mathFunction(x: Int)
}

fun validationContext(x: Int, block: (Int) -> Unit){
    require(x > 0)
    block(x)
}

fun main() {

    val o = object : MathThing {
        override fun mathFunction(x: Int) {
            println(x)
        }
    }

    validationContext(-1, o::mathFunction)

}

Solution

  • the problem in your code, is that you don't actually call the o::mathFunction in a block. You rather just reference it. in this case it is just no-op.

    You can fix it by passing mathFunction as a param, or explicitly calling it inside the block:

    validateContext(1) {
        o.mathFunction(it)
    }
    // ok. => 1
    
    validateContext(1, o::mathFunction)
    // ok. => 1
    
    validateContext(-1, o::mathFunction)
    // validation error
    

    update

    the short answer is 'no'. you can't easily restrict that, unless your language has dynamically bound execution context.

    what you can try, is to throw error, analyze stacktrace and decide if it the needed context function is in call stack. But this would be really slow and painful.

    i would do something like this, to be sure the function is always validated

    val o = object : MathThing {
        override fun mathFunction(x: Int) = validateContext(x) {
            println(it)
        }
    }