articleThe rescue clause does not work

creative.bachkhoa's picture

I've tested the system by an example of exception handling in Eiffel

 <eiffel>
feature {NONE} -- Initialization
    i:INTEGER
    x:REAL
    y:ARRAY[REAL]
    make
            -- Run application.
        do
            create y.make(1,2)
            io.put_string ("The item at position: ")
            io.read_integer
            i:=io.last_integer
            find
            io.put_string (" is: ")
            io.put_real (x)
            io.put_string ("%NReturn to make is successful")
        end

        -----------------------------------------------
    find
        require
            i<=2
        local
            no_retry:BOOLEAN
        do
            if not no_retry then
                x:=y.item (i)
                io.put_real (x)
            end
            no_retry:=true
        rescue
            if not no_retry then
                io.put_string ("Can not execute instruction")
                no_retry:=true
            end
        end

        ---------------------------
end
</eiffel> <code>
When the precondition is violated, the rescue clause take no action

Can anybody help me fix this error?
I am using EiffelStudio - 6.4 GPL (Official Release)

Thanks very much!

Comments

No violation

schoelle's picture

Why should the rescue clause be triggered? There is not contract violation in find. The precondition is an obligation to the caller, so the contract violation actually happens in the caller. Try adding a rescue clause to make.

"There is not contract

creative.bachkhoa's picture

"There is not contract violation in find"

 Thanks you for your reply.
 But, there is violation. When I input i the value 3. The precondition fails. But no retry is made
 There is an other example that make me trouble.

 
create
    make

feature {NONE} -- Initialization
  r:REAL
  make
    do
        io.put_string ("Input a number ")
        io.read_real
        r:=io.last_real
        io.put_string ("Inverse of ")
        io.put_real (r)
        io.put_string (" is ")
        io.put_real(quasi_inverse (r))
    rescue
        retry

    end
            ----------------------------

    quasi_inverse (x: REAL): REAL is
        -- 1/x if possible, otherwise 0
    require
        x/=0
    local
        division_tried: BOOLEAN
    do
        if not division_tried then
            Result := 1/x
        else
            io.put_string ("Divide by zero")
        end
    end
end

  Can you help me? I am just a beginner.

Contract violations aren't

Contract violations aren't exceptions, they aren't supposed to be caught in a retry clause.

The require clause:

require i <= 2


Doesn't mean an exception will be raised if i is greater than 2, it means you have a program bug that needs to be fixed because someone called find while i was bigger than 2.

Before you call `find' you should have a function that checks to make sure i <= 2 and take an appropriate measure if it is not.

A precondition violation

colin-adams's picture

A precondition violation DOES raise an exception (assuming that the OP has precondition monitoring turned on). The point is (as Bernd pointed out) that precondition violations are raised in the client, not the supplier. Colin Adams

I don't know much about violation and exception.

phundinhvu's picture

When is an exception occured. that is when pre or postcondition is violated. And how can we control the exception or violation. In java, we can do it by try and proper catch block, and then we can prcess it in our way with proper exception. In eiffel, i don't know how can we do this? Any more, i know when we use condition we often use this: positive : account > 0

But the word positive use for what purpose ?

Try these functions for an

Try these functions for an example of the difference in exceptions:

make do one two end

one -- Exception in `proc' require clause is raised in *calling* function, `one' local retried: BOOLEAN value: INTEGER do if not retried then value := proc (3) end rescue retried := True retry end

two -- Exception in `proc' ensure clause is raised in *called* function, `proc' local value: INTEGER do value := proc (2) end

proc (i: INTEGER): INTEGER require i <= 2 local retried: BOOLEAN do if not retried then Result := 2 * i end ensure Result <= 3 rescue retried := True Result := 3 retry end


When an exception is in the `require' clause, the exception is raised in the *calling* function. When an exception is in the `ensure' clause, the exception is raised in the *called* function.

Thanks

phundinhvu's picture

