By-Name vs By-Value method parameters
I’ve been spending some time trying to wrap my mind around the craziness that is by-name and by-value parameters in Scala. The syntax looks super weird when you first look at it. Just to quickly show you the difference, take a look at how you define by-name parameters:
def incNumberByName(x: => Int)
and here’s the by-value (the version us without a PhD in programming languages understand a little better):
def incNumberByValue(x: Int)
or, maybe we want to be able to pass some function that returns an int. like:
def incNumberByValue(x: () => Int)
There are a couple of things that were originally hard to grasp about this:
- What does passing a parameter by-name even do?
2. When the hell are you supposed to use by-name parameters? Just reading through scala source code, you’ll find them all over the place. But if you’re anything like me, trying to understand a lot of jvm-world source code is an extremely esoteric exercise. We need more concrete, practical examples to see why they’re useful.
Hopefully answering both of these questions will dispel some of this scala wizardry!
What does passing by-name even do?
Read this, it will help you understand various “evaluation strategies” for how parameters are passed to methods. Evaluation strategies just refers to how and when values given to your function are….well…..evaluated.
What does that mean? In short, some languages evaluate a function argument before they are used and some evaluate them when they are used within the function.
Passing by-name means, simply, that the parameter you pass to your function is evaluated each time it is used, and only when it is used within the function.
When are you supposed to use by-name, then?
If you need to pass a function as an argument to another, and you might infrequently call the function being passed. Take a look at this example:
trait Logger {
def debug(msg: => String)
def info(msg: => String)
def warn(msg: => String)
}
msg
is a by-name parameter, returning a String. Logging is a very typical thing, but what if we pass a very costly function to debug
? We don’t want have the compiler evaluate that argument right where it’s defined, especially if we set our log level in our application to info
. We get some nice performance savings by doing it this way!
One other great use case is for just making the way we pass arguments look more readable. Something like this:
def isBestMeme(compare: => Boolean) = {//figure out if this meme is the best}
def isBestMeme(compare: () => Boolean) = ???
it’s a little nicer to be able to write:
isBestMeme(meme1.score > meme2.score)
instead of:
isBestMeme(() => meme1.score > meme2.score))
don’t you think?
Summary
Ok, so by name parameters are pretty cool. They enable us to write slightly more readable code, because we can pass function bodies directly to methods that define by-name parameters! they also enable us to write code more efficiently — if we have functions that are costly to compute and aren’t used very frequently — it might make more sense to pass these arguments by-name rather than by-value.
Let me know if I missed any uses, or if you have any cool practical examples of using by-name parameters!
P.S. This was a great resource for learning more about by-name parameters in Scala. In fact, this entire blog is a gold mine so check it out!