A common question asked about Eiffel, especially those coming from Java or C# backgrounds is, where's my try...catch...finally block? Eiffel does provide exception handling mechanisms and the lack of try...catch...finally isn't a language oversight. The underlying reason for the mechanics of Eiffel's exception handling facilities lies in the purpose of routine; a routine should do one operation and either succeed or fail.
Try clauses work well when they're in isolation. When there are multiple try's per routine you run in to a spaghetti of flow control that's too complex to put in to a single routine.
Examples of try block breakdowns:
// The second try block may not be executed depending on whether the catch block suppresses the exception.
// The first try block may not have been executed fully which requires the second try block to query the success of the first try block.
{
try{}
catch{}
try{}
catch{}
}
//This pattern occurs when cleanup in the catch block may fail. The outer and inner try blocks may not have fully completed, the inner try block will have to query to see what parts of the outer try block have completed.
{
try{}
catch
{
try{}
catch{}
}
}
//Yes, I've actually seen a function like this. This example looks a lot more benign than actual implementations with code inserted.
{
try
{
try{}
catch{}
finally
{
try{}
catch{}
}
}
catch{}
}
How can I implement a try...catch...finally pattern in Eiffel? This simple pattern is equivalent to a try block and Eiffel limits it to one "block" per feature.
local
l_no_retry: BOOLEAN
do
if not l_no_retry then
--Try code here
end
l_no_retry := true
-- Finally code here
rescue
if not l_no_retry then
-- Catch code here
l_no_retry := true
retry
end
end
This example may look complex and this is semantically equivalent to a try block. Every time you write a try block this is what you're inferring to the compiler and people who have to maintain your code in the future. This is why try block are easy to write and nest but hard to maintain and be correct.
Just for completeness, an example with a retry counter:
local
l_retry_count: INTEGER
do
if l_retry_count < 3 then
--Try code here
end
l_retry_count := 3
-- Finally code here
rescue
if l_retry_count < 3 then
-- Catch code here
l_retry_count := l_retry_count + 1
retry
end
end

