I started a wiki topic on defensive programming techniques.
The first chapter is on range errors, how to debug them and how to prevent them.
I tried to write it for both beginners and intermediate programmers.
Tell me what you think. Advice and critique is welcome.
http://wiki.freepascal.org/Defensive_programming_techniques
Looking good so far - thanks!I will certainly take your tips into account. First I will write some subjects on simple proper programming like try/finally, ioresult vs exceptions, string-handling, pointer types, that kind of stuff.
Great stuff, Thaddy.Good suggestion. Feel free to correct any obvious language mistakes (?!) and discuss the above kind of valuable suggestions in this thread. I already have some rephrasing to do for tomorrow. :(
One further suggestion. In the "for in do..." example use an array of Char (or an array of some non-numeric type). This would make the difference between the array index and the array element obvious, and you would not need to say "j is not an index" etc.
It is also worth pointing out the read-only nature of the variable used in the syntax "for element-variable in anArray do", not only because the compiler cannot always detect attempts to alter element-variable's value, but also because it is an unexpected restriction.
I would not waste too much real estate on erroneous code.No - the tutorial is much more instructive this way, with erroneos code.
Show the examples how it should be done and only briefly mention the pitfalls.
No - the tutorial is much more instructive this way, with erroneos code.Of course not.
No - the tutorial is much more instructive this way, with erroneos code.Of course not.
When I want to learn another language, I do not want to first see a long list of erroneous examples.
And then have to dig for the right words or phrases.
I want to see how I can properly use the language elements.
Exactly the same with this.
To make the topic useable, instruct people how to properly use the language constructs (indeed use ranges and predefined set types where applicable).
But do not let them dig through randomly chosen erroneous code fragments and at the end force them to forget all of the above, and make them remember the last bits that supposedly are correct(-ish).
Would be funny if people went to any training, school or course, and half of the time get explained how nót to do something.
Waste of time.
http://wiki.freepascal.org/Defensive_programming_techniques
Thats great, thanks!
I did some trials and the following seems to work as well. I don't like the type cast, but seems not possible without it.
var LabelList:tList; lbl:TLabel; begin ... // initialize lists for pointer(lbl) in LabelList do lbl.Color:= clRed; end;
Alternatively, in this case you could use the TObjectList from Contnrs and the pointer can also be omitted.Just like this? ;D And if you try to compile it?
var LabelList:tObjectList; lbl:TLabel; begin // initialize lists for lbl in LabelList do lbl.Color:= clRed; end;
That is harder than you might think.I just thought you might have forgotten to go on, or other priorities. :)
Alternatively, in this case you could use the TObjectList from Contnrs and the pointer can also be omitted.I just tested, as ASerge said it doesn't compile.
var LabelList:tObjectList; lbl:TLabel; begin // initialize lists for lbl in LabelList do lbl.Color:= clRed; end;
Just like this? ;D And if you try to compile it?Compiles fine with {$mode delphi}.
Compiles fine with {$mode delphi}.Considering that in {$mode delphi} it works also with TList.
But yeah, that should have been mentioned.
I think that syntaxis quite strange. Downcasts from a class (here TLabel) to pointer normally workes implicit. But the variable lbl in the loop is to get assigned. ...
for pointer(lbl) in LabelList do;
var LabelList:tObjectList; lbl:TLabel; begin // initialize lists for lbl in LabelList do lbl.Color:= clRed; end;
If you go all defensive, check if is assigned and as you say, if it's TLabel.I'm guessing some kind of trolling? If not then assign(anyobject that's not nil) will always return true and TxxxxxList will always return <> nil aka the last known correct address.
No. I'm not trolling.well yes assigned should return true unless some one has gone through the list and replaced the address with nil, in which case if xxxx is Tlabel should return false making the assigned check superfluous.
I had that problem for real.
A list of objects linked to UI. When updating the list from internet then objects in UI (listbox) these doesn't exist anymore because was freed and replaced.
So if I understand you correctly it says that is also assigned?Well I don't exactly remember. But you're more experienced than me so I m sure you're right.
I see. Thanks!True local variables are not initialized. but you can write statements like
Now I'm understanding a bit more. Another question: objects in local variables inside a function are not initialized with nil?
Because I had that problems today. Checking for nil to an uninstantiated object something likeyeah the initialization of the global and class fields is more of a function of the memory manager returning memory filled with zeros than a deliberate field initialization from the compiler.
If assigned (obj1) then obj1.free;
And I get exceptions.
Sorry I'm more used to JS that starts with undefined or null.
How about iterations through lists? Like TList and TStrings and descendants. Is it it somehow possible to use the IN keyword there?
for ii in MyList.___ do;
...For TObjectList the enumerator is a TObject, which usually requires casting, and so on.Amendment. TObjectList does not override enumerator, i.e. it uses inherited from TList.
True local variables are not initialized. but you can write statements likewhich will add initialization code to your variables. (if you are not pulling my leg that is).
procedure Test; var MyObj :TLabel = nil; MyText:String = ''; MyInt :Integer = 0; begin end;
Btw ...In this specific example it may seem like overkill since the loop range is also limited to valid values. However it will guard against some faulty refactoring of say the for loop in future, for example substituting the low(anArray) with 0 in the for loop (because it is more "compact"):
[....] var I: Low(anArray)..High(anArray); [....] begin for i := Low(anArray) to High(anArray) do anArray[i] := 100+i; end;
What's the gain to subrange the loop counter (I)? Does that really make sense if it is used in a for low(...) to high(...) loop? Looks like overkill to me.