def recursiveList(path):One big design win of local functions is namespace cleanliness. The function
def collect(path, result):
# this is a function inside another function
result.append(path)
if os.path.isdir(path):
for child in os.listdir(path):
collect(os.path.join(path, child), result)
result = []
collect(path, result)
return result
collect
is not visible anywhere but inside of recursiveList
.Unfortunately, C/C++ has no way of doing this that I know of. Java gets really close to local functions with the ability to use anonymous classes. An anonymous class is especially useful for implementing an interface with a single method. Here's an example:
public static void pipeStreamsAsynchronously(final InputStream in, final OutputStream out) {It occurred to me only today that anonymous classes can be used just like local functions by using initializers. Initializers are segments of code that run at the beginning of (almost) every constructor. You declare them like this:
Thread thread = new Thread(new Runnable() {
// Runnable is an interface with just a void run() method.
public void run() {
try {
while (true) {
// this call to read() can block
int b = in.read();
if (b == -1)
return;
out.write(b);
}
} catch (IOException e) {
}
}
});
thread.start();
}
public class LinePrinter {You can also put a
private final String newline;
{
// this is an initializer
if (System.getProperty("os.name").startsWith("Windows"))
newline = "\r\n";
else
newline = "\n";
// NOTE: this is the wrong way to get the platform's line terminator.
}
private final PrintStream out;
public LinePrinter() {
// initializer has run by now
out = System.out;
}
public LinePrinter(PrintStream out) {
// initializer has run by now
this.out = out;
}
public void print(String line) {
out.print(line);
out.print(newline);
}
}
static
before the {
to make it a static initializer which runs once when the class is first accessed at runtime. Static and non-static initializers are the mechanisms java compilers use behind the scenes to evaluate initial assignments for fields with an assignment built into their declarations:public class MyClass {In general, explicit non-static initializers are not particularly useful since they offer code reuse only in the case non-converging constructor overloads. The proper way to implement the above LinePrinter class would be have the parameterless constructor call
// the getProperty() call runs in an implicit static initializer.
public static final String NEWLINE = System.getProperty("line.separator");
// the length() call runs in an implicit non-static initializer.
private final int newlineLength = NEWLINE.length();
}
this(System.out);
and have the other constructor do the newline
initialization logic. The example is only to demonstrate when initializers run.Here's how you can use anonymous classes and initializers together to make local functions in Java:
public static ArrayList<File> recursiveList(final File path) {
final ArrayList<File> result = new ArrayList<File>();
new Object() {
private void collect(File path, ArrayList<File> result) {
result.add(path);
File[] children = path.listFiles();
if (children != null)
for (File child : children)
collect(child, result);
}
{
// this is the initializer
collect(path, result);
}
};
return result;
}
No comments:
Post a Comment