I would like to create a function with the following signature:
def myFunction[T](functionWithName: (String, => T)): T
so that I can call it, e.g., like this: val x = myFunction("abc" -> 4 * 3). Tuple doesn't accept by-name parameter, however, so the signature above is invalid.
Inspired by this answer, I tried the following implicit conversion:
implicit class ByName[T](getValue: => T) extends Proxy {
def apply(): T = getValue
def self = apply()
}
def myFunction[T](functionWithName: (String, ByName[T])): T = {
// do something
functionWithName._2()
}
The implicit doesn't work in this case, however (unlike in the linked answer).
ByName doesn't work? myFunction("abc" -> 4 * 3) where 4 * 3 is passed by name?I have two proposals to implement this:
Make whole tuple by-name: functionWithName: => (String, T)
Make your own class:
class MyTuple[A, B](a: A, b: => B) {
def _1: A = a
def _2: B = b
def toTuple = a -> b // optional
}
and have a custom implicit method somewhere, like -> for Tuple2 (see ArrowAssoc in Predef):
implicit final class ArrAssoc[A](private val self: A) extends AnyVal {
@inline def -->[B](y: => B): MyTuple[A, B] = {
new MyTuple(self, y)
}
}
Then you could say this:
val t = 1 --> { println("blah"); 5 }
//t._2
//t.toTuple
The b parameter should not be evaluated until you call t._2
Or even make toTuple imlicit conversion, so when Tuple2 is espected you can pass a MyTuple...