Search code examples
eiffel

Error code: VUTA(3) Error: separate target of the Object_call is not controlled


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:

MY_LINKED_LIST[G]

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

MY_CELL[G]

class
    MY_CELL[G]

feature -- Access

    item: G

Solution

  • 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.