Some part of my source code are nested inside try statements in order to handle some run time errors, at the same time each and every line must be tried to execute even if the previous line is not executed because of run time error .
currently my code looks like this
try
try
//statement1
except
end;
try
//statement2
except
end;
try
//statement3
except
end;
finally
//something
end;
I am very sure going in the wrong way ,even if the final out put is working well, I have to do this for dozens of lines.
Is there any better way to implement this
If you want each statement to execute then you have to write it the way you have done. Note that in that case may not need the try/finally because you are swallowing all the exceptions.
However, the code does look a bit odd to me. I wonder if you really need each and every statement to execute. Normally you would write:
try
statement1;
statement2;
statement3;
except
//handle exceptions
end;
Then, if there is an exception in statement1, the other two lines will not execute.
However, it would be even more common not to handle exceptions at all and let them float up to some higher level handler. If you are making routine logic decisions using exceptions then that would be considered bad practice.
I think it would be helpful for you to publish some of your code that handles the exceptions and some details of what exceptions you are expecting to occur. Then we could give you some more specific advice.
Related
I have inherited a large code base that is full of constructs like this:
try
DoWhatever;
finally
end;
Sometimes "DoWhatever" involves some fiddling with controls, and very often it's a post to a database, and there are many cases in the code where there IS something in the finally block.
But my understanding is, if there's nothing in the finally block, then the whole try...finally thing is pointless. The code is pretty noisy overall so I'm assuming it was just a placeholder for future code or a holdover from previous code. (There are many placeholders in the code.)
Is my understanding correct or is there some secret double-bluff reverso in Delphi try...finally blocks I've overlooked? (This is Delphi 2010.)
There is no functional purpose to it — it has no effect on the run-time behavior of the program. When control leaves the try section, the program will jump to the finally section, do nothing, and then continue to whatever the next instruction should be (according to how control reached the finally statement), the same as if the try-finally block hadn't been there at all. The only difference will be that the program spends an extra moment before and after the try-finally block as it sets up and clears the control structure form the stack.
It might be that the author had a template that included a try-finally block, but that some instances of that template ended up not needing any cleanup code. Having the code fit a consistent pattern might have made certain automated tasks easier.
The try-finally block might also provide a convenient place to put a breakpoint that triggers after the protected code runs, even in the event of an exception or other premature termination.
To find out why the code has such apparently useless constructs, ask the previous author, or check the commit history.
I have some delphi code, kind of like this:
try
//some code
//occasionally throws an exception here, for example an EIndexOutOfRangeException
//more code...should get skipped if exception is thrown
finally
// there may or may not be any important cleanup code here
end;
The exception in this case is not something that needs handling beyond breaking out of the try block. So, before mad-except was added to the project for error troubleshooting, this code was "working". But now I'm getting bug reports because MadExcept is reporting the uncaught exception.
Related question, MadExcept triggers on try finally indicates the behavior of MadExcept breaking in such circumstance is "expected" because the exception isn't "handled".
I would like some clarification about what my options are as far ways to prevent a mad-except dialog from popping up when this code runs, regardless of whether there's an internal exception being thrown and ignored.
So I'm correct in thinking there's no switch to disable MadExcept from breaking on unhanded exceptions in a try/finally block? And I'm going to need to explictly "catch" the exception even if I wish to ignore it?
Should I be doing something like this (ignore any exception):
try
//some code
//sometimes throws EIndexOutOfRangeException here
//more code...should get skipped if exception is thrown
except do begin end;
end;
or perhaps (ignore a very specific exception):
try
//some code
//sometimes throws EIndexOutOfRangeException here
//more code...should get skipped if exception is thrown
except on E : EIndexOutOfRangeException do begin end;
end;
or maybe it needs to be:
try
try
//some code
//sometimes throws EIndexOutOfRangeException here
//more code...should get skipped if exception is thrown
except on E : EIndexOutOfRangeException do begin end;
finally
// some cleanup code
end;
If all three of those are valid solutions, should I prefer one over the other for any reason?
So I'm correct in thinking there's no switch to disable MadExcept from breaking on unhanded exceptions in a try/finally block?
Yes. try/finally is not exception handling; it's guaranteed cleanup, whether or not an exception occurs. As such, try/finally blocks are completely irrelevant to exception handling tools such as MadExcept.
And I'm going to need to explicitly "catch" the exception even if I wish to ignore it?
Yes. That's how exceptions work. They work their way down the stack until they find a handler that catches them. If no such handler exists, the OS interprets it as a crash and terminates the program. Delphi's TApplication object installs a handler very close to the bottom of the call stack so that your program won't crash, and MadExcept hooks this so that if an exception reaches this point, a report will be generated.
If you want to ignore an exception, yes, you do need to catch it, because what you are doing is formally "handling the exception by catching it at this point in the stack unwinding and ignoring it." That part about "catching it at this point in the stack unwinding" is important, since it means that the stack unwinding halts at that point and the program resumes normal execution. If you just ignored it, (ie. did nothing about it in your code, including not installing an exception handler,) it would continue to unwind the stack all the way to the default handler, whether or not you had MadExcept installed.
So yeah, in this case, example #2 is the correct course of action. Example #3 would be valid too, if you have cleanup code that needs to be performed at this point. But example #1 should never be done under any circumstances because it means you might end up ignoring an exception that you were not anticipating, and then you end up with corruption in your program and you never become aware of it.
It seems to me that you have a fundamental mis-understanding about what finally means.
A finally block does not influence the propagation of an exception. It just ensures that the finally block will execute, even if an exception has been raised, or the normal execution flow has been modified by exit, break etc.
Take the try/finally out and madExcept will still report that the program raised an exception that was not handled.
There are ways to tell madExcept to ignore certain exceptions. For instance some exceptions should be silent. The canonical example of such is EAbort. You would use RegisterExceptionHandler to customise how unhandled exceptions are treated. Although, as I will explain, I doubt this to be the solution for your problem.
What you need to do next is forget about madExcept. You need to work out what to do about this exception. Do you want to handle it here, or do you need to let the exception propagate? Only you can really know that. But madExcept is not the driver here. What must drive your decision is the correct execution of your program. Should the exception be handled or not, to make your program behave correctly? You must get that right first, and then worry about madExcept.
If you need to handle it here, then handle it selectively. Don't catch all exceptions. That's an absolute no-no. But if you handle it here, ask yourself if that is sensible. The code failed to perform some action. Is there some subsequent code that relies on that action succeeding? By handling the error, and ignoring it as you propose, you are forcing all subsequent code to be ambivalent about the success or failure of this action. That seems highly dubious to me.
Now, the exception is EIndexOutOfRangeException. That means you wrote something like A[i] where the value of i is invalid. I cannot think of a scenario where that would be acceptable. So it looks to me that your program contains an error and is simply using an invalid index. You should fix that error properly by not accessing out of bounds. Don't suppress the exception, stop it being raised.
Another way to look at this. How can you tell the difference between your current situation, and that which would arise from writing A[-i] instead of A[i]? Suppressing the exception means that you cannot detect such egregious errors as this.
The bottom line, so far as I can tell, is that madExcept is reporting an error in your code. You should regard madExcept as your friend and listen to what it says. It is telling you that you have a defect in your code that should be fixed.
In many places in some Apps which I maintain , I've found code which uses a try/finally or try/except block in a for loop or if sentence avoiding the use of begin/end
Consider the next code (not production code, just a sample)
{$APPTYPE CONSOLE}
{$R *.res}
uses
Classes,
SysUtils;
Procedure TestNoBeginEnd;
var
i : Integer;
L1 : TStringList;
begin
for i := 1 to 10 do
try
L1:=TStringList.Create;
try
L1.Add('Bar');
L1.Add(IntToStr(i));
L1.Add('Foo');
finally
Writeln(L1.Text);
L1.Free;
end;
except
on E: Exception do
Writeln('Opps '+E.ClassName, ': ', E.Message);
end;
end;
begin
try
TestNoBeginEnd;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
The Question, Is considered a bad practice, code smell or exist any drawback using a try/finally or try/except instead of begin/end in delphi?
UPDATE
I'm sorry by the silly sample code, just for clarify the try/finally and try/except doesn't pretend replace the begin/end , just to avoid to use it (the begin/end) when exist a case when the use of the try/finally or the try/except doesn't requires a begin/ end.
I personally don't see the need to add the extra begin..end around a try..finally/except..end, especially when there is little chance of code being added just before the try or certainly after the end.
That being said, the question would be more whether we need systematically a begin..end after a ..do or a ..then even when there is only a single instruction (in your case a try.. instruction).
It's mostly a question of style and habit, some people prefer to code defensively and systematically put a begin..end, others try to avoid unnecessary lines as much as possible.
When a fair number of lines are involved, I tend to add the begin..end to make the scoping more obvious.
I'd say, use good judgment and see what the chances are that someone (or you) modifying the code later could miss the intended scope.
First things first. Begin/End is not the same as Try/Etc. The latter first denotes a set of instructions, while the second is a single instruction (which contains possibly lots of instructions).
So they are like a hammer and ladder. Different tools for different
jobs.Sure you drive a nail with a ladder but it's not the most
efficient way of dealing with the problem.
Edit:
If I undertand the question (now that you've edit it) you're asking if one try/etc can be used with out a begin/end. Yes you can do this, because try/etc is a single statement. In fact I'd go as far as to say it's probably a good thing to avoid too much no use code.
Before edit:
So what does that mean? Well it means that if an error occurs in that function it's gets logged, but essentially ignored.
Unless there is really good exception handling and the code escalates exceptions or recovers correctly I'd say this was bad practise.
In your sample all the exception handler does is say Opps (oops?). What good is that? Sure it's probably only a sample and as such I'd examine the code to see what it really does. I beleive that the person who wrote this was trying to handle errors generally, but is actually making the reliability of the code far far worse using this pattern.
I use the general case of 'Exception Handlers are for Exceptional Cirmcumstances' where I can recover or I need to let someone/thing know. Mostly I find that no one can handle the error and the system has to degrade as per design. This is where the exception handlers will log safely and pass teh exceptions on.
The latter case I extend to all 'big boundaries in the system'. i.e. I'll collect exceptions at Service/API boundaries and log/wrap appropriately.
(note sometimes bad APIs use Exceptions for non exceptional circumstances, in this case you can safely add an exception handler to wrap the bad design).
Your edit on the question radically changed the question. You should have changed the title at least, and right now I wonder if the question is salvageable at all (-1).
That said, when addressing your original question:
A Try/Finally or Try/Except statement should never be used when a Begin/End statement would suffice. Besides the fact that Try-statements add (tiny or even unnoticeable) extra instructions to the compiled code, they imply code necessities which aren't there:
for I := 0 to Count - 1 do
try
Inc(Rect.Left, Shift);
finally
Inc(Rect.Right, Shift);
end;
Just not do it.
There is nothing wrong with omitting the begin end when a try finally/except wraps the same code in a block for you. Just remember that try-blocks have more overhead than a begin-block. This overhead is usually negligible, but I have found it to make meaningful differences when in loops, specially loops in methods that are referenced repeatedly.
Taking the above details in mind, your example is somewhat poor due to the fact that it adds unneeded overhead repeatedly in the loop. Whenever you can move try blocks out of a loop, it's a good thing. In your example if you MUST have the ability to catch an exception for each loop iteration, the below code would be more efficient, if not, move the except block out also.
Procedure TestNoBeginEnd;
var
i : Integer;
L1 : TStringList;
begin
L1:=TStringList.Create;
try
for i := 1 to 10 do
try
L1.Clear;
L1.Add('Bar');
L1.Add(IntToStr(i));
L1.Add('Foo');
Writeln(L1.Text);
end;
except
on E: Exception do
Writeln('Opps '+E.ClassName, ': ', E.Message);
end;
finally
L1.Free;
end;
end;
When an unhandled exception happens while debugging some code in any procedure/function/method, the debugger stops there and shows the message.
If I now continue debugging step by step, the execution jumps directly from the line that created the exception to the end of the current procedure (if there is no finally block).
Woulnd't it be just as good to continue with the next line of the current procedure?
Why jump to the end of the proc and continue with the calling procedure?
Is this just by design or is there a good reason for it?
An exception is a unexpected situation, that why processings is stopped.
The jump to the end of the procedure is an invisible finally statement to release any locally "allocated" memory, like strings, interfaces, records etc.
If you want to handle a exception the you have to incapsulate the call that can give an exception with try .. except statement, and use an "on" clause to only handle that particular exception that you want to handle.
In the except you can inspect variables in the debugger and in code you can raise the exception again if needed.
In general, an uncaught exception will execute a hidden "finally" in each function on the stack, as it "unwinds" up to an exception handler. This cleans up local variables in each stackframe. In languages like C++ with the Resource Acquisition Is Initialization paradigm, it will also cause destructors to run.
Eventually, somewhere up the callstack, the exception will be caught by a handler. If there's no explicit one, the system-provided one will kill the process, because what else can it reasonably do?
Throwing an exception is a way of saying "Something unexpected happening. I don't know how to handle this". In such case it it better not to do anything (other than throwing the exception) than to try to continue, not knowing if what you're doing is correct.
In real life you have the same kind of thing: If someone asks you to count to 10 in Hebrew (or some language you don't know), you just say you don't know. You don't go ahead and try anyway.
I would expect it to jump to the end of the proc, and then jump to the except or finally block of the calling proc. Does it really continue in the calling proc as if nothing had happened? What does it use as the return value (if it's a function call)?
Continuing with the next line in the original proc/function would be a very bad thing - it would mean the code executing radically differently in a debugger to in release (where the exception would indeed cause execution to exit that proc/function unless there's an except/finally block). Why should debugging let you ignore exceptions completely?
It has to unwind the stack to find a handler.
I do agree it's very annoying behavior. Continuing isn't an option but it sure would make life easier if the debugger was pointing to the spot that threw it with the local variables still intact. Obviously, the next step would be to the hidden finally, not to the next line.
I just want to be able to examine everything I can about what caused it. I was just fighting this not very long ago. Text parsing, I KNEW the offending string contained no non-numeric characters (sanity limits mean the overflow case should never happen, it's my data file, all I'm worried about is oopses) and so I didn't put an exception handler around the StrToInt--what's this nonsense about it not being a valid number????? Yup--the routine wouldn't call it with anything non-numeric in the buffer--but an empty string has nothing non-numeric in it!
In one of our application im getting an exception that i can not seem to find or trap.
...
Application.CreateForm(TFrmMain, FrmMain);
outputdebugstring(pansichar('Application Run')); //this is printed
Application.Run;
outputdebugstring(pansichar('Application Run After')); //this is printed
end.
<--- The Exception seems to be here
The Event log shows
> ODS: Application Run
> //Various Application Messages
> ODS: Application Run After
> First Change Exception at $xxxxxxxx. ...etc
All i can think of is it is the finalization code of one of the units.
(Delphi 7)
Try installing MadExcept - it should catch the exception and give you a stack-trace.
It helped me when I had a similar issue.
Here's two things you can try:
1) Quick and easy is to to hit 'F7' on the final 'end.'. This will step you into the other finalization blocks.
2) Try overriding the Application.OnException Event.
The SysUtils unit actually sets up the default ErrorProc and ExceptProc procedures in its initialization section, and undoes them in its finalization section, so often in this situation it's worth ensuring that SysUtils is the very first unit in the uses clause in your dpr, so then it will be the last one finalised. Might be enough to get you some meaningful data about what is going wrong.
Finalization exceptions are tricky. Even if you put SysUtls first in your project file, your application object may already be gone, which means your global exception handler is gone too. MadExcept may work for this though.
Another solution is to put a Try / Except block in each of your unit finalization sections, and then handle the exceptions there.
What is your objective? Do you want to suppress the exception or debug it? Debugging it can be done by stepping through them with F7 as Zartog suggested. If you discover which unit has the exception in finalization then you might try placing it in a different order in the uses clause it is called from.
Good luck!