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
...