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.
-
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;
Peter Turner : 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.Gamecat : Ok, that is fine with Delphi ;-).Peter Turner : 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.From Gamecat -
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.
Peter Turner : Yeah something like that'd work in Delphi but but it's probably just as much work as making it object oriented.Brad Gilbert : 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_tableFrom Tanktalus -
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.
From Kristopher Johnson
0 comments:
Post a Comment