3

I want to write a case class that can take in a function that has one or more Ints as its arguments. For instance, these would be valid functions:

def foo(x: Int): String = "foo"
def bar(x: Int, y: Int): String = "bar"
def foobar(x: Int, y: Int, z: Int): String = "foobar"

but this would not:

def nonExample():String = "no"

The problem is that I can't get the right argument type for my case class.

case class Mine(function: ???) {}

I've tried:

case class Mine(function: (Int*) => String)

and this didn't work since (Int*) is a sequence of Ints. I also tried using Function and Function1, but that didn't work either. Any ideas (or alternatives if this isn't possible in Scala)?

Edit: As Didier Dupont mentioned, Mine also needs to know how many arguments the method requires. Above I oversimplified Mine. It will also take another argument that tells about the function passed in. Based on that, it'll decide how many parameters to pass into the function. But other than that chunk of code, everything else in Mine operates the same regardless of the function.

9
  • My first thought is this isn't possible, but Scala always surprises me. :) Commented Jul 17, 2014 at 20:56
  • Function1, Function2, etc.. don't share a useful common trait, so I have serious doubts about it working without some magic. Commented Jul 17, 2014 at 21:06
  • Btw, methods can not be passed around, functions can. Commented Jul 17, 2014 at 21:14
  • 2
    How do you intend to use class Mine then? As you will not know how many arguments the method requires, it will be difficult to call it. Commented Jul 17, 2014 at 21:21
  • case classes are generally meant to be value containers more than anything really, a perfect example is the Either type. It has Left and Right as its possible values, each only supposed to hold a single value. It doesn't make a whole lot of sense to pattern match against something that has multiple one-parameter versions of itself, as it all ends up looking the same after erasure Commented Jul 17, 2014 at 21:26

3 Answers 3

3

I would recomend next solution (it has some disadvantages, but generaly it satisfy your needs)

sealed trait FuncRes[F] {
  def resolve : F
}

object FuncRes {
  implicit def func1[T1, R](f : T1 => R) = 
    new FuncRes[(T1 => R)] {
      def resolve = f
    }

  implicit def func2[T1, T2, R](f : (T1, T2) => R) =
    new FuncRes[((T1, T2) => R)] {
      def resolve = f
    }

  implicit def func3[T1, T2, T3, R](f : (T1, T2, T3) => R) = 
    new FuncRes[((T1, T2, T3) => R)] {
      def resolve = f
    }
}

case class Mine[F](private val f : FuncRes[F]) {
  def func[F] = f.resolve
}

and usage example:

def foo(x: Int): String = "foo"
def bar(x: Int, y: Int): String = "bar"
def foobar(x: Int, y: Int, z: Int): String = "foobar"

val m1 = Mine(foo _)
println { m1.func(10) }              // output: "foo"

val m2 = Mine(bar _)
println { m2.func(10, 20) }          // output: "bar"

val m3 = Mine(foobar _) 
println { m3.func(10, 20, 30) }     // output: "foobar"
Sign up to request clarification or add additional context in comments.

1 Comment

This is an interesting solution, Yury. Note to anyone else interested: With FuncRes, this is how you would actually pass foo, bar, and foobar into Mine: val m1 = Mine(FuncRes.func1(foo)), and so forth.
0

How about (Int, Int*) => String? You would receive the second argument as a Seq[Int].

1 Comment

Unfortunately, this doesn't work. I tried it in the repl and for foo, bar, and foobar there were all type mismatches.
-1

Why not using a function Array[Int] => String? Varargs are essentially array so it should fit.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.