2

Scala type inference is really nice and it is easy to get used not to have to write things twice. The more it hurts when you have to. One such example are function types.

Sometimes I would like to create a named type for some function signature. Is it possible somehow? Is there some way to get the compile-time type of the function so that I do not have to type it again when defining FType?

object Foo {
  def f(a:Int, b:Int, x:Double, y:Double, name:String) : Unit = {}

  //type FType = typeOf(f) // can compiler provide me a compile time type somehow?
  type FType = (Int,Int,Double,Double,String) => Unit

  def callF( func:FType) = func(0,0,0,0,"")
}

Is there something like C++ decltype in Scala which could be used for this purpose?

Suma
  • 33,181
  • 16
  • 123
  • 191

1 Answers1

2

I'm not quite sure what you're trying to achieve here, if I understand correctly you want to avoid typing (a:Int, b:Int, x:Double, y:Double, name:String) two times.

What about defining FType yourself upfront and then simply reusing it in f and callF?

object Foo {
  type FType = (Int,Int,Double,Double,String) => Unit

  def f: FType = (a, b, x, y, name) => ()

  def callF(func: FType) = func(0,0,0,0,"")
}

If you actually want to abstract over FType, it's a significantly different problem, but it doesn't seem to be the case as you're forcing the type by calling func(0,0,0,0,"").

You don't have decltype in Scala because types are not first class citizens like they can be in Idris for example. That said, you should be able to write it using Shapeless and/or macros.

If you want to fix the types and the arguments and reuse them, the simplest solution is to turn them into a case class. You can then use import to access your fields directly:

object Foo {
  case class FArgs(a: Int, b: Int, x: Double, y: Double, name: String)

  def f(args: FArgs): Unit = {
    import args._
    println(name) // or whatever you want to do
  }

  def callF(func: FArgs => Unit) = func(FArgs(0,0,0,0,""))
}
blouerat
  • 692
  • 4
  • 12
  • 2
    This is definitely improvement, but still I have to write this `(a, b, x, y, name)` which is kind of repeating myself. Inferring `FType` from `f` instead would avoid this, but I guess this is not possible. – Suma Mar 13 '15 at 15:37
  • .. and no, I do not want to abstract over `FType`, I just want to avoid repeating myself when defining `f` and the callback type used for it. – Suma Mar 13 '15 at 15:46
  • 1
    If you want to define multiple functions with type `FType` and you want them not only to be of the same type but also to have the same arguments names, that's the only repetition I can think of, then you should simply define a case class. Something like `case class FArgs(a: Int, b: Int, x: Double, y: Double, name: String)` – blouerat Mar 13 '15 at 15:56
  • case class is definitely a nice idea. A little drawback they have is one has to access the parameters using dot operator in the case class, but this seems reasonable. There might be performance implications as well (more objects created and garbage collected), but they should be acceptable for most code. – Suma Mar 13 '15 at 17:04
  • I have wrote a [separate question on decltype](http://stackoverflow.com/questions/29038214/why-scala-does-not-have-a-decltype), as I think is related, but not the same as this question. – Suma Mar 13 '15 at 17:15
  • It does not come for free but the objects should be pretty short-lived so your GC should handle it pretty well in most cases. If you don't want to use dots to access properties, you can use `import args._` and then access all its properties directly. – blouerat Mar 13 '15 at 18:26
  • 1
    With import args._ it sounds like a great solution. Would you care incorporating that approach into the answer? – Suma Mar 13 '15 at 18:44
  • Added the case class solution to my answer, what do you think of it? – blouerat Mar 14 '15 at 10:29