Rares Dima
Rares Dima

Reputation: 1767

Kotlin accessing an abstract function in a non abstract function in abstract class

I have a class that is basically this:

abstract class BaseContinuousSingleObjectiveFitnessFunction {

    // Invoke should compute some function, like f(x) = x^2 + 3x + 5
    abstract fun invoke(x: List<Double>): Double

    // This is supposed to return an object deriving this one where 
    // invoke actually returns 1/(1+f(x)), essentially reversing the function.
    fun reverse(): BaseContinuousSingleObjectiveFitnessFunction =
            object: BaseContinuousSingleObjectiveFitnessFunction() {
                override operator fun invoke(x: List<Double>): Double {
                    var denominator = 1.0 + super.invoke(x)
                    if (denominator.absoluteValue < Double.MIN_VALUE * 10)
                        denominator += denominator.sign * Double.MIN_VALUE * 10

                    return 1.0 / denominator
                }
            }
}

Problem is that invoke is abstract so the compiler complains that Abstract member cannot be accessed directly. which is true.

However any class deriving my class will obviously be forced to implement invoke so conceptually there should no problem with calling reverse in those classes but having the implementation in this base class. The implementation of reverse while strictly speaking is dependent on invoke, this implementation can not be called in any class that does not also provide an invoke anyway.

The simplest solution is to duplicate the code for reverse in every class but i'd rather not have code duplication.

So my question is what exactly is an elegant way of doing what I want: providing a well-defined behaviour (reverse) that uses behaviour not defined yet (invoke) but that will 100% be defined at the time when reverse is called?

Upvotes: 0

Views: 522

Answers (1)

Ryan M
Ryan M

Reputation: 20157

The problem is that super.invoke(x) is trying to call the super method of the object that derives directly from BaseContinuousSingleObjectiveFitnessFunction. Since there's no super implementation, you get the error. You probably want to hold a reference to the original function:

    fun reverse(): BaseContinuousSingleObjectiveFitnessFunction {
        val originalFunction = this
        return object: BaseContinuousSingleObjectiveFitnessFunction() {
            override operator fun invoke(x: List<Double>): Double {
                var denominator = 1.0 + originalFunction.invoke(x)
                if (denominator.absoluteValue < Double.MIN_VALUE * 10)
                    denominator += denominator.sign * Double.MIN_VALUE * 10

                return 1.0 / denominator
            }
        }
    }

Upvotes: 2

Related Questions