[[Property:title|SCOOP implementation]]
[[Property:weight|9]]
[[Property:uuid|eeb07907-e036-f3d6-5297-a7c44cfd1900]]
The implementation of SCOOP is the result of many years of design and refinement of the model. This page describes specific properties of its current state, in particular ways in which it differs from some of the earlier publications about the model.
=Known limitations=
==Supported concurrency mechanisms==
Although the SCOOP model can support any underlying concurrency mechanism, the current SCOOP implementation uses threads as SCOOP [[Concurrent programming with SCOOP#Processors|processors]].
==Maximum number of SCOOP processors==
In the initial release, the allowable maximum number of SCOOP processors per system is 1024.
==Agents targeted to objects of separate types==
Agents targeted on separate objects are currently not supported.
=Workarounds=
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
proc.call (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)
a_procedure.call (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 [[Concurrent programming with SCOOP#Access to shared resources|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.