Phung Dinh Vu- Hut Now I understand little. I'm coding for check. Thank "Colin LeMahieu" very much. ohm, Can I ask you a question ? LeMahieu is likely a vietnames name. Are you VietNames?

Tags appear in error messages

colin-adams's picture

The "positive:" part is the assertion tag.

When you are monitoring assertions, if an aseertion fails, the tag will be printed as part of the error message. This helps you track down which assertion actually failed.

Colin Adams

Can't control exception or violation.

phundinhvu's picture

Thank LeMahieu. I have fixed your code like this:

class
    EXCEPTION2

create
    make

feature {ANY}

    make
        do
            io.put_string ("Entry make%N")
            one
            two
            io.put_string ("Exit make")
        end

    one
        -- Exception in 'proc' require clause is raised in *calling* function, 'one'
        local
            retried: BOOLEAN
            value: INTEGER
        do
            io.put_string ("you call one method%N")
            if not retried then
                value := proc (3)
            end
        rescue
            io.put_string ("You call one's rescue%N")
            retried := True
            retry
        end -- one

    two
        -- Exception in 'proc' ensure clause is raised in *called* function, 'proc'
        local
            value: INTEGER
        do
            io.put_string ("you call two method%N")
            value := proc (2)
        end -- two

    proc (i: INTEGER): INTEGER
        require
            i <= 2
        local
            retried: BOOLEAN
        do
            io.put_string ("you call proc method%N")
            if not retried then
                Result := 2 * i
            end
        ensure
            Result <= 3
        rescue
            io.put_string ("You call proc's rescue%N")
            retried := True
            Result := 3
            retry
     end -- proc

end
When i run this class by press F5, the screen only view like this:

screen_F5.jpg

And in the feature, cussor stop at instruction :

    i <= 2
When I debug each instruction by press F10. The screen is likely:

screen_F10.jpg


I meant when I debug the screen view like I hope it would be. My question is: Why is there diffrent from two that way, when I use F5 to run, and when I use F10 to bug ? Any more, I know that use F5 to run file, when the violation or exception is occured the programme will stop and not excute any more, but I don't hope such that. How can I fix this? I mean in Java I can catch the exception and process it in proper way, and when I press F5 to run Java file, and when an exception occur and catch, the programme won't stop and continue excute. See this example:

public class Except {
   
    public Except(){
        int a = 0;
        System.out.println ("Enter construction method");
        try{
            System.out.println (1/a);
        }
        catch(Exception e){
            System.out.println (e.toString ());
        }
        System.out.println ("Exit construction method");
    }
    public static void main(String[] args) {
        new Except();
    }
}
And the out put screen is:
Enter construction method
java.lang.ArithmeticException: / by zero
Exit construction method

Process completed.
As you see "Exit construction method" is still viewed in the screen. In eiffel I don't see it. How can you explain this? Best wishes !

By default when debugging

By default when debugging Eiffel Studio will stop when an exception happens.

You can change this by going to menu -> Execution -> Exception handling -> POSTCONDITION_VIOLATION (ensure) -> Disable / Catch / *Ignore*.

This is how to get it to do what you want.

I would recommend against using postcondition failures and precondition failures as normal exceptions because this isn't their intent. "Assertion Violation rule: A run-time assertion violation is the manifestation of a bug."

Read http://docs.eiffel.com/eiffelstudio/general/guided_tour/language/tutorial-09.html

Thanks LemaHieu very much!

creative.bachkhoa's picture

I've tried running your example, it run well. I also take some other tests based on your example. But there is still things I don't understand.

  In the Exception Handling mode, the PRECONDITION and POSTCONDITION have there modes: disable, ignore, catch . Can you explain to me what is the difference between disable and catch?
 I hope your reply based on contract view. Actually, I'd like to explore the semantics and philosophy in Eiffel. 
I think you are very good at eiffel programing. Thanks you again!
Syndicate content