views:

354

answers:

3

Can it be known in general whether or not placing a case within a for loop will result in bad assembly. I'm interested mainly in Delphi, but this is an interesting programming question, both in terms of style and performance.

Here are my codez!

  case ResultList.CompareType of
  TextCompareType:
    begin
      LastGoodIndex := -1;
      for I := 1 to ResultList.Count -1 do
      if (LastGoodIndex = -1) and (not ResultList[I].Indeterminate) then
        LastGoodIndex := I
      else if not ResultList[I].Indeterminate then
      begin
        if (StrComp(ResultList[LastGoodIndex].ResultAsText,
                     ResultList[I].ResultAsText) > 0)
            and (Result  FalseEval) then
          Result := TrueEval
        else
          Result := FalseEval;

        LastGoodIndex := I;
      end;
    end;
  end;
  NumericCompareType:
  begin
    //Same as above with a numeric comparison
  end;
  DateCompareType:
  begin
    //Same as above with a date comparison
  end;
  BooleanCompareType:
  begin
    //Same as above with a boolean comparison
  end;

alternatively I could write

    begin
      LastGoodIndex := -1;
      for I := 1 to ResultList.Count -1 do
      if (LastGoodIndex = -1) and (not ResultList[I].Indeterminate) then
        LastGoodIndex := I
      else if not ResultList[I].Indeterminate then
      begin
      case ResultList.CompareType of
      TextCompareType:
      begin
         if (StrComp(ResultList[LastGoodIndex].ResultAsText,
                     ResultList[I].ResultAsText) > 0)
            and (Result  FalseEval) then
           Result := TrueEval
         else
           Result := FalseEval;
         LastGoodIndex := I;
      end;
      NumericCompareType:
      begin
       //Same as above with a numeric comparison
      end;
      DateCompareType:
      begin
       //Same as above with a date comparison
      end;
     BooleanCompareType:
     begin
       //Same as above with a boolean comparison
     end;

   end;
  end;
 end;

I don't like the second way because I'm asking a question I know the answer to in a for loop and I don't like the first way because I'm repeating the code I use to figure out which of my objects contain valid information.

Perhaps there is a design pattern someone could suggest that would circumvent this all together.

+2  A: 

Why not using subclasses?

This saves the use of the case statement.

TComparer = class 
protected
  function Compare(const AItem1, AItem2: TItem): Boolean; virtual; abstract;
public
  procedure DoCompare(ResultList: ...);
end;

TTextComparer = class (TComparer)
protected
  function Compare(const AItem1, AItem2: TItem): Boolean; override;
end;

procedure TComparer.DoCompare(ResultList: ...);
var
  LastGoodIndex, I : Integer;
begin 
  LastGoodIndex := -1;
  for I := 1 to ResultList.Count -1 do
  if (LastGoodIndex = -1) and (not ResultList[I].Indeterminate) then
    LastGoodIndex := I
  else if not ResultList[I].Indeterminate then begin
    if Compare(ResultList[LastGoodIndex], ResultList[I]) then
      Result := TrueEval
    else 
      Result := FalseEval;
  end;
end;

function TTextComparer.Compare(const AItem1, AItem2: TItem): Boolean; 
begin
  Result := StrComp(ResultList[LastGoodIndex].ResultAsText,
    ResultList[I].ResultAsText) > 0)    
end;
Gamecat
In this program I am, quite a bit (for me) in fact, but it's not perfect and here I'd like to just write some structured code.
Peter Turner
Ok, that is fine with Delphi ;-).
Gamecat
Wow I guess I'll do that. good point, I shouldn't have even had to ask that question. I'm not going to say it's the answer, because it's the answer to, "why shouldn't I use a case statement". But thank you nonetheless.
Peter Turner
+1  A: 

I suspect that it's more efficient to use a lambda or closure or even just a function reference. My Pascal's rusted right out, so my example is perl:

my %type = (
            TextCompareType => sub { $_[0] lt $_[1] },
            NumericCompareType => sub { $_[0] < $_[1] },
            DateCompareType => sub { ... },
            BooleanCompareType => sub { ... },
           );

for (my $i = 1; $i <= $#list; ++$i)
{
    if ( $type{$ResultList{CompareType}}->($list[$i-1], $list[$i]) )
    {
        $result = 1; # ?
    }
}

I'm not really following most of your code, but I think I've captured the essence of the question without fully capturing the code.

Another solution is to create comparator objects as subclasses off a base comparator class, and then call the object's compare function, but you do mention trying to stay structured instead of OO.

Tanktalus
Yeah something like that'd work in Delphi but but it's probably just as much work as making it object oriented.
Peter Turner
This is known as a jump table, or branch table. It gets its name from ASM, when it really was an array of jmp opcodes. http://en.wikipedia.org/wiki/Branch_table
Brad Gilbert
+4  A: 

In general, there is no way to know what assembly-language output will be generated for particular programming-language constructs. Every compiler is different. Even for a particular compiler, every application will be different, and the compiler will have different optimization strategies available to it.

If you are really worried about it, the easiest thing to do is compile the program and see what it generates. Play around with code and optimization settings until it looks how you want it to. (Or write assembly by hand.)

The common advice is to just write the clearest code you can, and don't worry about tweaking performance unless you really need to.

Kristopher Johnson