I'm a complete beginner to Eiffel and I'm implementing a linked list as an exercise. I get the following error in the feature has (which tells you if the list contains v).
Error code: VUTA(3)
Error: separate target of the Object_call is not controlled.
What to do: ensure the target of the call is controlled or is not separate.
Class: MY_LINKED_LIST [G]
Feature: has
Type: Generic #1
Line: 159
then
-> if l_cursor_a.item.is_equal (v) then
Result := True
The weird thing is that when I change the '.is_equal' for a '=' the error is gone. I don't know what 'controlled' in the error description means and what difference to it does make to use '=' in this context. The code is the following:
class
MY_LINKED_LIST[G]
feature -- Access
item: G
require
not off
do
check
off: attached cursor as l_cursor
then
Result := l_cursor.item
end
end
first,
last: detachable like item
feature -- Measurement
count: INTEGER
feature -- Element change
feature -- Status report
index: INTEGER
before: BOOLEAN
after: BOOLEAN
has (v: like item): BOOLEAN
require
local
l_cursor: like cursor
do
from
l_cursor := first_element
until
not attached l_cursor or Result
loop
check
attached l_cursor as l_cursor_a
then
if l_cursor_a.item.is_equal (v) then
Result := True
end
l_cursor := l_cursor_a.next
end
end
ensure
function_not_change_state: item = old item
end
feature {NONE} -- Implementation
cursor,
first_element,
last_element: detachable MY_CELL[G]
end -- class
class
MY_CELL[G]
feature -- Access
item: G
The error message is related to SCOOP — the model of concurrent programming built into Eiffel. According to it, a feature can be called on a separate object only when the object is controlled. This is achieved when the target of the call is an argument of a feature, or when a special separate instruction is used. In your case, the latter would look like
separate l_cursor_a.item as x do
if x.is_equal (v) then
Result := True
end
end
Why l_cursor_a.item
is considered separate in the first place? It has a type G
, and the formal generic is unconstrained that is identical to have a constraint detachable separate ANY
(so, most probably, the code above would not compile, you would need to make sure x
is attached before calling is_equal
on it).
The equality operator =
does not perform any calls (unless the involved types are expanded, but expanded types are never separate). For reference types (including separate ones), it simply tests whether two references are the same. This explains why the error disappears when is_equal
is replaced with =
.
An alternative solution to avoid the error message is to change the constraint of the formal generic to be non-separate: MY_LINKED_LIST [G -> detachable ANY]
.
Side note. The check instruction check attached l_cursor as l_cursor_a then ...
seems to be redundant, the compiler should be able to figure out automatically that l_cursor
is attached.