Now that I know how to execute Dart locally, I am ready to begin poking through the language a bit. First, I would like to explore the different ways to write anonymous functions. Be they used for currying, partial application, or simple callbacks, anonymous functions are a must in any language. Interestingly, I have already seen two different formats in Dart. I wonder how many more there are...
The one that I have been using for the past two days is a sort of naked argument list followed by the function body inside curly braces:
main() { var list = [0,1,2,3,4]; list.forEach( (i) { print("Item: " + i); } ); }(try.dartlang.org)
That format is very reminiscent of Ruby blocks:
list = [0,1,2,3,4] list.each { |i| $stderr.puts "Item: " + i }To be sure, there are more curly braces and semi-colons in the Dart equivalent, but it is nice being able to drop the
function
keyword from the Javascript equivalent. If I save and run that Dart script, I get:
➜ command_line git:(master) ✗ dart iterator01.dart Item: 0 Item: 1 Item: 2 Item: 3 Item: 4Interestingly, it is possible to make this Dart code look even more Javascript-y with a "function" before the argument list:
main() { var list = [0,1,2,3,4]; list.forEach( function(i) { print("Item: " + i); } ); }(try.dartlang.org)
That "function" is not a keyword in dart however, it is the name of the function (in effect, I have named my function "function"). I could have called it "f":
main() { var list = [0,1,2,3,4]; list.forEach( f(i) { print("Item: " + i); } ); }(try.dartlang.org)
So what are those things? Named anonymous functions? Somehow that does not quite work. Named blocks? Maybe.
At any rate, they lend themselves to recursion nicely:
main() { var list = [0,1,2,3,4]; list.forEach( f(i) { print("Item: " + i); if (i > 0) f(i-1); }); }(try.dartlang.org)
Yah, it is pretty silly to do recursion in an iterator block, but still, it works:
➜ command_line git:(master) ✗ dart iterator04.dart Item: 0 Item: 1 Item: 0 Item: 2 Item: 1 Item: 0 Item: 3 Item: 2 Item: 1 Item: 0 Item: 4 Item: 3 Item: 2 Item: 1 Item: 0Just as in Javascript, it is possible to assign anonymous functions to variables:
var f = (i) {
print("Item: " + i);
};
var list = [0,1,2,3,4];
list.forEach(f);
(try.dartlang.org)And, yes, regular function naming works as well:
f(i) {
print("Item: " + i);
};
var list = [0,1,2,3,4];
list.forEach(f);
(try.dartlang.org)That pretty much covers this anonymous function format, but then there was also a hash rocket format that I encountered:
var list = [0,1,2,3,4];
list.forEach( (i) => print("Item: " + i) );
(try.dartlang.org)This compact format seems to only work with a single expression. That is, both of the following are syntax errors:
// wrong #1
var list = [0,1,2,3,4];
list.forEach( (i) =>
print("Item: " + i);
print(" " + i);
);
// #wrong #2
var list = [0,1,2,3,4];
list.forEach( (i) =>
print("Item: " + i)
print(" " + i)
);
(try.dartlang.org)The first fails on the semi-colon:
'/home/cstrom/repos/dart-site/examples/command_line/iterator10.dart': Error: line 4 pos 26: ')' expected print("Item: " + i); ^The second fails on the second print statement in what is supposed to be a single expression:
'/home/cstrom/repos/dart-site/examples/command_line/iterator10.dart': Error: line 5 pos 7: ')' expected print(" " + i) ^But it does work if I combine those two statements into a function that can be called as a single expression:
var list = [0,1,2,3,4];
double_print(i) {
print("Item: " + i);
print(" " + i);
}
list.forEach( (i) => double_print(i) );
(try it on try.dartlang.org)Checking through the language specification, it seems like those two formats (argument list + block and hash-rocket + expression) are the two available anonymous function formats allowed in Dart.
While looking through the language specification, I notice that there do appear to be optional arguments. While messing about, I had tried a Ruby-ish:
f(i, j=0) { /* ... */ ]But that had not worked. Looking through the formal specification, I do not see any examples of optional arguments, but some of the discussion seems to show optional arguments inside square brackets:
main() { pretty_int(i, [label="Number: "]) { print(label + i); } pretty_int(1); pretty_int(42, "Answer to everything: "); }(try it on try.dartlang.org)
And that does seem to work as expected:
➜ command_line git:(master) ✗ dart optional_arg.dart Number: 1 Answer to everything: 42With a pretty good handle of functions under my belt, I call it a night here. Up tomorrow, I think that I will play with currying functions in Dart. I love me some good currying.
Day #251
Good article, keep them coming. Note though that Dart has string interpolation so you can do print("Item: $i") (or print("Item: ${i}")) instead of concatenating string using +.
ReplyDeleteThanks for the interpolation hint. I prefer Ruby's hash ("Item: #{i}") to Dart's dollar sign, but maybe I'll get used to it :)
ReplyDeleteNow if only Dart supported sprintf interpolation...
The => syntax is more or less equivalent of a lambda in Python. It evaluates a expression and returns the result. From the spec: "A function body of the form => e is equivalent to a body of the form {return e;}".
ReplyDeleteIt is mostly used for short method definitions:
class Foo {
int bar() => 1;
int baz() => 2;
}
Here are some other fun anon functions: http://try.dartlang.org/s/xpkl
ReplyDeleteOnly String gives a warning in non checked mode.
Also, for the simplest anonymous function, you can omit the function name:
ReplyDeletelist.forEach( (i) { print("Item: " + i); } );
Here: http://try.dartlang.org/s/K4Yl
google 1727
ReplyDeletegoogle 1728
google 1729
google 1730
google 1731
google 1732
Best Part-Time MBA Colleges in Mumbai, Direct MBA Admissions
ReplyDeleteMBA Rendezvous