Recent

Author Topic: Defensive programming  (Read 16617 times)

taazz

  • Hero Member
  • *****
  • Posts: 5364
Re: Defensive programming
« Reply #45 on: April 12, 2018, 05:20:15 am »
I see. Thanks!

Now I'm understanding a bit more. Another question: objects in local variables inside a function are not initialized with nil?
True local variables are not initialized. but you can write statements like
Code: Pascal  [Select][+][-]
  1. procedure Test;
  2. var
  3.   MyObj :TLabel = nil;
  4.   MyText:String = '';
  5.   MyInt  :Integer = 0;
  6. begin
  7. end;
  8.  
which will add initialization code to your variables. (if you are not pulling my leg that is).
Because I had that problems today. Checking for nil to an uninstantiated object something like

If assigned (obj1) then obj1.free;

And I get exceptions.

Sorry I'm more used to JS that starts with undefined or null.
yeah 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.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

howardpc

  • Hero Member
  • *****
  • Posts: 3779
Re: Defensive programming
« Reply #46 on: April 12, 2018, 10:19:20 am »
How about iterations through lists? Like TList and TStrings and descendants. Is it it somehow possible to use the IN keyword there?

Code: Pascal  [Select][+][-]
  1. for ii in MyList.___ do;

Provided the list has an enumerator (of type TEnumerator) you can iterate using the Object Pascal "for x in list_of_x do ..." syntax.
Most RTL container classes come with one or more enumerators already.
If there is no built-in enumerator, you can write one yourself, and FPC is sufficiently well-designed to use the enumerator you provide.
The enumeration, of course, is based on the type of the element in the container. So for TList and TFPList which which are basically arrays of pointers the enumerator assumes a pointer element, which then usually required casting. For TObjectList the enumerator is a TObject, which usually requires casting, and so on. But delphi mode is not as strict as objfpc mode, so in some cases a cast is not required.
From the point of view of defensive programming, the looser delphi mode is less type-safe, but perhaps more convenient.

A dynamic array of TLabel gives you both type-safety and built-in "for ... in ... do" syntax, and no need for any casting.
Of course it is not "generic" either, like TList, holding only TLabel references and nothing else.
Code: Pascal  [Select][+][-]
  1. type
  2.   TLabelList = array of TLabel;
  3. ...
  4. var
  5.   Llist: TLabelList;
  6.   lbl: TLabel;
  7. begin
  8.   // initialise Llist ...
  9.   for lbl in Llist do
  10.     lbl.Color := clRed;
  11.     ...
In this code the compiler will stop you using anything but a TLabel as the enumerator.
The compiler also prevents you from doing any kind of assignment to the loop variable lbl. It is read-only.
« Last Edit: April 12, 2018, 10:26:02 am by howardpc »

ASerge

  • Hero Member
  • *****
  • Posts: 1868
Re: Defensive programming
« Reply #47 on: April 12, 2018, 05:06:00 pm »
...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.

Thaddy

  • Hero Member
  • *****
  • Posts: 10920
Re: Defensive programming
« Reply #48 on: April 12, 2018, 05:56:46 pm »
That's true, but it works without a cast because of the result type of TObjectList. That should - but not tested - also work in ObjFpc mode not only in delphi mode.
The average programmer productivity is 4-5 hours per day. Peak performance 72 hours for short bursts. MTBF is 1 second or less.

lainz

  • Hero Member
  • *****
  • Posts: 3848
Re: Defensive programming
« Reply #49 on: April 15, 2018, 10:39:24 pm »
True local variables are not initialized. but you can write statements like
Code: Pascal  [Select][+][-]
  1. procedure Test;
  2. var
  3.   MyObj :TLabel = nil;
  4.   MyText:String = '';
  5.   MyInt  :Integer = 0;
  6. begin
  7. end;
  8.  
which will add initialization code to your variables. (if you are not pulling my leg that is).

Thanks, I did not use that too much.

And no, I'm beign serious, I really don't know everything about Pascal.

Maybe I've readed that some day in the manual, but with no using it directly, problems happens, and I sometimes can't figure why.

damieiro

  • Full Member
  • ***
  • Posts: 188
Re: Defensive programming
« Reply #50 on: August 29, 2021, 07:21:58 pm »
Hi thaddy!

Sorry for kicking this topic (>120 days) but i liked a lot the view of the tutorial, and even oldies can learn from it (me too :) )

