Recent

Author Topic: [SOLVED] Bug? in IfThen  (Read 640 times)

egsuh

  • Full Member
  • ***
  • Posts: 200
[SOLVED] Bug? in IfThen
« on: July 21, 2019, 12:17:05 pm »
Hi,
There is a useful function IfThen, which is used like

Quote
function NthValue(n:integer):integer;
begin
    result := IfThen (Length(VarArray) <= n, -1, VarArray[n]);
end;

But it seems that there occurs an error if the length of VarArray is smaller than n.

Following codes do not cause errors.

Code: Pascal  [Select]
  1.    if Length(VarArray) <= n then Result := -1 else Result := varArray[n];
  2.  

I think the reason may be lies in that VarArray[n] is accessed when used in IfThen function, regardless of whether the if condition is met or not. 

Is this intended or a kind of bug?
« Last Edit: July 22, 2019, 09:04:27 am by egsuh »

lucamar

  • Hero Member
  • *****
  • Posts: 1944
Re: Bug? in IfThen
« Reply #1 on: July 21, 2019, 12:35:57 pm »
IfThen() is a normal function so all its arguments have to be processed before the call is made.

If n is bigger than the array's length, then, VarArray[n] will fail, as it should. I guess you're getting a range error or a seg fault, aren't you?
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

jamie

  • Hero Member
  • *****
  • Posts: 1759
Re: Bug? in IfThen
« Reply #2 on: July 21, 2019, 04:20:58 pm »
looks like it is being used backwards in the first place ..

Code: Pascal  [Select]
  1. function NthValue(n:integer):integer;
  2. begin
  3.     //result := IfThen (Length(VarArray) <= n, -1, VarArray[n]);
  4.    Result := IfThen(Length(VarArray) <= n, VarArray[n], -1);
  5. end;
  6.  
The resulting is TRUE then False;
But regardless of that, it will still index out of bounds while entering the function so this isn't really that
useful in this regard.

Kays

  • Full Member
  • ***
  • Posts: 170
  • Whasup!?
    • KaiBurghardt.de
Re: Bug? in IfThen
« Reply #3 on: July 21, 2019, 04:50:41 pm »
Lol, I just had a “brilliant” idea:
Code: Pascal  [Select]
  1. {$modeSwitch arrayOperators+}
  2. function nthValue(n: integer): integer;
  3. begin
  4.         result := (varArray + [-1])[min(n, length(varArray))];
  5. end;
Just construct your array on the fly %).
Yours Sincerely
Kai Burghardt

Thaddy

  • Hero Member
  • *****
  • Posts: 8481
Re: Bug? in IfThen
« Reply #4 on: July 21, 2019, 05:40:39 pm »
What version of FPC are you using? During development of the generic ifthen<T>() I noticed a bug, but after I introduced that one, it was not there anymore (not related but an observation).
So 3.0.4. and before may have had- small - problems, but 3.2.0 is OK. Otherwise it would have turned up in the test suite.
Read the manuals and if you are a professional get a proper education in computer science. Makes the forum a lot cleaner.

jamie

  • Hero Member
  • *****
  • Posts: 1759
Re: Bug? in IfThen
« Reply #5 on: July 21, 2019, 06:52:07 pm »
The only way I can see that working as a function is for the compiler to emit a default value if the index is out of range. But that of course is bad debugging day since a default value could be a -1 in this case, but then again the array could have a -1 in it for a valid entry so what do you do?

 This is why this type of function used this way is kind of unless. You need to ensure the range is valid before even calling it.


bytebites

  • Full Member
  • ***
  • Posts: 190
Re: Bug? in IfThen
« Reply #6 on: July 21, 2019, 07:56:41 pm »
Code: Pascal  [Select]
  1. var a:array of integer;
  2. i:integer;
  3. begin
  4.   setlength(a,5);
  5.   i:=-1;
  6.   ifthen<integer>(i<0,0,a[i]);
  7. end;

What this crap does?

Thaddy

  • Hero Member
  • *****
  • Posts: 8481
Re: Bug? in IfThen
« Reply #7 on: July 21, 2019, 08:25:35 pm »
What this crap does?
Well, simply check the 3.2.0 documentation..... :D
BTW, I would first do a range check. Your code is crap.  :P
Read the manuals and if you are a professional get a proper education in computer science. Makes the forum a lot cleaner.

lucamar

  • Hero Member
  • *****
  • Posts: 1944
Re: Bug? in IfThen
« Reply #8 on: July 21, 2019, 08:44:19 pm »
Code: Pascal  [Select]
  1. var a:array of integer;
  2. i:integer;
  3. begin
  4.   setlength(a,5);
  5.   i:=-1;
  6.   ifthen<integer>(i<0,0,a[i]);
  7. end;

What this crap does?

By itself, as it is? Nothing, since you're not using or assigning IfThen's return value. As a side effect? If it doesn't bomb out with an exception at least you know i is a valid index.

The question really is that, for all its "usefullnes", using IfThen() to both check the index and  access the array is a very bad idea. One should, instead, rely on an old and trusty if ... then ... else ..., embedding it in a function if needed:
Code: Pascal  [Select]
  1. function NthElement(n: Integer; AnArray: TIntegerArray; DefVal: Integer): Integer;
  2. begin
  3.   if (n >= Low(AnArray)) and (n <= High(AnArray)) then
  4.     Result := AnArray[n]
  5.   else
  6.     Result := DefVal;
  7. end;

ETA: I forgot ...
Don't try to shorten the index check by testing just against Length(AnArray).

