Search code examples
iteratorvoidnotnulleiffel

Getting the error "VEVI: Variable is not properly set" in Eiffel


I am trying to make an iterator for for a linked_list in Eiffel.

I am getting this error: Variable is not set properly.

Class: ITERATOR_ON_COLLECTION [E]
Feature: make
Attribute(s): {ITERATOR}.target
Line: 30

I know it's because of void safety but I don't know how to fix it. (I set void safety to True and changed the precompiled library to safe version and clean_compile it.)

the following is the class:

class
    ITERATOR_ON_COLLECTION [E]

inherit
    ITERATOR [E]

create
    make

feature {NONE} -- Attributes

    collection: LINKED_LIST[E]
    item_index: INTEGER

feature -- initialization

    make(c: LINKED_LIST [E])
        require
            --c /= void
        do
            --  create {COLLECTION} collection.make
            --  create collection.make -- it doesnt work with/without this line 
            collection := c
            item_index := 1
        end

    start
        do
            item_index := 1
        end

    item: STRING
        do
            Result := "hello"
        end

    next
        do
            item_index := item_index + 1
        end

    is_off: BOOLEAN
        do
            Result := True
        end


    do_until (action: PROCEDURE [E]; test: FUNCTION [E, BOOLEAN])
            -- Apply `action' to every item of `target' up to
            -- and including first one satisfying `test'.
            -- (Apply to full list if no item satisfies `test').
        require else
            action_exists: action /= Void
            test_exists: test /= Void
        do
        end

    do_while (action: PROCEDURE [E]; test: FUNCTION [E, BOOLEAN])
            -- Apply `action' to every item of `target' up to
            -- and including first one not satisfying `test'.
            -- (Apply to full list if all items satisfy `test').
        require else
            action_exists: action /= Void
            test_exists: test /= Void
        do
        end

    until_do (action: PROCEDURE [E]; test: FUNCTION [E, BOOLEAN])
            -- Apply `action' to every item of `target' up to
            -- but excluding first one satisfying `test'.
            -- (Apply to full list if no items satisfy `test'.)
        require else
            action_exists: action /= Void
            test_exists: test /= Void
        do
        end

    while_do (action: PROCEDURE [E]; test: FUNCTION [E, BOOLEAN])
            -- Apply `action' to every item of `target' up to
            -- but excluding first one satisfying not `test'.
            -- (Apply to full list if all items satisfy `test'.)
        require else
            action_exists: action /= Void
            test_exists: test /= Void
        do
        end

    there_exists (test: FUNCTION [E, BOOLEAN]): BOOLEAN
            -- Is `test' true for at least one item of `target'?
        require else
            test_exists: test /= Void
        do
        end

    for_all (test: FUNCTION [E, BOOLEAN]): BOOLEAN
            -- Is `test' true for all items of `target'?
        require else
            test_exists: test /= Void
        do
        end

end

Solution

  • Without looking at the class ITERATOR it's hard to tell what is the real cause. Here is my guess what happens:

    Class ITERATOR declares an attribute target of an attached type. The attribute has to be set in your creation procedure. Most probably you need to discard the attribute collection in your class and use target instead. Depending on the attribute's type you may need to redefine it in your class or not.

    In terms of efforts it's better to start from void-safe versions of classes right from the beginning and when you switch from a non-void-safe settings to void-safe ones, you may need to make sure that the class types are attached by default (look for a configuration option "Are types attached by default?" in projects setting dialog). This option should be set to True (this is not done automatically in EiffelStudio prior to 16.11).

    A few comments on other parts of the code:

    • If an argument type is attached there is no point of checks in the form arg /= Void.

    • If a precondition foo is specified for a feature in a parent class there is no need to repeat it like

      require else
          foo
      

      It can be safely removed. (You can look at the feature flat (or flat short) form to see that the parent's precondition is still there.)

    • If comments of redefined features are not changed, they can be replaced with

      -- <Precursor>
      

      This way any changes in parent's versions will be automatically reflected in redeclarations (again have a look at the flat form).