Really I like it like a "good practices" in coding not only for defensive programming (and even offensive ones, i like this branch of defensive coding too)

Is this project continuated or something like good practices and book of examples (more than code snipets) i have see on wiki?

I think not knowing only what to do, but knowing why is should be do is a great engineer job. And i see this article as a little gem.
Are there more communty jobs like it? How can be started this job or continue yours? (i would like to make a "good practices wiki reviewed/written by all community).



Nimral

  • Full Member
  • ***
  • Posts: 186
  • Keep it simple.
Re: Defensive programming
« Reply #51 on: August 30, 2021, 02:20:12 pm »
Advocate this! Being somewhere in between beginner and mediocre Pascal programmer I read the wiki with interest, and looked forward for the missing parts. They'd provide more insight into why some code looks over-complicated at first, but here you get the reasons why the really experienced guys do sometimes write a couple of lines more to prevent common mistakes.

Unfortunately it was never continued.

Armin.

Btw ...
Code: Pascal  [Select][+][-]
  1. [....]
  2. var
  3.       I: Low(anArray)..High(anArray);
  4. [....]
  5. begin
  6.       for i := Low(anArray) to High(anArray) do anArray[i] := 100+i;
  7. end;
  8.  

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.

« Last Edit: August 30, 2021, 06:39:33 pm by Nimral »
Lazarus 2.0.12 & 2.3.0  (trunk) on Windows 10, Raspberry Pi OS "Buster", macOS Catalina, macOS BigSur, VMWare Workstation 15

ccrause

  • Sr. Member
  • ****
  • Posts: 447
Re: Defensive programming
« Reply #52 on: August 30, 2021, 02:54:51 pm »
Btw ...
Code: Pascal  [Select][+][-]
  1. [....]
  2. var
  3.       I: Low(anArray)..High(anArray);
  4. [....]
  5. begin
  6.       for i := Low(anArray) to High(anArray) do anArray[i] := 100+i;
  7. end;
  8.  

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.
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"):
Code: Pascal  [Select][+][-]
  1. [....]
  2. var
  3.       I: Low(anArray)..High(anArray);
  4. [....]
  5. begin
  6.       for i := 0 to High(anArray) do anArray[i] := 100+i;
  7. end;

Now if anArray is declared as follows:
Code: Pascal  [Select][+][-]
  1. var
  2.   anArray: array[1..10] of integer;
and the above modified for loop is compiled you should get a compile time error, as explained in the article.

Zvoni

  • Hero Member
  • *****
  • Posts: 734
Re: Defensive programming
« Reply #53 on: August 30, 2021, 03:09:31 pm »
Addition to ccrause: Don't forget the use of Sets.
Like the article explained it's very easy that way to walk through an array just accessing the "odd" members
One System to rule them all, One IDE to find them,
One Code to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
People call me crazy, because i'm jumping out of perfectly fine aircraft

damieiro

  • Full Member
  • ***
  • Posts: 188
Re: Defensive programming
« Reply #54 on: August 30, 2021, 04:52:41 pm »
I love the Sets part of the article. I have misused them a lot.

For the defensive techiques are some universal ones (not only languaje driven)
A classic "defense" for indexes is like that:

Code: Pascal  [Select][+][-]
  1. program dtp_1d2;
  2. {$mode objfpc}{$R+}
  3.  
  4. const
  5.   anArrayIdxL=0;  //or other kind of naming
  6.   anArrayIdxH=9;
  7.  
  8. var
  9.   anArray:array [anArrayIdxL..anArrayIdxH] of integer;
  10.   i:shortint; // it can be as a set, like thaddy shows. i:anArrayIdxL..anArrayIdxH, but too verbose to my taste
  11.  
  12. begin
  13.   // data to show what for in do does
  14.   for i := anArrayidxL to anArrayidxH do
  15.   begin
  16.     anArray[i] := i;
  17.     write(anArray[i]:3);
  18.   end;
  19.  
  20.   readln;
  21. end.  
« Last Edit: August 30, 2021, 04:54:52 pm by damieiro »

Thaddy

  • Hero Member
  • *****
  • Posts: 10920
Re: Defensive programming
« Reply #55 on: September 27, 2021, 08:55:09 pm »
Finally, from Oct 1st I have some time left to add to my article. I will keep you posted for updates.
The average programmer productivity is 4-5 hours per day. Peak performance 72 hours for short bursts. MTBF is 1 second or less.

 

TinyPortal © 2005-2018