views:

1430

answers:

4

consider the following delphi pascal code:

var
  tc: TComponent
begin
{ do something to get tc }
repeat
  if(tc is TDBEdit)then begin
    if(check_something_about_edit(tc))then break;
    do_something_else_edit(tc);
    break;
  end else if(tc is TBMemo) then begin
    if(check_something_about_memo(tc))then break;
    do_something_else_memo(tc);
    break;
  end;
  raise exception.create('invalid component type');
until(true); {single iteration look required to use break }

I know there's probably some polymorphic stuff that I could do with TComponent, but that's not my question. I'm wondering if there's a way to get rid of the single iteration repeat-until statement. Without it, I can't use the break statement anywhere in the processing block, and I need that to stop processing at any time.

+4  A: 

Pack it into a function and use exit to jump back. if there is more code to follow the repeat statement, use a local function/procedure, something like:

procedure ...
  procedure testsomething(tc: TComponent);
  begin 
    if(tc is TDBEdit)then begin
      if(check_something_about_edit(tc))then exit;
      do_something_else_edit(tc);
      exit;
    end else if(tc is TBMemo) then begin
      if(check_something_about_memo(tc))then exit;
      do_something_else_memo(tc);
      exit;
    end;
    raise exception.create('invalid component type');
  end;

var
  tc: TComponent;
begin
{ do something to get tc }
  try
    TestSomething(tc);
    { do something more }
  except
     ...
  end;
end;
Ralph Rickenbach
while the if-else solution is more correct in this specific case, this solution is more applicable to the real-life case. It requires moving a bunch of code around, but that's OK. I prefer to have things correct.
David Dombrowsky
+4  A: 

What you are actually doing is using break as a goto. Ralph's suggestion to use a function as a scope is a good one. But otherwise you might as well be honest and use a 'goto finished'. Losing the repeat will make it actually more readable.

Henk Holterman
hmmm, a case where a goto is actually /less/ evil than a break. Strange days...
David Dombrowsky
Well, you came up with a very evil use of break. And break/continue are structured goto's anyway.
Henk Holterman
+13  A: 

There is another easy way to go:

if(tc is TDBEdit)then begin
  if not (check_something_about_edit(tc)) then
    do_something_else_edit(tc);
end else if(tc is TBMemo) then begin
  if not (check_something_about_memo(tc)) then
    do_something_else_memo(tc);
end else
  raise exception.create('invalid component type');
end;
Ralph Rickenbach
I think this is a much better alternative than the first one you posted.
Rob Kennedy
so do I, but it took a while to get through the code ;)
Ralph Rickenbach
I leave the other one in, maybe it can be usefull in a similar setting.
Ralph Rickenbach
This is how I re-wrote it this afternoon. As usual, putting in the "breaks" made the code work and only took about 10 minutes to do. Making the code correctly took another hour to make sure all my if-else's lined up correctly. Its just a problem I've faced before and I was more wondering if it was EVER correct to use a single interation loop just so you could use the break statement.
David Dombrowsky
I agree with Ralph and Rob....
Fabricio Araujo
+1  A: 

Why do you want to use break rather than Exit? Break in Delphi is not the same as "break" in the curly brace languages.

var
  tc: TComponent
begin
  { do something to get tc }
  if (tc is TDBEdit) then 
  begin
    if not (check_something_about_edit(tc)) then 
      do_something_else_edit(tc);
    Exit;
  end;
  if (tc is TBMemo) then 
  begin
    if not (check_something_about_memo(tc)) then 
      do_something_else_memo(tc);
    Exit;
  end;
  raise exception.create('invalid component type');
end;

A point about layout. If you didn't try to reduce whitespace so much it mightn't take "another hour to make sure all my if-else's lined up correctly" as you said in an earlier comment.

If you have code that you want to execute after this, either use Ralph's suggestion of a local procedure, or wrap in a try..finally - the code in the finally will still be executed.

Gerry