Recent

Author Topic: For variable being read after loop... Any way to get an error or warning on it?  (Read 21164 times)

cdbc

  • Hero Member
  • *****
  • Posts: 2473
    • http://www.cdbc.dk
Hi Davo
Quote
example of code that depended on the variable being undefined
Personally, I've never seen an example of that in ~ 39 years of coding...
Break/Exit is another matter entirely.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6 -> FPC 3.2.2 -> Lazarus 4.0 up until Jan 2025 from then on it's both above &: KDE6/QT6 -> FPC 3.3.1 -> Lazarus 4.99

440bx

  • Hero Member
  • *****
  • Posts: 5820
Whether its worth the added complexity is another question of course.
Davo
Actually, implementing that should be trivial.   It's just a matter of saving the register back into the memory location reserved for the control variable (which is likely the non-optimized behavior anyway and the reason the control variable has the desired value when the loop ends - no matter how it ended - in that case.)


FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8505
My argument being that removing that 'undefined' characteristic (and doing what many users expect) cannot possibly do anyone any harm. Whether its worth the added complexity is another question of course.

Diplomats appear to work on the principle that negotiations should avoid using a language which is imprecise, or excessively nuanced.

I have long argued that where a language's syntax demanded a compiler which was provably complex ** , it was worth reviewing and if necessary changing the syntax to simplify implementation. After all, there were no full PL/I or Ada implementations hosted by 8-bit systems, but there were multiple full Pascal compilers on at least Z80-based systems.

I think the current "might or might not be undefined on completion" issue is one where difficult semantics merit changing the syntax, so that even if the compiler cannot be guaranteed to "do the right thing" it can at least issue an intelligent warning ("if you use a non-local control variable, be it on your own head").

MarkMLl

** I use the word "provably" with an appreciation of what it means in CS terms. However I would hazard that any compilation technique that has taken three years of a postgrad's life to master should be automatically disqualified from common use: that level of complexity strongly implies incorrect starting assumptions.
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

dbannon

  • Hero Member
  • *****
  • Posts: 3568
    • tomboy-ng, a rewrite of the classic Tomboy
I have long argued that where a language's syntax demanded a compiler which was provably complex ** , it was worth reviewing and if necessary changing the syntax to simplify implementation.

Well, at a lower level, that is the on going RISC v. CISC argument. The trouble is feature creep, Nick (and Borland for that matter) made a small, fast compiler that handled a carefully defined, small, set of instructions (or syntax). Much of that that syntax would be used by the average user. But then, someone adds an other feature, and another. The syntax becomes 'sparse', many features used by only a smaller subset of users. May not be a good thing but absolutely inevitable.

Ada, because of its rigid control, may be the exception ? I mean, a language with no string handling built it ? And, I must add, boring to use.

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Thaddy

  • Hero Member
  • *****
  • Posts: 18363
  • Here stood a man who saw the Elbe and jumped it.
Ada, because of its rigid control, may be the exception ? I mean, a language with no string handling built it ? And, I must add, boring to use.

Davo
I can crash Ada.. :D But that is just because I can, never used such Ada code in professional practice. It is hoop jumping squared.
It still allows for hackery code, though. In that sense it is fool complete.
That said, it is not boring, it rather keeps you focussed.
But that is just my two cents.
« Last Edit: August 16, 2024, 02:56:46 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6195
  • Compiler Developer
My argument being that removing that 'undefined' characteristic (and doing what many users expect) cannot possibly do anyone any harm. Whether its worth the added complexity is another question of course.

It would restrict the compiler from some optimizations of the for-loop which it currently can do as long as the loop does not contain a Break or goto.

Kays

  • Hero Member
  • *****
  • Posts: 624
  • Whasup!?
    • KaiBurghardt.de
I think the consensus is that the control variable does not (or at least should not) become defined by a for‑statement (unless you prematurely exit it with goto or goto in disguise [break]). The question really is, does the control variable retain its defined vs. undefined status despite an intervening for‑statement:
Code: Pascal  [Select][+][-]
  1. {$mode ISO}
  2. program forLoopPostAssertionsTest(output);
  3.         var
  4.                 number: integer;
  5.         begin
  6.                 { `number` becomes defined: }
  7.                 number := 8;
  8.                
  9.                 for number := 1 to 10 do
  10.                 begin
  11.                         writeLn(number)
  12.                 end;
  13.                
  14.                 { Should this print `8` or cause an “undefined variable” error. }
  15.                 writeLn(number)
  16.         end.
Currently it prints 10, which is wrong since there is no assignment number := 10. Only the for‑loop could have possibly made such an assignment, but it is not supposed to do that according to the standards.
Yours Sincerely
Kai Burghardt

BrunoK

  • Hero Member
  • *****
  • Posts: 722
  • Retired programmer
Code: [Select]
    for number := 1 to 10 do
