views:

174

answers:

3

Let's say I have a method expecting another method as a parameter. Is it possible to send an object's instance methods for that parameter? How would I handle methods that have no parameters?

I'll write some pseudocode:

void myMethod1(callback<void,int> otherFunc); // imagine a function returning void, and taking a int parameter

void myMethod2(callback<int,void> otherFunc); // function returning void, not taking params

if for example I have an ArrayList, like this:

val a = new ArrayList()

how could I send it's add method as parameter for myMethod1, and it's size method as parameter for myMethod2?

+3  A: 
def myMethod(callback : Int => Unit, size : => Int) = ...

myMethod(a.add _, a.size)

Void is represented through the type Unit.

Edit: Through the above use of => Int, size is passed by name which means it's always re-evaluated when needed.

Dario
Isn't it possible to reference `a.size` and invoke it whenever needed?
Geo
Do you mean passing size:Int by name?def myMethod(callback: Int => Unit, size: => Int)
davetron5000
+3  A: 

I think myMethod4 may be what you mean when you say: "Isn't it possible to reference a.size and invoke it whenever needed?".

def myMethod1(f: Int => Unit): Unit = f(1)

def myMethod2(f: () => Int): Unit = {
  val value = f // f is function, taking no arguments, and returning an int.
                // we invoke it here.
  ()
}

def myMethod3(f: => Int): Unit = {
  val value = f // f is call by name parameter.
  ()
}

def myMethod4[A](f: A => Int, a: A): Unit = {
  val value = f(a)
  ()
}

import java.util.ArrayList

val a = new ArrayList[Int](1)
myMethod1((i: Int) => a.add(i))
myMethod1(a.add(_))     // shorthand for the above
myMethod2(() => a.size) // a.size is not evaluated, it is enclosed in an anonymous function definition.
myMethod3(a.size)       // a.size is not evaluated here, it is passed as a by-name parameter.
myMethod4((al: ArrayList[Int]) => al.size, a)
myMethod4((_: ArrayList[Int]).size, a)
myMethod4[ArrayList[Int]](_.size, a)
retronym
can you please explain how the empty parantheses work in method2/3/4 ?
Geo
A block `{a; b; c}` must contain a sequence of expressions and declarations (var, val, class, function, trait, object). It must finish with an expression. For clarity, I assigned the result of `f` to a val `value`, so I needed to follow this with an expression that conforms the the expected type of the block, which in this case is the declared type of the function: `Unit`. `()` is the one and only instance of the type `Unit`. An empty `return` would also work. As would an expression of any other type, as any value can be converted to type `Unit`.
retronym
+3  A: 

The type of a function in Scala is denoted

(Types,To,Pass) => ReturnType

(you can leave off the parens if there is only a single type to pass), and the way to convert a method into a function to pass to another method is

myObject.myMethod _

So, putting these together--and paying attention to the types of the Java classes:

scala> def addMySize(adder: Int => Boolean, sizer: () => Int) = adder(sizer())
addMySize: ((Int) => Boolean,() => Int)Boolean

scala> val a = new java.util.ArrayList[Int]()
a: java.util.ArrayList[Int] = []

scala> addMySize(a.add _, a.size _)
res0: Boolean = true

scala> addMySize(a.add _, a.size _)
res1: Boolean = true

scala> println(a)
[0, 1]

(Note that ArrayList has an add that takes an object and returns a boolean--not one that returns void.)

Rex Kerr