Search code examples
linked-listeiffelreadable

Eiffel - How do I make my classes readable?


I'm new to Eiffel and I'm trying to use the LINKED_LIST class for organizing instances of other class "MONOMIO" I've made. I added a function for ordering this elements and I use the remove and the cursor movement features and when I try to execute the code it raises an exception saying that the objects contained should be readable and writable. I would like to know how to do it, this is my class:

class
    MONOMIO

feature --Initialization 
    make (coef:INTEGER; expX:INTEGER; expY:INTEGER)
    do
            coeficiente := coef
            exponenteX := expX
            exponenteY := expY
    end
feature
    evaluar(valX: INTEGER; valY: INTEGER): REAL_64
            do
                    Result := coeficiente*(valX^exponenteX)*(valY^exponenteY)
            end;
    coeficiente: INTEGER;

    exponenteX: INTEGER;

    exponenteY: INTEGER;


feature --setter
    set_coeficiente(val: INTEGER)
            do
                coeficiente := val
            end;
end

I think the exception raises because of this feature I've made for a class that has as a feature the LINKED_LIST[MONOMIO] and it's called "contenido":

simplificar
    local
        tamanio_polinomio: INTEGER -- Número de monomios que tiene el polinomio
        contador: INTEGER
        monomio_a_comparar: MONOMIO -- Auxiliar
        coeficiente_total:INTEGER -- Auxiliar
        indice_monomio_en_revision:INTEGER
    do
        from
            contenido.start
            indice_monomio_en_revision := 0
            tamanio_polinomio := contenido.count
        until
            indice_monomio_en_revision = tamanio_polinomio
        loop
            contenido.start
            contenido.move (indice_monomio_en_revision)
            monomio_a_comparar := contenido.item

            from
                contador := indice_monomio_en_revision
                coeficiente_total := monomio_a_comparar.coeficiente
                contenido.forth
            until
                contador = tamanio_polinomio
            loop
                if
                    (monomio_a_comparar.exponentex = contenido.item.exponentex) and
                    (monomio_a_comparar.exponentey = contenido.item.exponentey)
                then
                    coeficiente_total := coeficiente_total + contenido.item.coeficiente
                    contenido.remove -- Mueve el cursor a la derecha
                    tamanio_polinomio := tamanio_polinomio - 1
                    contador := contador - 1
                else
                    if
                        not contenido.islast
                    then
                        contenido.forth
                    end

                end
                contador := contador + 1
            end
            contenido.start
            contenido.move (indice_monomio_en_revision)
            contenido.item.set_coeficiente (coeficiente_total)
            indice_monomio_en_revision := indice_monomio_en_revision + 1
        end
    end;

I hope anyone can help me with this problem. Thanks.


Solution

  • Suppose you have a list with 1 element. Then we enter the outer loop and move to the first element. Then we execute contador := indice_monomio_en_revision that is still 0 at this point and do contenido.forth. Now we are beyond the list because there is only one element. However contador = tamanio_polinomio is false (0 = 1), so we enter the inner loop and try to retrieve the second (non-existing) item. BOOM!

    Other issues include:

    • There are multiple calls like contenido.start followed by contenido.move. You could use a single call to go_i_th instead.

    • Instead of counting number of items in the list I would look at the feature after. It tells when you reach an end of the list. It would simplify the logic of your loop (e.g. the call to islast would be removed) and let you to remove some local variables.

    Taking the last point into account I would write the inner loop condition as

    contenido.after
    

    At least this would avoid the crash you experience. As to the logic, you may need to check features start, after, forth and remove to see what effect they have. The usual way to write loops in such cases is like

    from
        l.start
    until
        l.after
    loop
        ... -- Use l.item
        l.forth
    end
    

    In case of remove probably you do not need to call forth.