Type-dependent Closures is a bit unclear as to what it’s communicating. Certainly it describes closures, but mostly talks about how the syntax shown results in evaluation at a time different than what you might think.
Suppose you wish to create a logging framework that encourages detailed and dynamic log messages (e.g.
"You tried to access port " + port + " of url " + url + "and got the error " + error). In Java, you would wrap messages like this in an
if statement that checks to see if the runtime logging level is sufficient to generate the message before you actually construct it.
In Scala, we can use closures to achieve this without any complicated conditionals around our logging statements.
Note that the log level is not sufficient to generate debug messages. When this program runs, we see, via our
breadcrumb method that the “RED ALERT” message was created (and printed), but also that the message passed to the
javaDebug method was created (and not printed), but not the messages in the other two
This is because the log message’s parameters are ‘’pass by name’’. This means that the parameters aren’t evaluated until they are need (and not evaulated if they aren’t). For the debug messages, these blocks don’t get called. (and thus, our complicated string concatenations don’t execute).
=> String is different than
() => String; the first form indicates a pass-by-name parameter that evaluates to a
String is expected, while the second indicates a function taking no arguments and returning a
String is expected. This is subtle on two levels. First, we can pass in a closure (a block of code) and it won’t be evaluated until it’s called. Secondly, a block code taking no parameters seems very similar to a function taking no parameters.
Note that the closures have access to the scope in which they were created. If we were to set the log level to 10, the output would be:
BREADCRUMB This is a simple debug message... BREADCRUMB This is a complicated debug test debug message... BREADCRUMB This is a mucho complicated debug test debug message... BREADCRUMB RED ALERT...
Notice how the value of “complex” changes between the calls, and the closures use the correct value. In Java, this would not be possible; the variables would have to be declared
We can take this to the next level by applying FunctionCurrying . Suppose we wanted to bring back the ternary operator that Scala doesn’t seem to include.
So, we define a method named
? that takes three expressions. The first must evaluate to a boolean, and the second two must evaluate to the same type (that we don’t know). When the method is called, we evaluate the first expression. If it returns true, we evaluate the second expression, otherwise we evaluate the third.
Note that since these are pass-by-name closures, only one of the second two expressions will get evaluated.
My Thoughts on this Feature
Closures are solid gold. Money. I love them and all they do, and this is one of the top reasons to use Scala. While the second example of adding in generics and currying certainly stretches some bounds, it demonstrates how Scala’s (often weird) syntax can be used to extend the language and make it appear to have new control structures and keywords.