begin
writeLn(number)
end;

{ Should this print `8` or cause an “undefined variable” error. }
writeLn(number)
end.
Currently it prints 10, which is wrong since there is no assignment number := 10. Only the for‑loop could have possibly made such an assignment, but it is not supposed to do that according to the standards.
i:= is an assignement even in  a for loop.

BUT if it writes 10 after the end of the loop (I didn't test) I would consider it not being what I expected. Having done some basic many tens of year ago, I would have expected 11 to show because the for loop ended when the iterating value got out of range. My bet is that in some cases, optimization might work like in basic and in other situations, like your example shows.

Thus : after a for loop, the value of the iterator cannot be guaranteed, exactly like the documentation states. You can shake it anyway you like, there is no reason to change it.

Thaddy

  • Hero Member
  • *****
  • Posts: 18363
  • Here stood a man who saw the Elbe and jumped it.
(I didn't test)
Most of the rest of us DID test and have - the sane and informed ones - similar conclusions.
In such a long thread, plz read the whole thread and don't make assumptions.
It is people like you that keeps this nonsense thread open.
The conclusion is simple:
The language specs defines explicitly that a For loop variable is undefined after the loop and you should not rely on its value after a loop has ended.
Enough is enough. >:D
That said, a warning is being worked on.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

BrunoK

  • Hero Member
  • *****
  • Posts: 722
  • Retired programmer
(I didn't test)
Enough is enough. >:D
That said, a warning is being worked on.
Usually and contrary to you, I do test things, thus have not as much time as you who parade supposed knowledge of which half is pure nonsense. You are quite a kind of  frustrated Old_Glory, aren't you ?

But here is really a case of "How many angels can dance on the head of a pin ?"

There are already so many warnings that they become useless, sometimes, there are things that might warrant a warning but don't produce any or an difficult to figure out one.

For example, the warnings about inline not implemented do absolutely pollute the messages. Turning them off means that one doesn't known, except via single stepping, if the one you thought useful was

MarkMLl

  • Hero Member
  • *****
  • Posts: 8505
The language specs defines explicitly that a For loop variable is undefined after the loop and you should not rely on its value after a loop has ended.

For the sake of anybody who jumps in here (possibly courtesy of Google) and doesn't read the entire thread:

The control variable ends up with no defined (i.e. predictable) value. It does not in some way become undeclared, or have a special value assigned to it that code can subsequently recognise as an undefined value.

Testing and personal experience ("it was ten every time I tried it") is utterly irrelevant.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

cdbc

  • Hero Member
  • *****
  • Posts: 2473
    • http://www.cdbc.dk
Hi
@MarkMLl: +1
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6 -> FPC 3.2.2 -> Lazarus 4.0 up until Jan 2025 from then on it's both above &: KDE6/QT6 -> FPC 3.3.1 -> Lazarus 4.99

silvercoder70

  • Full Member
  • ***
  • Posts: 200
    • Tim Coates
Just to add my 2c worth to Mark's comments ...

the only case where a programmer wants to use control variable (for loop) might be to check if a something a found in a list or array? And is a bad practice. The End.

And the way around that would be to use a while or repeat/until construct. But even then, I would add a Found boolean ...

Code: Pascal  [Select][+][-]
  1. while (not Found) and (I < Something) do
  2. begin
  3.   if (condition) then
  4.   begin
  5.     Found := True;
  6.   end
  7.   else
  8.     Inc(I);
  9. end;
  10.  

But I could still do this ...

Code: Pascal  [Select][+][-]
  1. var I: integer;
  2. for I := 1 to 10 do begin ... end;
  3.  
  4. {Reuse variable...}
  5. I :=
  6.  

🔥 Pascal Isn’t Dead -> See What It Can Do: @silvercoder70 on YouTube

MarkMLl

  • Hero Member
  • *****
  • Posts: 8505
the only case where a programmer wants to use control variable (for loop) might be to check if a something a found in a list or array? And is a bad practice. The End.

But if it's in a function then the control variable can be returned via exit(). However I'd note again that all of these nasties (break, exit, and so on) are extensions to what Wirth originally defined and implemented, and if he'd had the time circa 1968 he might have done things differently before UCSD and Borland got their hands on the language.

I'd be interested in any comment that Sven has on the extent to which exit(<control_variable>) messes up optimisation etc.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 5820
I'd be interested in any comment that Sven has on the extent to which exit(<control_variable>) messes up optimisation etc.

MarkMLl
You didn't ask me but, the answer is: it shouldn't have any.  if the index's value is already in a register then, in the worst case, it adds one mov reg, reg to move it to the register that holds the function's return value and that "mov" is needed only just before whatever code is implementing "exit" (which will often simply be a jump to the function's epilog.)

In many cases the compiler should simply have the loop counter in the register that is used by the function to return a value.  simple and very easy to implement.
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018