I agree that TStringList makes more sense than TList<string>. Generics are useful for types which do not have built-in container- etc. types.
Amazing. Every unit that makes use of TList<string> adds 10k for the executable! wow. That really caught me by surprise.
If you define a new type only in one place, like:
TMyStringList = specialize TList<string>;
and use it in other units, I think it will add 10k total.
Anyway, if you only add strings to a list and later read then out, TStringList is good. Often however it is used in wrong places which leads to poor performance.
If you want to search for strings fast, you sort the list. Then Find() and IndexOf() use binary search O(log2(n)). Good.
In some use cases you must add more items to a list and then search again. Adding items to a sorted list is
very slow. First it does a binary search and then moves a big chunk of existing items a step forward. Same problem when deleting items.
Many Delphi programs do that because traditionally there were no good container libraries.
Now there are choices. For lots of data a HashMap is superior. It uses more memory than some other containers and resizing is "expensive".
A good compromise is a balanced tree. It does a fast binary search when adding and retrieving, but does not need to move data around.
Unit AvgLvlTree in LazUtils has a nice optimized TStringMap, and others like TStringToPointerTree and similar.
LazUtils also has unit LookupStringList with a hybrid unsorted StringList with a fast lookup feature. I don't know if anybody uses it.