SCOOP means Simple Concurrent Object Oriented Programming.
The keyword here, is simple. As always in Eiffel.
And as always in the ECMA Eiffel world, things get complicated. See those articles:
* http://se.ethz.ch/people/nienaltowski/papers/contracts_for_concurrency.pdf * http://se.ethz.ch/people/nienaltowski/papers/flexible_locking_in_scoop.pdf * http://se.inf.ethz.ch/people/nienaltowski/papers/oopsla04.pdf * http://se.inf.ethz.ch/people/nienaltowski/papers/scoop_easy_draft.pdf * http://se.ethz.ch/teaching/2009-S/0268/lectures/lecture%207.pptx
They are interesting. They truly are. And they try to solve a real problem: the rules defined by B.M. in OOSC2 are not quite as sound as we would like. I'm glad they saw it at last, by really working on SCOOP.
But I do not agree with their solution. It's complex. I'm curious to see the error messages they will display to the John Doe programmer who wants a little bit of concurrency (well, I am John Doe). Simple? Where is it??
And it does not allow to pass a non-separate object to a separate target. Yes, I know about the "traitor" concept; but the solution is not simple since any random library must be "prepared" to accept separate object. How does one pass a STRING to a separate STRING, in order to concatenate it?? One cannot.
I think their "separate" keyword is a virus. It spreads to any class that may deal with separate reference.
But there are good things in those papers, esp. concerning lock passing (although I need to read again when fully awake).
Liberty's solution (this is still science fiction)
There is another way: keep it SIMPLE. Really.
Separate is a class property
Like deferred which in SmartEiffel (and therefore in Liberty) can only be a property of a class (not of a random entity), separate is also a property of a class.
In other words, to keep it simple, a class (and therefore John Doe who programs it) is "aware" of its separateness status. Furthermore, this rule helps to circumscribe the concurrency management to as few classes as possible.
Allow passing reference objects
Yes, but not traitors. Reference objects must be deeply copied in the target's processor. Ditto for expanded objects containing non-separate references.
- This forces a "pass-by-copy" semantics on all non-separate objects.
- Two distinct separate objects, even if they belong to the same class, have distinct processors.
- In other words, the only separate objects having the same processor than Current, are Current and its non-separate references.
Definition: an imported object (from an original object) is:
- a reference or expanded object that belongs to the target's processor, with each of its attribute being also imported from the original object's corresponding attribute (recursively).
- a separate object belonging to another processor stays attached to that processor.
- Void stays Void.
- A class may be either expanded or separate, but not both.
- If a formal argument of a routine defined in a separate class is...
- separate, then the actual argument's value will be the reference of the original object, which is locked by the routine until its completion.
- not separate, then the actual argument's value will be the reference of an object imported into the target's processor (see rule 4 exception).
- If the result of a routine defined in a separate class is...
- separate, then the returned object's value will be passed Result's reference.
- not separate, then the returned object's value will be the reference of Result imported back into the caller's processor (see rule 4 exception).
- If the caller's and target's processors are the same  then the objects are not imported and the passed value is the original reference.
- if a separate class TS inherits from a non-separate class T, then any t: T may be attached to a ts: TS entity (but not the opposite)
- a class T cannot inherit from, or insert, any separate class.
The semantics of once functions is slightly changed:
- if the once function returns a separate object, then it is evaluated once in the life of the entire program and the same separate entity reference is returned at each call
- if the once function returns a non-separate object, then it is evaluated once per calling processor and the returned reference depends on the calling processor.
Note that this case definition degrades gracefully for non-SCOOP systems, which are merely systems having one processor.
No special provision for std_input, std_output, std_error, and io. The classes are not separate, hence the objects are evaluated in each processor.
As a consequence, the behavior of those entities depends on the underlying operating system.
- Not "pass-by-value". Eiffel is strictly pass-by-value anyway since you cannot write the swap(a, b) method in Eiffel. Referenced objects are passed by their reference value. To be precise (and quite pedantic), in the case of separate objects, the passed value is the reference of a new object belonging to the good processor ("imported").
- In a separate class the target's and caller's processors are the same only if the target of a routine call is either Current or a non-separate object.