Zero (0) is usually a valid index but it's also the length of an empty array, so the result of code such as:
Code: Pascal  [Select]
  1. function TTestApp.NthElement(n: Integer; IntArr: TIntegerArray): Integer;
  2. begin
  3.   if Length(IntArr) <= n then
  4.     Result := IntArr[n]
  5.   else
  6.     Result := 0;
  7. end;
  8.  
  9. procedure TTestApp.DoRun;
  10. begin
  11.   Writeln('Array Length: ', Length(AnArray),
  12.           LineEnding,
  13.           'Element 0   : ', NthElement(0, AnArray));
  14.   Terminate;
  15. end;
is, as should be expected:
Array Length: 0
Element 0   : Exception at 080480E0: EAccessViolation:
Access violation.
« Last Edit: July 21, 2019, 09:13:21 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.

Thaddy

  • Hero Member
  • *****
  • Posts: 8481
Re: Bug? in IfThen
« Reply #9 on: July 22, 2019, 07:47:15 am »
you can also nest the ifthen's, but all the given solutions are way too complex when you can do simply this:
You can simply protect the range like so:
Code: Pascal  [Select]
  1. {$mode delphi}
  2. uses sysutils;
  3. var
  4.   i:integer = 3;
  5.   a:array of integer = [1,2,3,4,5];
  6. begin
  7.  writeln(ifthen<integer>((i<0) or (i>High(a)) ,0,a[i]));
  8. end.
Prints 4 
« Last Edit: July 22, 2019, 08:39:08 am by Thaddy »
Read the manuals and if you are a professional get a proper education in computer science. Makes the forum a lot cleaner.

egsuh

  • Full Member
  • ***
  • Posts: 200
Re: Bug? in IfThen
« Reply #10 on: July 22, 2019, 09:04:14 am »
Yes... it gives access violation error.  Currently I'm using Lazarus version 2.0.2, and FPC 3.0.4.   

Thank you for all your ideas, but I have no problem in typing "if..then..else...". 
The reason I'm thinking IfThen is just for readability, nothing else.

I need to be more careful, so that all the arguments (even those which will not be used actually) have valid values. 

Thaddy

  • Hero Member
  • *****
  • Posts: 8481
Re: [SOLVED] Bug? in IfThen
« Reply #11 on: July 22, 2019, 09:15:10 am »
In that case you can use
Code: Pascal  [Select]
  1. {$mode delphi}
  2. uses math;
  3. var
  4.   i:integer = 3;
  5.   a:array of integer = [1,2,3,4,5];
  6. begin
  7.  writeln(ifthen((i<0) or (i>High(a)) ,0,a[i]));
  8. end.
3.0.4 does not have the generic ifthen, I added it in 3.1.1, so it is in 3.2.0
Read the manuals and if you are a professional get a proper education in computer science. Makes the forum a lot cleaner.

PascalDragon

  • Hero Member
  • *****
  • Posts: 507
  • Compiler Developer
Re: Bug? in IfThen
« Reply #12 on: July 22, 2019, 09:15:38 am »
you can also nest the ifthen's, but all the given solutions are way too complex when you can do simply this:
You can simply protect the range like so:
Code: Pascal  [Select]
  1. {$mode delphi}
  2. uses sysutils;
  3. var
  4.   i:integer = 3;
  5.   a:array of integer = [1,2,3,4,5];
  6. begin
  7.  writeln(ifthen<integer>((i<0) or (i>High(a)) ,0,a[i]));
  8. end.
Prints 4

And if you use an invalid index (which is what the thread author asked about) it will still bomb:
Code: Pascal  [Select]
  1. {$mode delphi}
  2. {$R+}
  3. uses sysutils;
  4. var
  5.   i:integer = -1;
  6.   a:array of integer = [1,2,3,4,5];
  7. begin
  8.  writeln(ifthen<integer>((i<0) or (i>High(a)) ,0,a[i]));
  9. end.
Code: [Select]
An unhandled exception occurred at $004016BD:
ERangeError: Range check error
  $004016BD  main,  line 8 of fpctests/tifthen.pp

Because as lucamar said:
IfThen() is a normal function so all its arguments have to be processed before the call is made.

If n is bigger than the array's length, then, VarArray[n] will fail, as it should. I guess you're getting a range error or a seg fault, aren't you?

Thaddy

  • Hero Member
  • *****
  • Posts: 8481
Re: [SOLVED] Bug? in IfThen
« Reply #13 on: July 22, 2019, 09:32:48 am »
Ah, I see.  But because the Boolean expression satisfies the bounds, I guess a {$Push}{$R-}..{$POP} is allowed here.
« Last Edit: July 22, 2019, 09:37:53 am by Thaddy »
Read the manuals and if you are a professional get a proper education in computer science. Makes the forum a lot cleaner.

lucamar

  • Hero Member
  • *****
  • Posts: 1944
Re: [SOLVED] Bug? in IfThen
« Reply #14 on: July 22, 2019, 10:17:35 am »
Ah, I see.  But because the Boolean expression satisfies the bounds, I guess a {$Push}{$R-}..{$POP} is allowed here.

So that instead of a range error it shoots out an access violation? Or am I not understanding what you're driving to?

Remember, the condition this thread is about is when the index is out of bounds and the problem with IfThen (in any incarnation, or by whatever name) is that the parameters, of course, are evaluated before the call to the function is made, so with an invalid index n, any parameter using AnArray[n] will cause an errror/exception.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.2/2.0.4  - FPC 3.0.4 on:
(K|L)Ubuntu 12..16, Windows XP SP3, various DOSes.