An anonymous functions have several important properties:
The last point could use some further elaboration. Looking up a name “lexically” means that you determine its referent using a specific context (or scope). A context is an assignment of names to values. The lexical context is the context where an object is defined. A function that captures such a context is called a closure. In practical terms, using lexical scope means that you can tell the identity of an identifier by looking at your source code. If a name is used in a function, first you check if it’s local or a parameter. If not, then you look to the enclosing block. If the enclosing block doesn’t define it, then you keep looking outwards until you reach the global top-level. Some languages have simple scope hierarchies: C has a fixed number of levels (it’s either three or four). Today’s nine languages all support many levels. That said, let’s bring out the contestants.
Today’s Contestants
Java bursted out of Sun in 1994. A systems language cleverly retargeted and marketed for the web, Java soon became the de-facto standard object oriented language. (C++ doesn’t count, “C++ pretends to provide an object-oriented data model, C++ programmers pretend to respect it, and everyone pretends that the code will work,” Guy Steele coauthor of the Java Language Specification.) Though Java doesn’t have anonymous functions per se, it does have anonymous inner classes. Again Guy Steele, “when anonymous inner classes were introduced into Java, we had a full implementation that made them act like closures. We got push-back from users.” Despite the push-back, from the right base class, function-like inner classes are readily obtained.
JavaScript first appeared in Netscape Navigator at the end of 1995. Infamous for popups, cross-browser incompatibility, and being mistaken for Java, JavaScript has cleaned up its act. With the emergence of web-standards, JavaScript’s semantics was refined by the ECMA-262 spec earning JavaScript it’s official title: ECMAScript. Standing alone as a popular scripting language with a formal spec, ECMAScript was realized as ActionScript in Macromedia Flash and even found its way into Adobe Photoshop. Professionally, JavaScript has been my primary language for the passed year as I’ve been employed in mutating Mozilla, Navigator’s open source child, for research purposes.
Slate is a new Smalltalk-80 descendant in development since 2003. Inspired by CLOS (the Common Lisp Object System) and Sun’s research language Self, Slate is an attempt to redeem the promises of Smalltalk that were never realized. Only the future can tell if Slate will succeed.
Ruby, brain child of Yukihiro Matsumoto, was conceived in February of 1993 by the then unemployed Matz. After a two year gestation, Ruby became public in 1995. True to its design philosophy, “we need to focus on humans, on how humans care about doing programming or operating the application of the machines. We are the masters. They are the slaves,” Matz produced an industrial quality gem. Excellent for everyday programming tasks of all sizes, Ruby is the most practical programming language I know. My only complaint is a consequence of its greatest virtue. Says Matz, “Actually, I’m trying to make Ruby natural, not simple.” Natural it is, simple it is not: Mixins are Modules, Procs aren’t Blocks, and custom instances are Eigenclasses.
Scheme: “Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary.” First designed in 1975 as a cleaner Lisp, Scheme has had five major revisions since then. If Common Lisp is at the bottom of the language lattice: the great repository of all language features, then Scheme is at the top: remove anything and all you have left is a bunch of parenthesis.
Misp is a minimal Lisp like language that I invented on November 11 of last last year. Misp is a minimal by only having symbols and pairs. Due to its simplicity, a Misp interpreter can be implemented with any of today’s languages in just about a hundred lines. My Misp meta-interpreter is exactly fifty lines.
OCaml is an impure strongly typed functional programming language that performs. Creator Xavier Leroy, “OCaml delivers at least 50% of the performance of a decent C compiler.” OCaml is the 1996 child of the then year old Caml. Both were developed by INRIA (the French National Institute for Research in Computer Science and Control). OCaml extends Caml with Object Oriented constructs. Caml itself is impure because it has some imperative primitives.
Haskell, the premiere pure functional language, was created by committee in 1987 to be a language that’s as appropriate for academic papers as it is for compilation on a computer. I know I’ve read much more Haskell than I’ve written. Haskell looks more like mathematical notation than a programming language. Paul Hudak, “we provided [our Haskell prototype] without explaining that it was a program, and based on preconceptions from their past experience, they had studied [it] under the assumption that it was a mixture of requirements specification and top level design. They were convinced it was incomplete because it did not address issues such as data structure design and execution order.”
wl is my favorite language. In fact, wl is my, Will’s, language. In frantic development (I don’t sleep), I’m hoping to have a public release ready by the middle of 2010.
Show me the code!
Now that everyone’s introduced, the game to write an idiomatic program that applies an anonymous function for adding two numbers to the numbers four and five. Notes follow the results.
| Language | Code | Length | Compared to Misp |
|---|---|---|---|
| Java | ((Integer)(new Function() {
public Object call(int x, int y) {
return new Integer(x + y);
}
}).call(4, 5)).intValue(); | 122 | 508% |
| JavaScript | (function(x, y) { return x + y; })(4, 5); | 41 | 171% |
| Slate | [| :x :y | x + y] applyWith: 4 with: 5. | 39 | 162% |
| Ruby | lambda {|x, y| x + y}.call 4, 5 | 32 | 133% |
| Scheme | ((lambda (x y) (+ x y)) 4 5) | 28 | 116% |
| Misp | ((fn (x y) (+ x y)) 4 5) | 24 | 100% |
| OCaml | (fun x y -> x + y) 4 5;; | 24 | 100% |
| Haskell | (\ x y -> x + y) 4 5 | 20 | 83% |
| wl | {v + w} 4 5 | 11 | 46% |
The Java version assumes the Function class with several varieties of call. call returns an Object in order to allow all kinds of return values for functions of two ints. Since Java 1.5 has a stronger type system, one might be able to simplify this code.
Though syntactically similar to Java, JavaScript’s biggest difference is the function keyword for defining anonymous functions. I use semicolons ; here because it’s the preferred JS style; however, in my own code, I omit them whenever possible.
Slate uses a block syntax very much like Smalltalk’s. A colon : before an identifier in the header indicates that the variable is an argument. If there were no colon, you are declaring a local variable. I chose to send the applyWith:with: message instead of the roughly equivalent applyTo: because applyTo: would require that I put the arguments into a list first.
Ruby is inspired by Smalltalk and it shows. The lambda is necessary because Blocks are not Procs: blocks must be the argument to a method, so the lambda method is used to capture one. Ruby makes parenthesis around arguments optional. I exercise the option whenever I can. Some people say that after writing enough Lisp, you disregard the parenthesis; you stop seeing them. I disregard them, so I see them as noise.
Notice that both Scheme and Misp use prefix syntax for the sum +. Strictly speaking, Misp doesn’t have numbers. Moreover, symbols in Misp are completely atomic: there’s no way to discover the letters used to write them. Therefore, you couldn’t really implement a sum function like this even if you wanted to.
Since Haskell and OCaml are functional languages, it’s no surprise that the function definition syntax is very elegant. It’s not a typo, OCaml does use two semicolons ;; to end a statement. The backslash \ in Haskell is meant to suggest the Greek letter lambda.
In wl, you don’t have to name the arguments to a function. If you don’t, then v refers to the first argument and w refers to the second argument. Other arguments are accessible by index through vs. Implicit binding has great uses. All of the languages (except Misp) support implicit binding in one way or another. In wl, it is conventional to use v and w for short functions in which more descriptive names wouldn’t do much good. If had been set on naming the variables, we could have written {x y -> x + y} 4 5.
Commentary