Let\'s say I have a class and I want to make its methods chainable, I could do something like this:
class MyClass {
def methodOne(arg1: Any): MyClass = {
It's easy to implement makeChainable
for unary function, but it gets hairy if you want to support higher arity. The only way I can see to do method two, unless you want to write a separate makeChainable
for every arity, is to tuple the method, pass it through makeChainable
, and then untuple it.
class MyClass {
def methodOne: Any => MyClass = makeChainable {
(arg1: Any) => println("doing stuff")
}
def methodTwo: (Any, Any) => MyClass = Function untupled makeChainable {(
(arg1: Any, arg2: Any) => println("doing other stuff")
).tupled}
def makeChainable[A](f: (A) => Unit): (A => MyClass) = { a: A => f(a); this }
}
new MyClass().methodOne("a").methodTwo("b", "c")
But - and please forgive me for opining - invocation chaining is generally a shortcut you take in other languages that are less expressive than Scala. Unless you're doing this to make an API for Java users, I think this is a really bad idea.
Here's one alternative, which I still would never do, to accomplish roughly the style you're going for in a way that's less invasive:
class MyClass {
def methodOne(a: Any) { println("doing stuff") }
def methodTwo(a: Any, b: Any) { println("doing other stuff") }
def apply(fs: (MyClass => Unit)*) { fs.foreach(f => f(this)) }
}
new MyClass()(_.methodOne("a"), _.methodTwo("b", "c"))
Edit:
A more elegant way would be to define a "kestrel combinator". I do think this approach is legit :)
class MyClass {
def methodOne(a: Any) { println("doing stuff") }
def methodTwo(a: Any, b: Any) { println("doing other stuff") }
}
implicit class Kestrel[A](x: A) {
def ~(f: A => Unit): A = { f(x); x }
}
new MyClass() ~ (_.methodOne("a")) ~ (_.methodTwo("b", "c"))