12

Lets say I have a class C with some methods

def class C {
  def f1():Int = ...
  def f2():Int = ...
}

Now I'd like a method that takes two instances of C, as well as a method of C, but I don't know what the types of f1, f2 are, nor how to invoke them. I'm thinking it would look something like

def cmp(first:C, second:C, t:() => Int): Boolean = {
  first.t < second.t
}

This complains that t is not a method of C. Surely there must be a way to express this.

Mike Kraley
  • 415
  • 1
  • 4
  • 12

3 Answers3

15
def cmp(first:C, second:C, t: C => Int): Boolean = {
  t(first) < t(second)
}

Then...

val c1 = new C
val c2 = new C
cmp(c1, c2, _.f1())
cmp(c1, c2, _.f2())

This is using anonymous functions. The last two lines are equivalent to:

cmp(c1, c2, {c: C => c.f1()})
cmp(c1, c2, {c: C => c.f2()})

You can't pass a reference to a method per se unless you use some kind of reflection.

ghik
  • 10,706
  • 1
  • 37
  • 50
  • 2
    Actually both answers are very good - thank you! But I accepted this one, since it is the one I actually used. – Mike Kraley Jul 02 '13 at 01:54
9

You can just pass the method references instead:

object DoOperation extends App {

  class C(val x: Int) {
      def f1():Int = x-1
      def f2():Int = x+1
   }


  def cmp(first: () => Int, second: () => Int): Boolean = {
    first() < second()
  }

  override def main(args: Array[String]) {
      println(cmp(new C(1).f1,new C(0).f2)) //prints "true"
      println(cmp(new C(1).f2,new C(1).f1)) //prints "false"
  }

}

The methods will be closed over their corresponding object instances, so the net effect is the equivalent to what you appear to want to accomplish.

mikołak
  • 9,605
  • 1
  • 48
  • 70
0

This approach may also work:

@ class myClass {
    def double(x: Int): Int = x * 2
    def triple(x: Int): Int = x * 3
  }
defined class myClass

@ val instance = new myClass
instance: myClass = ammonite.$sess.cmd0$myClass@4195105b

@ def callArbitraryMethod(instance: myClass, f: (myClass, Int) => Int, x: Int): Int = f(instance, x)
defined function callArbitraryMethod

@ val f = (instance: myClass, x: Int) => instance.double(x)
f: (myClass, Int) => Int = ammonite.$sess.cmd3$$$Lambda$1965/11731022@3b8b4846

@ callArbitraryMethod(instance, f, 10)
res4: Int = 20
Michael Stokley
  • 159
  • 1
  • 3