The experienced JavaScript programmer is well versed in using anonymous functions. Since functions in JavaScript are a first-order concept, functions are passed around in JavaScript with abandon. Some even lament the callback hell of certain frameworks, but aesthetics aside, there can be no denying that anonymous functions are an important thing in JavaScript. So, the same must surely be true in Dart, right?
In JavaScript, an anonymous function omits the function name, using only the function keyword.
| function(i) { |
| if (i < 2) return i; |
| return fib(i-2) + fib(i-1); |
| } |
We have already seen that the only difference between JavaScript and Dart functions is that the latter do not have the function keyword. It turns out this is also the only difference between JavaScript and Dart anonymous functions.
functional_programming/fib.dart | |
| (i) { |
| if (i < 2) return i; |
| return fib(i-2) + fib(i-1); |
| } |
At first glance, that looks quite odd—almost naked. But that is just our JavaScript eye. Ruby has lambdas and procs that look very similar.
| { |i| $stderr.puts i } |
Given enough consideration, what purpose does the function keyword in JavaScript really serve? The knee-jerk reaction is that it helps to identify the anonymous function, but in practice, it is just noise.
Consider this Fibonacci printer:
| var list = [1, 5, 8, 10]; |
| list.forEach(function(i) {fib_printer(i)}); |
| |
| function fib_printer(i) { |
| console.log("Fib(" + i + "): " + fib(i)); |
| } |
| |
| function fib(i) { |
| if (i < 2) return i; |
| return fib(i-2) + fib(i-1); |
| } |
Does the function keyword help or hinder readability of the code? Clearly, it makes the situation worse, especially inside the forEach call.
Let’s consider the equivalent Dart code.
| var list = [1, 5, 8, 10]; |
| list.forEach((i) {fib_printer(i);}); |
| fib_printer(i) { |
| print("Fib($i): ${fib(i)}"); |
| } |
| fib(i) { |
| if (i < 2) return i; |
| return fib(i-2) + fib(i-1); |
| } |
Recipe 6 | Note: We are using the string interpolation trick first noted in Chapter 1, Project: Your First Dart Application to insert the value of the counter i into "Fib($i)". |
All that we did was remove the function keyword, and yet the intent of the code is much clearer. Multiply that effect across an entire project, and the long-term health of a codebase goes up dramatically.
Speaking of clarity, if curly braces make you cringe, there is a hash rocket syntax that can be used for simple functions. Instead of writing our anonymous iterator as (i) { fib_printer(i) }, we can write (i) => fib_printer(i). Thus, our code becomes as follows:
| var list = [1, 5, 8, 10]; |
| list.forEach((i) => fib_printer(i)); |
| fib_printer(i) { |
| print("Fib($i): ${fib(i)}"); |
| } |
| fib(i) { |
| if (i < 2) return i; |
| return fib(i-2) + fib(i-1); |
| } |
The argument (i) is repeated both in the definition of the anonymous function and in the call to fib_printer(i). In JavaScript, there is nothing to be done to clean that up. In Dart, however, the function (i) => fib_printer(i) can be further simplified as simply fib_printer.
| var list = [1, 5, 8, 10]; |
| list.forEach(fib_printer); |
| fib_printer(i) { |
| print("Fib($i): ${fib(i)}"); |
| } |
| fib(i) { |
| if (i < 2) return i; |
| return fib(i-2) + fib(i-1); |
| } |
That is a fantastic little shortcut to use with abandon in our Dart code.
3.137.216.175