procedure RemoveSpaces(StringParameter: string);
You are passing the string parameter by value. Semantically1, a copy is made of the argument you pass, and any modifications made are made to that copy. The caller does not observe the modifications.
You need to pass the parameter by reference. When you pass by reference, the procedure operates on the original variable, and not a copy.
In Pascal, and Delphi, you pass by reference by using the var
keyword. Change
procedure RemoveSpaces(StringParameter: string);
to
procedure RemoveSpaces(var StringParameter: string);
The reason that you observed what appeared to be different behaviour with a TStringList
parameter is that TStringList
is a class which is a reference type. That means that given List: TStringList
then List
is a reference to the object. For more discussion on the distinction between value and reference types see my answer here: Why should we use classes rather than records, or vice versa?
The documentation has this to say on the matter:
A variable of a class type is actually a pointer that references an object. Hence more than one variable can refer to the same object. Like other pointers, class-type variables can hold the value nil
. But you don't have to explicitly dereference a class-type variable to access the object it points to. For example, SomeObject.Size := 100
assigns the value 100
to the Size
property of the object referenced by SomeObject
; you would not write this as SomeObject^.Size := 100
.
Here the documentation is rather more explicit about the fact that class type variables are really just pointers.
You can implement your procedure more efficiently and simply by using the RTL function StringReplace
:
procedure RemoveSpaces(var StringParameter: string);
begin
StringParameter := StringReplace(StringParameter, ' ', '', [rfReplaceAll]);
end;
I would also comment that a function would probably be a better option here. That gives you the flexibility to pass something other than a variable, for instance a literal or a constant. And you can also compose and chain functions more easily.
So this would be
function SpacesRemoved(const str: string): string;
begin
Result := StringReplace(str, ' ', '', [rfReplaceAll]);
end;
And then instead of having to write:
RemoveSpaces(Input);
Writeln(Input);
you can write
Writeln(SpacesRemoved(Input));
1 I said semantically because a string
is a reference type, albeit a special one. The distinction is that if multiple variables refer to the same string object, then when a modification is made, the string is copied to a new object and the modifying variable is given a unique reference. This is known as copy-on-write and has the effect of making the string
data type behave like a value type.