Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass an optional closure parameter to a function?

Tags:

scala

I would like to pass a closure to a method as an Option and I am doing what is shown below. I get a compile error as shown below. Is it possible to pass an optional closure parameter to a function?

def sampleMethod(a: String, b: String, optionalMethod: Option[(String, Int) => Unit]) {
    // do some processing with a and b
    optionalMethod match {
      case Some(optionalMethod) => {
        optionalMethod("a",3)
      }
      case _
      log("no optional method passed")
    }
}

// definition of optMethod in some other place
val optMethod = (c: String, d: Int) => {
  // some processing with c, d and external values 
}

// invoke
sampleMethod("hi", "bye", optMethod) => FAILS TO COMPILE

ERROR = type mismatch. expecting Option[(String, Int) => Unit] found (String, Int) => Unit
like image 351
Sriram Subramanian Avatar asked Feb 08 '13 14:02

Sriram Subramanian


People also ask

Can a closure be passed parameters?

Because closures can be used just like strings and integers, you can pass them into functions.

Why optional closures are escaping?

It doesn't make sense to add escaping annotations to optional closures because they aren't function types: they are basically an enum (Optional) containing a function, the same way you would store a closure in any type: it's implicitly escaping because it's owned by another type.

Can a closure be assigned to a variable?

Said differently, a closure is a block of code that you can assign to a variable. You can then pass it around in your code, for instance to another function. The function then calls the closure and executes its code, as if the closure is an ordinary function.


3 Answers

The error message is pretty explicit: sampleMethod expects an Option, but you are passing a straight function value (not wrapped in Some).

The simplest way to fix this is to wrap optMethod into a Some:

sampleMethod("hi", "bye", Some(optMethod))

But if you want to be able to simply do sampleMethod("hi", "bye", optMethod), you could add overloaded definitions of sampleMethod:

object Test {
  def sampleMethod(a: String, b: String, optionalMethod: Option[(String, Int) => Unit]) {
    // do some processing with a and b
    optionalMethod match {
      case Some(optionalMethod) => {
        optionalMethod("a",3)
      }
      case _ => log("no optional method passed")
    }
  }
  def sampleMethod(a: String, b: String) { sampleMethod(a, b, None) }
  def sampleMethod(a: String, b: String, optionalMethod: (String, Int) => Unit) {
    sampleMethod(a, b, Some(optionalMethod)) 
  }
}

val optMethod = (c: String, d: Int) => {
  // some processing with c, d and external values 
}

// invoke
Test.sampleMethod("hi", "bye", optMethod) // Now Compiles fine
Test.sampleMethod("hi", "bye") // This too
like image 57
Régis Jean-Gilles Avatar answered Oct 17 '22 23:10

Régis Jean-Gilles


As pointed out earlier, your method expects an Option value containing the optionalMethod. You must hence pass an Option value to it:

// invoke with method
sampleMethod("hi", "bye", Some(optMethod))
// invoke without method
sampleMethod("hi", "bye", None)

If you want to avoid the Option value (esp. avoid the None), you can try the following:

def sampleMethod(a: String, b: String, optionalMethod: (String, Int) => Unit = (_, _) => log("no optional method passed")) {
  optionalMethod("a", 3)
}

// invoke with method
sampleMethod("hi", "bye", optMethod)
// invoke without method
sampleMethod("hi", "bye")
like image 43
Fynn Avatar answered Oct 18 '22 01:10

Fynn


How about

sampleMethod("hi", "bye", Some(optMethod))
like image 3
Wilfred Springer Avatar answered Oct 18 '22 01:10

Wilfred Springer