Recent

Author Topic: for loop initial value  (Read 6208 times)

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
for loop initial value
« on: February 10, 2016, 09:15:57 am »
I'm using Lazarus 1.4.4.

In a for .. do loop, if the upper value is lower than the initial value, the loop is still executed once.

for i := 0 to -1 do
begin
  dosomething <- this is executed once.
end;

It is debatable if this is correct, but it doesn't happen like that in Delphi, and the Free Pascal wiki says that it is not supposed to happen.

Hard to find in the bugtracker, if it isn't there I'll add it.

Edit: it seems to happen when the loop variable is Cardinal and the upper value is negative.
« Last Edit: February 10, 2016, 09:18:26 am by SymbolicFrank »

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
Re: for loop initial value
« Reply #1 on: February 10, 2016, 09:24:05 am »
let me guess, the variable I is a word type (0 to  ....). It should be a type that can handle negative numbers (integer, smallint)
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

Thaddy

  • Hero Member
  • *****
  • Posts: 14359
  • Sensorship about opinions does not belong here.
Re: for loop initial value
« Reply #2 on: February 10, 2016, 09:35:21 am »
Yup.

Otherwise, to be sure, just write:
Code: Pascal  [Select][+][-]
  1. var i:integer
  2. for i := 0 to 0 do
  3.    ...
  4.  

You are asking one too many anyway.
Is this serious?

Because Delphi would also execute your code once ([edit] even a lot of times, this is funny[with tricks, I have to admit, /edit]. Just tested. Now find out what type I am using ;) for i.
« Last Edit: February 10, 2016, 09:39:23 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: for loop initial value
« Reply #3 on: February 10, 2016, 09:44:54 am »
Ok, if it was C(++) I would agree that it is probably not a bug. But (Object) Pascal tends to be logical about things.

Thaddy

  • Hero Member
  • *****
  • Posts: 14359
  • Sensorship about opinions does not belong here.
Re: for loop initial value
« Reply #4 on: February 10, 2016, 09:49:51 am »
Are you a basic or BASIC programmer by education? I know you are not.
Let me "guess" what both compilers do when overflow checking is on....
And (dead giveaway) try casting a signed to an unsigned... ;)

Anyway. It is not a bug.
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8757
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: for loop initial value
« Reply #5 on: February 10, 2016, 09:51:39 am »
Ok, if it was C(++) I would agree that it is probably not a bug. But (Object) Pascal tends to be logical about things.
It is:
Code: Pascal  [Select][+][-]
  1. var
  2.   i: cardinal;
  3. begin
  4.   for i := 0 to -1 do ;
  5. end.
  6.  
Code: Bash  [Select][+][-]
  1. $ fpc test.pas
  2. Hint: End of reading config file /etc/fpc.cfg
  3. Target OS: Linux for x86-64
  4. Compiling test.pas
  5. test.pas(4,23) Error: range check error while evaluating constants (-1 must be between 0 and 4294967295)
  6. test.pas(6) Fatal: There were 1 errors compiling module, stopping
  7. Fatal: Compilation aborted
  8. Error: /usr/bin/ppcx64 returned an error exitcode
  9.  

shobits1

  • Sr. Member
  • ****
  • Posts: 271
  • .
Re: for loop initial value
« Reply #6 on: February 10, 2016, 10:55:16 am »
Just checked it (using Lazarus v1.4.4) doesn't execute anything inside the loop when signed variable is used and compiler reports an error when unsigned variable is used.

so maybe you are doing something wrong.

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: for loop initial value
« Reply #7 on: February 10, 2016, 11:11:37 am »
I just tested it: a runtime error is generated when Range checking is enabled.

Lesson learned: always enable Range- and Overflow checking, to prevent this kind of bugs.


BeniBela

  • Hero Member
  • *****
  • Posts: 906
    • homepage
Re: for loop initial value
« Reply #8 on: February 10, 2016, 11:31:00 am »
These things would not happen if you would not need to declare the for loop variable manually.

