Friday, March 20, 2009

Parameter checking

One of the worst parts of Delphi’s RTL is the fact that parameters are not being checked for correctness in a function call. What this means is that the offending routine will not function as intended in certain circumstances. This usually leads to “side-effects”. Let’s take the Delete routine in System unit for example:


function TrimStringPart(const S: String;
const C: Char): String;
var
I: Integer;
begin
Result := S;
I := Length(Result);

{ Find the position of character C in the string }
while (I > 0) and (Result[I] <> C) do Dec(I);

{ And remove anything after (+ it) }
Delete(Result, I, Length(Result) - I + 1);
end;

This function will search for a given character in the string starting from the end. The part of the string starting with that character is deleted. This function works as expected in all cases, but a non-Delphi trained developer can spot a problem immediately: What happens if the character is not found in the string? I becomes 0 (zero) and Delete is called with invalid parameters. Well, lucky that Delete is all-forgiving and will simply exit when this happens. The logically correct function would look like this:


function TrimStringPart(const S: String;
const C: Char): String;
var
I: Integer;
begin
Result := S;
I := Length(Result);

{ Find the position of character C in the string }
while (I > 0) and (Result[I] <> C) do Dec(I);

{ And remove anything after (+ it) }
if I > 0 then // <-- CHECK IF CHAR WAS FOUND
Delete(Result, I, Length(Result) - I + 1);
end;

This code adds a check to see if the character was found prior to trying to delete parts of the string. It may be useless since Delete already does this, but it increases the readability of the code. Sadly I too rely on side-effects of Delete sometimes. I do not bother specifying how much to cut from a string if I want everything starting from element I to be removed. I just pass Length(S).

And that makes me wonder: how many applications would break if Delphi would throw exceptions when invalid parameters are passed to a RTL function?

No comments: