Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: how to implement via function object parameters a generic flow where signatures differ?

I am a Java programmer taking baby steps into Scala programming.

I have defined a function similar to (which may be idiomatically wrong, I wouldn't know...):

def someGenericAlgorithm(param1: String, param1: String, param3: String) = {

    val triedResult1 = someFunction(param1)
    triedResult1 match {
      case Success(result1) =>
        val triedResult2 = someOtherFunction(param2)
        triedResult2 match {
          case Success(result2) =>
            val triedPolymorphicResult = someToBeReplacedAccordingToSpecificLogicFunction(result1, result2, param3)
            triedPolymorphicResult match {
              case Success(polymorphicResult) =>
                doSomethingGeneric(polymorphicResult)                    
                ....
              case Failure(exception) =>
                ....
            }
          case Failure(exception) =>
            ....
        }
      case Failure(exception) =>
        ....
    }
  }

So the function receives 3 parameters, processes the first two in sequence, takes the results of the processing and passes it along to the someToBeReplacedAccordingToSpecificLogicFunction along side the third parameter.

Now I wish to write a similar function in that the first two function calls are present, the error logic is the same, and the only difference is that the someToBeReplacedAccordingToSpecificLogicFunction is now aReplacementLogicFunction instead.

Had the two functions had the same signature, I guess that would not have been a problem, but, they do not, the aReplacementLogicFunction has different parameters, more specifically, two more parameters. You may say then, that I could just pass in Option parameters where these two Options are Nones in the first case and in that way I would have aligned my two functions to be of the same signature, thus:

def someToBeReplacedAccordingToSpecificLogicFunction(result1: Int, result2: Int, param3: String, unused1:Option[String] = None, unused2:Option[String] = None)

def aReplacementLogicFunction(result1: Int, result2: Int, param3: String, used1:Option[String], used2:Option[String])

But, a third flow exists where the nonexistent arguments of the first function are of a different kind, say MyClass, e.g.:

def anotherReplacementLogicFunction(result1: Int, result2: Int, param3: String, used1: MyClass, used2: MyClass)

The question is, then, how would I generify these functions to be passed along to some refactored generic algorithm function that would receive a function as a parameter. Is there a way to define something like:

def refactoredOutCoreLogic(param1: String, param1: String, param3: String, polimorphicFunction: SignatureUnknown)

To answer my own question in Java:

The way in which I would have solved this in Java is to have defined a class hierarchy akin to:

abstract class ResultKeeperRunnable implements Runnable {
    protected int param1, param2;
    void setParam1(...) {...}
    void setParam2(...) {...}
}

class SomeToBeReplacedAccordingToSpecificLogicFunctionClass extends ResultKeeperRunnable  {
    String param3;
    // ctor receiving all params omitted for brevity 
    void run() {
      // do specific Logic
    }
}

class AReplacementLogicFunctionClass extends ResultKeeperRunnable {
    String param3, param4, param5;
    // ctor receiving all params omitted for brevity 
    void run() {
      // do specific Logic
    }
}

class AnotherReplacementLogicFunctionClass extends ResultKeeperRunnable {
    String param3;
    MyClass param4, param5;
    // ctor receiving all params omitted for brevity 
    void run() {
      // do specific Logic
    }
}

Finally the factored out core logic method would be something like:

void refactoredOutCoreLogic(String param1, String param2, String param3, ResultKeeperRunnable polimorphicLogic) {
    // error handling logic removed for brevity
    int result1 = someMethod(param1);
    int result2 = someOtherMethod(param2);
    polymorphicLogic.setParam1(result1);
    polymorphicLogic.setParam2(result2);
    polymorphicLogic.run()
    ...

}

Will the Scala solution, be no more of a syntactically different clone of the Java solution presented above? It seems as if there should be a more elegant solution.

like image 354
Yaneeve Avatar asked Feb 12 '15 07:02

Yaneeve


1 Answers

You have a function that takes result1, result2, and a bunch of other parameters.

You want a function that just takes result1 and result2.

To do this, use partial application. Write your replaceable functions curried like this with a second set of parentheses at the end holding the common parameters:

def aReplacementLogicFunction(param3: String, used1:Option[String], used2:Option[String])(result1: Int, result2: Int)

Then pass the partially applied function into your common function like this:

someGenericAlgorithm(param1, param2, aReplacementLogicFunction(param3, used1, used2))

As far as the generic algorithm is concerned, it has absolutely no knowledge of the extra parameters. Those are all applied before calling the function.

like image 76
Karl Bielefeldt Avatar answered Oct 05 '22 22:10

Karl Bielefeldt