Nested function
In computer programming, a nested function is a function which is defined within another function, the enclosing function. Due to simple recursive scope rules, a nested function is itself invisible outside of its immediately enclosing function, but can see all local objects of its immediately enclosing function as well as of any function which, in turn, encloses that function. The nesting is theoretically possible to unlimited depth, although only a few levels are normally used in practical programs.
Nested functions are used in many approaches to structured programming, including early ones, such as ALGOL, Simula 67 and Pascal, and also in many modern dynamic languages and functional languages. However, they are traditionally not supported in the C-family of languages.
Effects
Nested functions assumes function scope or block scope. The scope of a nested function is inside the enclosing function, i.e. inside one of the constituent blocks of that function, which means that it is invisible outside that block and also outside the enclosing function. A nested function can access other local functions, variables, constants, types, classes, etc. that are in the same scope, or in any enclosing scope, without explicit parameter passing, which greatly simplifies passing data into and out of the nested function. This is typically allowed for both reading and writing.Nested functions may in certain situations lead to the creation of a closure. If it is possible for the nested function to escape the enclosing function, for example if functions are first class objects and a nested function is passed to another function or returned from the enclosing function, then a closure is created and calls to this function can access the environment of the original function. The frame of the immediately enclosing function must continue to be alive until the last referencing closure dies and non-local automatic variables referenced in closures can therefore not be stack allocated. This is known as the funarg problem and is a key reason why nested functions was not implemented in some simpler languages as it significantly complicates code generation and analysis, especially when functions are nested to various levels, sharing different parts of their environment.
Examples
An example using Pascal syntax :function E: real;
function F: real;
begin
F := x + y
end;
begin
E := F + F
end;
The function
F
is nested within E
. Note that E
's parameter x
is visible also in F
while both x
and y
are invisible outside E
and F
respectively.Similarly, in Standard ML:
fun e =
let
fun f y = x+y
in
f 3 + f 4
end;
One way to write the same example in Haskell syntax:
e :: Float -> Float
e x = f 3 + f 4 where f y = x + y
The same example in GNU C syntax :
float E
Quicksort
A more realistic example is this implementation of quicksort:void sort
Another example is the following implementation of the Hoare partition based quicksort using C++11 lambda expression syntax:
template
auto Sort->void
Purpose
Lexically nested function definitions are a form of information hiding and are useful for dividing procedural tasks into subtasks which are only meaningful locally. This avoids cluttering other parts of the program with functions and variables that are unrelated to those parts.They are typically used as helper functions or as recursive functions inside another function. This has the structural benefit of organizing the code, avoids polluting the scope, and also allows functions to share state easily. As nested function can access local variables of the enclosing function, sharing of state is possible without passing parameters to the nested function or use a global variable, simplifying code.
In languages with nested functions, functions may normally also contain local constants, and types, encapsulated and hidden in the same nested manner, at any level of depth. This may further enhance the code structuring possibilities.
Other uses
Control flow
Nested functions can also be used for unstructured control flow, by using the return statement for general unstructured control flow. This can be used for finer-grained control than is possible with other built-in features of the language – for example, it can allow early termination of a for loop ifbreak
is not available, or early termination of a nested for loop if a multi-level break
or exceptions are not available.Higher-order functions
As in most languages functions are valid return types, it is possible to create a nested function that accesses a set of parameters from the outer function and have that function be the outer function's return value. Thus it is possible to return a function that is set to fulfill a certain task with little or no further parameters given to it, which can increase performance quite significantly.Alternatives
The main alternative to nested functions in languages that lack support for them is to place all relevant functions and variables in a separate module and expose only the top-level wrapper function publicly. In C this will generally be done by using static functions for encapsulation and static variables for communication. This achieves encapsulation and sharing of state, though not the logical organization given by lexical nesting of functions, and comes at the cost of having a separate file. It is also not possible in more than a single level.Another alternative is to share state between the functions through function parameters, most often passing references as arguments to avoid the cost of copying. In C this is generally implemented by a pointer to a structure containing the context. This significantly increases the complexity of the function calls.
In PHP and other languages the anonymous function is the only alternative: the nested function is declared not as usual function, but by reference, as a local variable. To use local variables in the anonymous function, use closure.
Languages
Well known languages supporting lexically nested functions include:- ALGOL-based languages such as ALGOL 68, Simula, Pascal, Modula-2, Modula-3, Oberon, Seed7 and Ada
- Modern versions of Lisp such as Scheme, and Common Lisp
- ECMAScript
- Scala
- Various degrees of support in scripting languages such as Ruby, Python, Lua, PHP and Perl
- GCC supports nested functions in C, as a language extension.
- C#, starting with C# 7.0
- The D language, a C-related language with nested functions.
- Fortran, starting with Fortran-90, supports a single level of nested subroutines and functions.
- MATLAB
- Wolfram Language
- Pawn, with YSI
Functional languages
Some languages without direct support
Certain languages do not have straightforward syntactic and semantic support to implement nested functions. Nevertheless, for some of them the idea of nested functions can be simulated with some degree of difficulty through the use of other language constructs. The following languages can approximate nested functions through the respective strategies:- C++
- *before C++11: allows definition of classes within classes, providing the ability to use class methods in a way similar to nested functions in one level.
- *since C++11: by using lambda expressions as the quicksort example above.
- Eiffel explicitly disallows nesting of routines. This is to keep the language simple, and also allows the convention of using a special variable, Result, to denote the result of a function.
- Visual Basic, by using anonymous methods or lambda expressions.
- Java, by using lambda expressions or through a workaround that consists in an anonymous class containing a single method. A named class declared local to a method may also be used.
Implementation
Access of non local objects
There are several ways to implement nested procedures in a lexically scoped language, but the classic way is as follows:This original method is faster than it may seem, but it is nevertheless often optimized in practical modern compilers.
Another way to implement nested functions that is used by some compilers is to convert nested functions into non-nested functions using a process known as lambda lifting during an intermediate stage in the compilation.
Functions as values
In order for local functions with lexically scoped nonlocals to be passed as results, the language runtime code must also implicitly pass the environment that the function sees inside its encapsulating function, so that it is reachable also when the current activation of the enclosing function no longer exists. This means that the environment must be stored in another memory area than a chronologically based execution stack, which, in turn, implies some sort of freely dynamic memory allocation. Many older Algol based languages does therefore not allow local functions that access nonlocals to be passed as return values, or do they not allow functions as return values at all, although passing of such functions as arguments may still be possible.No-execute stacks
At least one implementation of nested functions cause a loss of No-execute stacks. GCC's nested function implementation calls nested functions through a jump instruction put in the machine stack at runtime. This requires the stack to be executable.No execute stacks and nested functions are mutually exclusive under GCC. If a nested function is used in the development of a program, then the NX Stack is silently lost. GCC offers the -Wtrampoline warning to alert of the condition.
Software engineered using Secure Development Lifecycle often do not allow the use of nested functions in this particular compiler due to the loss of NX Stacks.