SCOOP implementation

  1. Known limitations
    1. Supported concurrency mechanisms
    2. Maximum number of SCOOP processors
    3. Separate anchored types
    4. Agents targeted to objects of separate types
  2. Workarounds
    1. Printing a separate STRING
    2. Calling a separate agent
  3. Implementation dependent behavior
    1. The Wait Rule

The implementation of SCOOP within EiffelStudio varies from the definition as it has been presented in publications during the model's evolution.

Some of the differences stem from the reality that SCOOP systems could be optimized for performance, including maximizing concurrency. For example, even though the SCOOP rules state that a separate call to a query is synchronous, i. e., the calling processor waits until the query completes before proceeding, if a static analysis can show that the wait is not necessary to the proper functioning of the remainder of the calling routine, then the call to the query can be done asynchronously.

In other ways, particularly for early versions, the EiffelStudio implementation may not cover all the goals of SCOOP as stated in the various publications. Certain elements that are defined in the SCOOP descriptions may not yet be present, or only partially implemented in the EiffelStudio implementation.

The differences between the EiffelStudio implementation of SCOOP and current and previous definitions of the SCOOP model are shown below.

Known limitations

Supported concurrency mechanisms

Although the SCOOP model can support virtually any underlying concurrency mechanism, the initial SCOOP implementation in EiffelStudio version 6.8 supports only one executable, using multiple process threads as SCOOP processors.

Maximum number of SCOOP processors

In the initial release, the allowable maximum number of SCOOP processors per system is 1024.

Separate anchored types

Applicable prior to revision number 86657:

Separate status for anchored types is not supported properly. So declarations of the form:

my_entity: separate like my_query


my_entity: separate like Current

should be used only if you are using revision 86657 or later.

Also, if you use an anchored declaration such as:

my_entity: like my_query

and the type of my_query is separate, you should make sure you are using revision 86657 or later.

Agents targeted to objects of separate types

In version 6.8, agents targeted on separate objects are not supported.


The first implementation of SCOOP, some things that we do commonly in sequential Eiffel become less fluid in the presence of SCOOP. Although not strictly limitations in the implementation of SCOOP principles, in order to make SCOOP programming easier, these are areas that should be improved in future releases. In the meantime, there are workarounds for some of these situations.

Printing a separate STRING

Suppose you have declared a class attribute of type separate STRING:

my_separate_string: separate STRING = "Hello Eiffel World!"

and you want to output that string using io.put_string. The solution you might use from sequential Eiffel would be:

io.put_string (my_separate_string)

But the statement above results in a compile error because the argument type (separate STRING) is not compatible with the type (STRING) that put_string is expecting.

In order to make printing of the content of separate instances of STRING, a creation procedure, make_from_separate, is available in the string classes which allows initialization of a non-separate instance of STRING from a separate STRING.

So, to print my_separate_string, you could create a non-separate instance of STRING, then print the non-separate instance, as shown below.

local l_temp: STRING ... create l_temp.make_from_separate (my_separate_string) io.put_string (l_temp)

Or use a creation expression and avoid declaring the local variable:

io.put_string (create {STRING}.make_from_separate (my_separate_string))

Calling a separate agent

Calling a separate agent is a bit tricky, especially if it's a PROCEDURE which should be executed asynchronously. If the agent does not take any arguments, you must pass Void, otherwise the compiler will generate an empty TUPLE which is on the same processor as the caller and thus triggers lock passing (see Asynchronous Calls):

do_call (proc: separate PROCEDURE [ANY, TUPLE]) do (Void) end

If the agent does take arguments, things get a bit more tricky. If the call must be asynchronous, you have to do a workaround with the feature {ROUTINE}.empty_operands like this:

do_call (a_procedure: separate PROCEDURE [ANY, TUPLE[separate STRING]]; a_string: separate STRING) local l_tuple: separate TUPLE [separate STRING] do l_tuple := a_procedure.empty_operands set_tuple_string (l_tuple, a_string) (l_tuple) end set_tuple_string (a_tuple: separate TUPLE [str: separate STRING]; a_string: separate STRING) do a_tuple.str := a_string end

Implementation dependent behavior

The Wait Rule

note : This only applies to EiffelStudio releases prior to 15.01

The Wait Rule says: A routine call with separate arguments will execute when all corresponding processors are available and hold them exclusively for the duration of the routine.

In the EiffelStudio implementation prior to 15.01, a routine will not necessarily wait for all processors associated with its separate arguments to be available before it begins execution. The waiting on processors occurs in a "lazy" manner. Execution will only wait on the availability of one of the processors when it actually needs to use the argument associated with that processor. This means that if there are several instructions ahead of the first instruction that references a separate argument, then those several instructions will be executed immediately. Only at the point at which the separate argument's processor is needed will the routine pause and wait for the availability of the processor.