FTurtle

  • Sr. Member
  • ****
  • Posts: 292

Thaddy

  • Hero Member
  • *****
  • Posts: 14359
  • Sensorship about opinions does not belong here.
Re: for loop initial value
« Reply #10 on: February 10, 2016, 04:31:33 pm »
These things would not happen if you would not need to declare the for loop variable manually.

Well, any compiler engineer would have trouble to use type inference for loop counters if they can be variable.
That's just one. If you want to script, use a scripting language.
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
Re: for loop initial value
« Reply #11 on: February 11, 2016, 08:44:45 am »
Lesson learned: always enable Range- and Overflow checking, to prevent this kind of bugs.
It's not a bug. Its logical. it's pure math.
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: for loop initial value
« Reply #12 on: February 11, 2016, 10:14:41 am »
It's not a bug. Its logical. it's pure math.
That depends on your mathematical domain. In pure algebra, it's a bug. When working with collections, it's not.

Anyway, I'm a defensive programmer. Things like this:

Code: [Select]
function TMyList.Find(ThisParam: TSomeObject): Integer;
begin
  Result := -1;

  if not Assigned(ThisParam) then Exit;
  ...

are everywhere in my code. And I use Cardinals for indexes, amounts, or loop counters. I only use Integers as function results that should return an index so I can use negative values for errors (mostly just -1).

So, when I have to traverse a list or array, I use "for .. in .. do", except when I have to return an index. Like this:

Code: [Select]
function TMyList.Find(ThisParam: string): Integer;
var
  i: Cardinal;
begin
  Result := -1;

  if (self.Count = 0) or (ThisParam = '') then Exit;

  for i := 0 to self.Count - 1 do
  begin
    ...

(where "self.Count" is a Cardinal as well.) But that "self.Count = 0" shouldn't be needed. And logically, it should make no difference if "i" is Integer or Cardinal.

This should be a non-issue if integers were 64-bits in 64-bits applications. But they're not. Then again, logically it would make more sense to make Cardinals 64-bit, and allow the construction above.

So, it's probably best if I start using Int64 for all indexes, counts and amounts, and make sure Range checking and Overflow checking are enabled. I tend to make custom lists for everything anyway. Except for strings, of course. But it feels wrong to use a data type that allows negative values for those.


I use Lazarus mostly for tools (as I generally have no say about the language for the main project), and data sizes have grown a lot. More than 4 GB for a single item is still uncommon, but more than 2 GB happens regularly. And lists with more than 2^31 items are starting to appear. So it would be the most future-proof option.

Incidentally, that's also why I would want 32-bit unicode. Yes, it makes the memory requirements even larger, but the bottleneck is almost always the processing speed. I happily tell my boss that running one of my tools requires 16 GB of RAM memory. That's rarely an issue. But when it takes more than a day to process, that is often a problem.


That reminds me, what is the maximum amount of items for a "for .. in .. do" construction in a 64-bit application?


Edit: I checked, and a TList (TStringList etc) from the Classes unit can only contain 2^28 (268 million) items. With generic lists it's even only 2^21 (2 million). Enumerators seem to use pointers and check if it is the first or last item (like BOF and EOF), so they're probably safe.
« Last Edit: February 11, 2016, 11:38:41 am by SymbolicFrank »

Zath

  • Sr. Member
  • ****
  • Posts: 391
Re: for loop initial value
« Reply #13 on: February 14, 2016, 02:11:24 am »
Quote
I happily tell my boss that running one of my tools requires 16 GB of RAM memory

Are you serious ?


SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: for loop initial value
« Reply #14 on: February 15, 2016, 11:20:39 am »
Yes? I don't see the problem.

Specifying that it needs 60 GB of SSD storage (as one of my current products) is a bit more problematic, but still doable.

Many of my small projects (conversions, updates imports/exports, reporting and such) take longer than a day to run on the first try, because of the size of the data set. And possibly the amount of database queries.

Telling a customer to wait a few days or taking a server offline for a few days for an update is most of the time not an option.

 

TinyPortal © 2005-2018