In many of my programs I will avoid/reduce/keep close eyes on free/create as much as possible to reduce chance of dangling objects.
Sometimes this means a performance drain.. example:
end; // end means free!
At the start of the procedure, I create.. and at the end of the procedure, I free. This is a simple form of encapsulation.
Many OOP programmers would be wondering what the heck I would be putting objects into a procedure for if I'm doing OOP coding! Well, as many of you might know, I'm no OOP fanboy.. I use OOP sometimes, I don't other times, and I mix and match other times. I actually avoid OOP often when it creates unneeded complexity. You'd be amazed at how many people thank me for my simple code and simple downloads that.. surprisingly, doesn't follow any of the rules over in OOP.Language.Design newsgroups. I'm continually praised and thanked for my simple code that I offer.. I've never heard someone say 'Lars I like this code but it is very complex and hard to understand'. I usually always hear 'I like how simple you made that code, and yet it is powerful'.
The advantage of creating a procedure to wrap the free/create is that you are doing safer programming.. it is almost like a garbage collector. If your free and create is visible in one single procedure then it is much easier to see and manage this dangerous object that otherwise could be dangling if the free and create are too far away from each other in the code.
What about performance
If the DoSomething procedure must go into a loop:
for i:= 1 to 60000 do begin
Then you might be thinking.. WHOA! Performance drop! We have to instantiate that object in the loop each time!
Let me tell you.. performance doesn't matter, if you know how to design code so that it can perform well LATER after some reorganization. And I say this as a speed freak myself who sometimes parses 22,503 websites and grabs them all in one evening using an http connection and a console program (sometimes a gui program). I deal with LOTS of data.. so I know when speed matters and when it doesn't. I design my code so that if I have to optimize in the future.. I can do it.. just by reorganizing buffers and reorganizing code that was originally in loops but can now be pulled out of loops.
Doing lots of parsing helps a programmer become a master at writing slow code that can easily be fast code later.. you get a feel of what really will cause your program to be slow forever or slow temporarily. Anything that is temporarily slow that can easily be moved/adjusted later is a good slow. Anything that will cause permanent slowdown is a bad slow. Lots and lots and lots of parsers you write are slow at first.. and you eventually become a master at writing good slow parsers that can easily be tweaked to be fast. Don't take my word for it, download this file and see the end result of thousands of files that I parsed in one evening from crowded messy disorganized html files off the net.. where I first have to log in using cURL and authenticate.. and all that other slow horrible wonderful stuff.
You can always pull the free/create code out of the procedure and optimize it so that the free/create is called outside the loop later. Most of the time you're code will run fast enough even with the create/free inside the procedure. Some times you don't even need the free/create in the procedure if you use the stack and a record.
Sometimes I write a parser and one of the last performance optimizations is the free/create in the loop.. many times there are other areas to optimize first.. such as using buffers that don't continually allocate each concatenation. Sometimes moving the free and create outside the loop helps and I still try to do that in a way that the free and create are not far apart from each other.. otherwise things can get lost and you can have dangling objects.
Garbage collectors solve some of this problem but there are still ways to keep create/free code clean without using a garbage collector.
Other Ways to Avoid Free/Create
Another way to avoid dangerous free/create is to use the stack... using records or using old objects without constructors/destructors.
Not only is free/create more dangerous code.. it is also more line noise. I find whenever I can hide my free/create or encapsulate it it cleans up my code a lot.. even if the free/create slows down the code when it is hidden away in a procedure that is being called in a loop 1000 times.
(Side note: one advantage of CGI programming is that each CGI program gets killed.. so each CGI program acts like a garbage collector, even if your language isn't garbage collected... if one CGI program has a memory leak, this memory leak will be cleaned up immediately as soon as the page is loaded. )
I find many times modern pascal code is severely bloated with free/create calls.. and people are continually mixing up where to put their try/finally blocks.. and people are continually mixed up whether or not a create/free could cause an exception.. and try/finally's start to get really nested when done correctly (not many people use try/finally/except correctly.. they just throw everything in one block).
This in fact is one of the biggest problems with modern pascal.. the whole verbose try/finally/create/free dangerous code. The compiler does not tell us 'remember to put your free calls in the right place near that finally block but not right there where you are thinking of putting it'.
Already Enough Complexity
Then you've got threads, which add a whole other mess of crap and danger to the program.. I personally avoid threads when I can.. thank goodness cgi programming doesn't require threaded programming.. and for desktop apps I try to create separate executables for some tasks instead of threads.. if possible.. even if it takes a bit more work.. and even if the OS isn't designed for launching processes as much as it is designed for launching threads.. people have such fast computers that launching a process is fast too.
I think one thing modern pascal programmers ignore.. is the fact that OOP programming is extremely dangerous when you have free/create and exceptions. If anything, languages should be lessening our bugs.. and free/create cause bugs.
Am I a fan of garbage collectors? At times.. for example not many people realize that the reference counted ansistring is actually a garbage collected string. One can argue all night and day about whether or not reference counting is a form of garbage collection.. but it is. Imagine you had to free and create each instance of an ansistring. This would be dangerous and too verbose. Oh oh, but hold on.. as soon as I mention that free/create for objects is dangerous and verbose.. people get offended quite easily....
Remember, though.. there are ways to clean up free/create line noise and danger without resorting to a garbage collector. First you can reduce the amount of free and create by building functions that do useful things like how the sysutils and system units are designed.. and second you can encapsulate your free/create code in a way that it is safely freed and created in one spot. When you need to optimize, you pull out the free/create and you use Something.Clear and Something.Cleanup instead of creating and freeing each time inside a loop.
Many modern pascal programmers are very afraid to build 'safe' procedures that wrap OO code since they are continually taught that instantiating and freeing the object is the proper way to code. The object has a life, and is created and then freed. But in many cases, this code below is much safer and much more maintainable:
if s = '' then outln('there was a problem') else String2File(s, 'out.txt');
..compared to this horrible mess below:
// Try here? No.. yes.. no.. unsure..
try // probably here.. but still unsure.. crossing fingers
try // hmm but what if Create throws something? uggh.. cross fingers
SL:= nil; // whoa this line noise, where is the algorithm again?
finally // I hope this finally nest is right.. dunno for sure
HttpGetterFactory:= nil; // ugh.. more line noise
// hmm... not sure if any exceptions need to be trapped either.. there is no
// contract in the function stating what will happen if there is problem.
// but maybe if I read all the docs over again and ensure there won't be ESomeErr
// I'll be okay.. or maybe I won't read the docs and.. forget I mentioned it all.
// cross your fingers! This code stuff is.. good and safe, no? Or is it? Hope!
Don't get me wrong.. this isn't about always avoiding OOp and always avoiding exceptions wherever possible.. it is just about being good at making wrappers. You can still hide all the create and free code inside your wrapper unit. But for creeps sake, don't make the end user have to go through the above hassles just to grab a website off the internet and parse it.. or just to grab some variables stored in an INI file. Because believe it or not.. many cases programmers need to do these simple tasks. Whether it be taking data from a database or taking data from an ugly XML file, or creating a cute TButton on your GUI program, or creating a CGI program..
life has to be simpler if we can make it simpler.
Free and Create do offer us benefits, such as being able to really optimize when we need to (though ComponentPascal and Digital Mars D will give us a good run for our money with their garbage collectors that are fast, as far as I have read/tested).
I'm not such a huge fan of the 'end programmer' or 'end developer' having to use lots of free's and creates, if he can avoid it. We can avoid it by either by using a garbage collector, or encapsulating the creates and frees (yes even by using procedural code that wraps OO code in layers), or we can use reference counting, or we can use a combination of both.. such as using some garbage collected things like ansistrings, and some not garbage collected things. There are clever ways to engineer wrappers, so that you reduce complexity for your end developer or end programmer (and hopefully your end user) even if you don't have the a garbage collector on your side.
And I hate to say this, but I fear that a lot of the people on OOP.Object.Language.Design style newsgroups or the ones that prefer the above verbose nonsense are a bunch of quiche eaters who don't do quantities of real world programming like Lars does. But in Cee it is worse, where you have to do MemAlloc and GetMem and FreeMem and Dealloc kludges.