Language Support
Functional programming languages, such as Scheme, ML, Haskell, F#, and Scala all have first-class functions. When Lisp, one of the earliest functional languages, was designed not all aspects of first-class function were then properly understood, resulting in functions being dynamically scoped. The later Common Lisp dialect, does have lexically scoped first-class functions.
Many scripting languages, including Perl, Python, PHP, Lua, Tcl/Tk, JavaScript, Ruby, and Io, have first-class functions.
For imperative languages, a distinction has to be made between Algol and its descendants such as Pascal, the traditional C family, and the modern garbage-collected variants. The Algol family has allowed nested functions and higher-order taking function as arguments, but not higher-order functions that return functions as results (except Algol 68, which allows this). The reason for this was that it was not known how to deal with non-local variables if a nested-function was returned as a result (and Algol 68 produces runtime errors in such cases).
The C family allowed both passing functions as arguments and returning them as results, but avoided any problems by not supporting nested functions. (The gcc compiler allows them as an extension.) As the usefulness of returning functions primarily lies in the ability to return nested functions that have captured non-local variables, instead of top-level functions, these language are generally not considered to have first-class functions.
Modern imperative languages often support garbage-collection making the implementation of first-class functions feasible. First-class function have often only been supported in later revisions of the language, including C# 2.0 and Apple's Blocks extension to C, C++ and Objective C. C++11 has added support for anonymous functions and closures to the language, but the non-garbage collected nature of the language and capture semantics of non-local variables still make it problematic for functions to be returned as results.
Language | Higher-order functions | Non-local variables | Partial application | Notes | ||||
---|---|---|---|---|---|---|---|---|
Arguments | Results | Nested functions | Anonymous functions | Closures | ||||
Algol family | ALGOL 60 | Yes | No | Yes | No | No | No | Have function types. |
ALGOL 68 | Yes | Yes | Yes | Yes | No | No | ||
Pascal | Yes | No | Yes | No | No | No | ||
Oberon | Yes | Non-nested only | Yes | No | No | No | ||
C family | C | Yes | Yes | No | No | No | No | Has function pointers. |
C++ | Yes | Yes | No | C++11 | C++11 | No | Has function pointers, function objects. (Also, see below.) | |
C# | Yes | Yes | No | 2.0 / 3.0 | 2.0 | No | Has delegates (2.0) and lambda expressions (3.0). | |
Objective-C | Yes | Yes | No | 2.0 + Blocks | 2.0 + Blocks | No | Has function pointers. | |
Java | Partial | Partial | No | No | 8 | No | Has anonymous inner classes. | |
Functional languages | Lisp | Syntax | Syntax | Yes | Yes | Common Lisp | No | (see below) |
Scheme | Yes | Yes | Yes | Yes | Yes | SRFI 26 | ||
Clojure | Yes | Yes | Yes | Yes | Yes | Yes | ||
ML | Yes | Yes | Yes | Yes | Yes | Yes | ||
Haskell | Yes | Yes | Yes | Yes | Yes | Yes | ||
Scala | Yes | Yes | Yes | Yes | Yes | Yes | ||
Scripting languages | JavaScript | Yes | Yes | Yes | Yes | Yes | ECMAScript 5 | Partial application possible with user-land code on ES3 |
PHP | Yes | Yes | Unscoped | 5.3 | 5.3 | No | (see below) | |
Perl | Yes | Yes | 6 | Yes | Yes | 6 | ||
Python | Yes | Yes | Yes | Partial | Yes | 2.5 | (see below) | |
Ruby | Syntax | Syntax | Unscoped | Yes | Yes | 1.9 | (see below) | |
Other languages | Mathematica | Yes | Yes | Yes | Yes | Yes | No | |
Smalltalk | Yes | Yes | Yes | Yes | Yes | Partial | Partial application possible through library. | |
Fortran | Yes | Yes | Yes | No | No | No |
- C++
- C++11 closures can capture non-local variables by copy or by reference, but without extending their lifetime.
- Java
- Java 8 closures can only capture immutable ("effectively final") non-local variables.
- Lisp
- Lexically scoped Lisp variants support closures, dynamically scoped variants do not.
- In Common Lisp, the identifier of a function in the function namespace cannot be used as a first-class value. It must be converted into a value using the
(function )
or#'
operators. Conversely, to apply a function encapsulated in such a way as a value, one must use the(funcall )
operator instead of calling it directly. - PHP
- Nested functions are created at global scope once the outer function is executed.
- Python
- Python's anonymous functions can only have an expression as the body
- Explicit partial application with
functools.partial
since version 2.5, andoperator.methodcaller
since version 2.6. - Ruby
- The identifier of a regular "function" in Ruby (which is really a method) cannot be used as a value or passed. It must first be retrieved into a
Method
orProc
object to be used as first-class data. The syntax for calling such a function object differs from calling regular methods. - Nested method definitions do not actually nest the scope.
- Explicit currying with
Proc#curry
.
Read more about this topic: First-class Function
Famous quotes containing the words language and/or support:
“Neither Aristotelian nor Russellian rules give the exact logic of any expression of ordinary language; for ordinary language has no exact logic.”
—Sir Peter Frederick Strawson (b. 1919)
“... married women work and neglect their children because the duties of the homemaker become so depreciated that women feel compelled to take a job in order to hold the respect of the community. It is one thing if women work, as many of them must, to help support the family. It is quite another thingit is destructive of womans freedomif society forces her out of the home and into the labor market in order that she may respect herself and gain the respect of others.”
—Agnes E. Meyer (18871970)