SCOOP: Concurrency for Eiffel
SCOOP (Simple Concurrent Object-Oriented Programming), is an Eiffel-language extension that facilitates parallel programming. It is available for download as part of EiffelStudio.
The key to the future of software development is to master concurrency. With the "end of Moore's law as we knew it", software's free ride is over: it is no longer possible to expect that performance improvements will continue to come from faster processors. Instead, they require multi-processor ("multicore") architectures. On the software side, this evolution means that programs must increasingly be concurrent (or "parallel"), using multiprocessing or multithreading. Another area of concurrency is the increasing role of networks and in particular the Internet.
The usual approaches to concurrent programming rely on low-level libraries providing synchronization and communication mechanisms, such as the threading libraries available for Java, C++, C# and other languages. These libraries are based on concepts from the nineteen-sixties, such as semaphores which are hardly compatible with modern object-oriented techniques. They force programmers to change their mode of thinking and the architecture of their programs radically when introducing concurrency. Experience shows that for most programmers such a change is very difficult; and even if they master the low-level reasoning needed to make their applications concurrent, the resulting programs are difficult to write, difficult to bring to correctness (since traditional techniques of testing and debugging do not work for concurrent programs), and difficult to understand and maintain since the notations are so low-level.
SCOOP, the concurrency mechanism for Eiffel, simplifies concurrent programming so that it becomes a natural extension of object-oriented programming. SCOOP adds to Eiffel only one keyword (separate) yet provides the full power of concurrency. The key is to let the Eiffel implementation take care of all the tricky issues, in particular synchronization, so that programmers can concentrate on the business side of their applications.
As a typical example, the following is a routine, written in ordinary Eiffel without concurrency, to transfer a certain amount of money from an account to another:
transfer (amount: INTEGER ; source, target: ACCOUNT) -- Transfer amount dollars from source to target. require enough: source·balance >= amount do source·withdraw (amount) target·deposit (amount) ensure removed: source·balance = old source·balance – amount added: target·balance = old target·balance + amount end
The body (do …) describes the implementation: withdraw the amount from the source, deposit it on the target. The precondition (require …) describes the condition for applicability: there must be enough money on the source. The postcondition (ensure …) expresses the expected final state: the amount has been removed from the balance of the source and added to the balance of the target.
How do we turn such a routine into a concurrent operation? The problem is that if several such operations are proceeding in parallel we cannot allow arbitrary interleaving. For example two transfer operations for $800 could both find that the precondition is satisfied on the source, as it has a balance of $1000; then they would both proceed to transfer $800 to different targets, but this is wrong as there was not enough money to allow both!
In usual approaches to concurrent programming, programmers have to write complicated synchronization operations to guarantee that certain instructions are executed together. Here, for example, the precondition checking, the withdraw and the deposit should never be interleaved with instructions from another instance of transfer. In addition, if the source account does not initially have a high enough balance, the operation should wait. All this leads to tedious, low-level and error-prone programming and, as noted, to programs that are very hard to debug.
With Eiffel and SCOOP the transition to concurrency is straightforward. All that has to change in the above non-concurrent code, to make it concurrent but still correct and safe, is the header of the routine:
transfer (amount: INTEGER ; source, target: separate ACCOUNT) ... All the rest as before! ...
Declaring the accounts as separate tells the compiler that they are going to be handled by concurrent threads. All scheduling needs - including waiting on a source account whose balance is too small, as expressed by the precondition - are taken care of entirely by the SCOOP scheduler.
Using these simple expressive mechanisms enables SCOOP programmers to write even the most demanding concurrent applications in a simple and clear way, leaving all the difficult details to the implementation. The correctness of programs is easy to establish, without the need for painful debugging. Concurrency ceases to be a formidable barrier, becoming a natural complement to the modern programming techniques that programmers already master.