What Is the "Execute Around" Idiom

What is the Execute Around idiom?

Basically it's the pattern where you write a method to do things which are always required, e.g. resource allocation and clean-up, and make the caller pass in "what we want to do with the resource". For example:

public interface InputStreamAction
{
void useStream(InputStream stream) throws IOException;
}

// Somewhere else

public void executeWithFile(String filename, InputStreamAction action)
throws IOException
{
InputStream stream = new FileInputStream(filename);
try {
action.useStream(stream);
} finally {
stream.close();
}
}

// Calling it
executeWithFile("filename.txt", new InputStreamAction()
{
public void useStream(InputStream stream) throws IOException
{
// Code to use the stream goes here
}
});

// Calling it with Java 8 Lambda Expression:
executeWithFile("filename.txt", s -> System.out.println(s.read()));

// Or with Java 8 Method reference:
executeWithFile("filename.txt", ClassName::methodName);

The calling code doesn't need to worry about the open/clean-up side - it will be taken care of by executeWithFile.

This was frankly painful in Java because closures were so wordy, starting with Java 8 lambda expressions can be implemented like in many other languages (e.g. C# lambda expressions, or Groovy), and this special case is handled since Java 7 with try-with-resources and AutoClosable streams.

Although "allocate and clean-up" is the typical example given, there are plenty of other possible examples - transaction handling, logging, executing some code with more privileges etc. It's basically a bit like the template method pattern but without inheritance.

Why the Execute Aroud idiom is not considered a Strategy design pattern?

The way I see it, although both may be solutions to similar problems, these are different idioms and, therefore, should have different names.

I call them idioms, because the execute around it's just a programming idiom, used in many typical situations (similar to one presented) and also in several languages. And, at least that I have knowledge, the Execute Around was never formalized as a software design pattern, at least yet.

And why are they different? Here's my view:

The Stategy design pattern is intended to (from Wikipedia):

  • defines a family of algorithms,
  • encapsulates each algorithm, and
  • makes the algorithms interchangeable within that family.

Typically the strategy instance as a long lasting relation with the context instance, typically passed as a constructor dependency. Even though the context may have setters to the strategy, the same strategy can be used in several call to the context, without the caller (client) even not knowing which one is being used by that particular context and at the moment the call was done. Moreover, the same strategy instance may be used by the context in several methods of its public interface, without the caller no even knowing anything about its usage.

On the other hand, the execute around idiom is suited for parameterized algorithms, where the caller (client) should always pass the algorithm parametrization function in each call. Therefore, the strategy function passed, only influences behavior of that particular call, not other calls.

Although the presented differences may seam theoretical and rhetorical, if you put the context being called in a multithreaded scenario, is where I think the differences are more obvious and easily seen and "felt".

Without lots of locks and synchronization, you cannot use the strategy design pattern in a multithreaded scenario, at least if it is allowed to change the context strategy. If you don't, you see the more lasting duration of that relation between the context and the strategy, as they typically live the same time.

The execute around idiom, if properly implemented, should not suffer from this "disease", at least if the the passed function doesn't have any side effects.

Wrapping up, although Strategy design pattern and execute around idiom may seam alike, may be used to solve similar problems, and may seam to have a similar static structure, they are different in nature, having the former a much more OO style and the latter more functional style and, therefore, should have different names!

I agree with Miguel Gamboa, that the proliferation of names that mean the same is not good and should be avoided. But, at least in my opinion, this is not the case.

Hope this helps!

Is it abusive to implement the execute-around idiom with scoped objects?

If you pedantically consider the definition of RAII, anything you do using scoping rules and destructor invocation that doesn't involve resource deallocation simply isn't RAII.

But, who cares? Maybe what you're really trying to ask is,

I want X to happen every time I leave function Y. Is it
abusive to use the same scoping rules and destructor invocation that
RAII uses in C++ if X isn't resource deallocation?

I say, no. Scratch that, I say heck no. In fact, from a code clarity point of view, it might be better to use destructor calls to execute a block of code if you have multiple return points or possibly exceptions. I would document the fact that your object is doing something non-obvious on destruction, but this can be a simple comment at the point of instantiation.

Where do you draw the line? I think the KISS principle can guide you here. You could probably write your entire program in the body of a destructor, but that would be abusive. Your Spidey Sense will tell you that is a Bad Idea, anyway. Keep your code as simple as possible, but not simpler. If the most natural way to express certain functionality is in the body of a destructor, then express it in the body of a destructor.

Execute Around in C#

Have you considered implementing IDisposable interface, so later you can use using keyword, e.g.:

using (PdfLoadedDocument loadedDocument = new PdfLoadedDocument(path))
{
List<string> annotations = Build(loadedDocument);
}

public class PdfLoadedDocument : IDisposable
{
public void Close()
{

}

public void Save()
{

}

public void Dispose()
{
Save();
Close();
}
}

Idiom vs. pattern

Contrary to the idea that patterns are language agnostic, both Paul Graham and Peter Norvig have suggested that the need to use a pattern is a sign that your language is missing a feature. (Visitor Pattern is often singled out as the most glaring example of this.)

I generally think the main difference between "patterns" and "idioms" to be one of size. An idiom is something small, like "use an interface for the type of a variable that holds a collection" while Patterns tend to be larger. I think the smallness of idioms does mean that they're more often language specific (the example I just gave was a Java idiom), but I don't think of that as their defining characteristic.

Feedback on F# idiom and style, what do ;; mean, etc

There are two ways of working with F# - compiling an assembly with fsc (.fs files) and writing a script file to be executed with fsi. Bear with me if I'm stating the obvious, it will be relevant later.

Usually when you write a script, you're executing the code as you go, experimenting with it and capturing the results of a REPL session for later. That's where the ;; that are purely an fsi usage artifacts come from (as described in a comment).

One side effect of this REPL based approach is that the shape of things you have in the script may end up reflecting the path of how the implementer got there more than deliberate design, and as scripts are more of a throwaway thing, that is often acceptable. That's how the code might have evolved to have a test2 function with only a single usage - it's an ok idea to roll test and test2 together, and while I might recommend doing that if they're part of some reusable library and test2 has no clear usage scenarios on its own other than being part of test, I don't think it necessarily matters here.

The main function that you have at the end of the file however is an entry point to a console application - so the compiled way of working with F# - and really has no place and special meaning in a script. I believe it was just pasted over and left there for no obvious reason.

[<EntryPoint>]
let main argv =
0

You could just drop that and execute all those lines directly within the script.

You can test F# code using all the standard unit testing frameworks you have for .NET, but that's more of a use case for the compiled assembly path. Scripts are not unit-testable this way, and you'd test them interactively or through inline tests like the ones you have.



Related Topics



Leave a reply



Submit