Apple Blocks added to C++?

Reimer Behrends behrends at gmail.com
Thu Sep 3 05:40:26 PDT 2009


Walter Bright wrote:
> The reason for nested functions are:
> 
> 1. factoring out repeated code within the function into a nested function
> 
> 2. locality - a nested function is adjacent to where it is used, rather 
> than somewhere else
> 
> 3. isolation - by scope rules, it is easy to see the nested function and 
> all calls to it

You don't actually need nested functions for that. Consider, for 
example, Tarjan's algorithm [1] to find strongly connected components in 
a directed graph. It's normally a prime example of where you would use 
nested functions: It's got some scaffolding to set up temporary state, 
then repeatedly calls a recursive helper algorithm that operates on the 
temporary state. Without going into the details of the algorithm, you 
can basically write it as follows (using Scala as an example, though of 
course it would also work in D, OCaml, etc.):

class DirectedGraph[V] {
   ...
   def stronglyConnectedComponents: Set[Set[V]] = {
     def recursiveHelper(vertex: V) = { ... }
     ...
   }
   ...
}

However, you could also factor out the algorithm into a class of it's own:

class StronglyConnectedComponents[V](val graph: DirectedGraph[V]) {
   def findAll: Set[Set[V]] = { ... }
   private def recursiveHelper(vertex: V) = { ... }
}

This satisfies all your three criteria above. The potentially repeated 
code is factored out into its own function, the helper function is next 
to where it is used, and you can see who call it since it is private.

However, unlike a nested function, you have additional benefits: You can 
reuse the helper function, for starters. And since the algorithm isn't 
an integral part of the DirectedGraph class anymore, you can furthermore 
improve the refactoring, since the algorithm doesn't need the full 
graph, but only a set of vertices and a successor function:

class StronglyConnectedComponents[V](val vertices: Set[V],
     val successors: V => Set[V]) {
   def findAll: Set[Set[V]] = { ... }
   private def recursiveHelper(vertex: V) = { ... }
}

Now we can use the algorithm not only for directed graphs, but also for 
other, similar data structures that do not need to be a subtype of 
DirectedGraph.


>> However, nested functions are hidden inside their parent, which means 
>> that they are not reusable;
> 
> That's actually a feature, see (3).

As I showed above, you can have both locality and reusability. These are 
not mutually exclusive properties.

>> on top of that, object-oriented languages already have means to share 
>> state between multiple methods (which is sometimes imperfect, but so 
>> are nested functions).
> 
> Nested classes (Java) and functors (C++) are pretty ugly next to nested 
> functions.

I am not even talking about nested classes, just classes (see above). 
Classes are the standard vehicle in most object-oriented languages for 
having multiple functions operating on shared state.

Mind you, I'm not saying that this is the only approach to deal with 
such issues (and it has imperfections of its own). Just that it is an 
alternative, equally valid way of doing things.

			Reimer Behrends


[1] 
http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm



More information about the Digitalmars-d mailing list