Reputation: 682
Is it possible to call an object method without parentheses, after import it ?
Here is my test code, based on this article by Martin Odersky:
package gardening.fruits
object PrintPlanted {
def main(args: Array[String]) {
// Call method on object
import gardening.fruits
fruits showFruit(apple)
fruits showFruit apple
// Import object
import gardening.fruits._
showFruit(apple)
// showFruit apple
// Error: missing arguments for method showFruit in package fruits;
// follow this method with `_' if you want to treat it
// as a partially applied function
}
}
After importing the package object fruits
, I can call the method showFruit(apple)
, but is there any way to call the method without parentheses like the last of the code ?
I use such of methods in a little DSL and it is a bit annoying to use parentheses. All your suggestions are welcome.
Upvotes: 4
Views: 956
Reputation: 22471
Well, almost anything in Scala is doable:
package object fruits {
val planted = List(apple, plum, banana)
import scala.language.dynamics
object showFruit extends Dynamic {
private val lookupFruit = planted
.map(f => (f.getClass.getSimpleName, f)).toMap;
def applyDynamic(name: String)(args: Any*) = {
realShowFruit(lookupFruit(name+"$"));
}
private def realShowFruit(fruit: Fruit) = {
println(fruit.name + "s are " + fruit.color)
}
}
}
Will make your code work.
We are replacing the original showFruit
method with an object. This object happens to be Dynamic, so:
showFruit apple ~~> showFruit.applyDynamic("apple")([Some param, see below])
Which means that we are not receiving the apple
object, we are dealing with an "apple"
(String
).
So we need to lookup fruits according to their string names. I'm using a map and some nasty Java Reflection for this :). The apple
object is actually gardening.fruits.apple$
, so our f.getClass.getSimpleName
approach works.
Well, now that you know how to do what you want, please don't. This is actually a really broken workaround simulating post fix operator syntax (which is, by itself, not advisable) .
This will put you in all sorts of trouble. Say you want to use your method like this:
def main(args: Array[String]): Unit = {
import com.sevenrtc.testreflection.fruits._
showFruit apple // won't compile
}
But this compiles:
def main(args: Array[String]): Unit = {
import com.sevenrtc.testreflection.fruits._
showFruit apple
println("Will compile!");
}
Why? For the same reason that this compiles:
def main(args: Array[String]): Unit = {
import com.sevenrtc.testreflection.fruits._
showFruit apple
()
}
The result of println
(which is ()
) is actually being passed to applyDynamic
. So the first example is equivalent to:
showFruit.apple(println("Will Compile!"))
Upvotes: 3
Reputation: 67290
No that is not possible. e1 op e2
is a so-called infix operation and equivalent to e1.op(e2)
. This does not work when the receiver (e1
) is left out. For the same reason you can't write things like println "hello"
, either.
Upvotes: 3