How does the pascal for loop work? - pascal

I've got a question related to the way the for loop works in Pascal:
Program example;
var i:integer;
Begin
i:=7;
for i:=1 to i do write(i);
End.
This piece of code outputs: 1234567.
I think that the compiler makes a secondary copy of the variable i, and then uses that one in the for loop.

Note that this is REQUIRED to work in Pascal according to the ISO7185 standard. The "end value" should be copied before the loop counter is modified.
https://github.com/Leporacanthicus/lacsap/blob/master/test/Basic/iso7185pat.pas#L761

In the for loop in Pascal we have variable called loop counter which controls the iterations of the loop, and this variable changes in each iteration of the loop, so it's that i which is declared here: i:=1 in your code.
The second is the variable declared above the loop which is called also i but it's a variable which is the final value for the loop.
Consider this:
Program example;
var i:integer;
var addr:^word;
Begin
i:=10;
for i:=1 to i do addr:=#i;
addr^ := addr^+1; { I add 1 to the last loop counter }
writeln(i); { This is final variable, I don't add anything to the final variable of the loop }
writeln(addr^); { This is value of the last loop counter index }
{ Both variables give us the same result }
{ Proposal: In my opinion, your guess about the copy is correct }
End.
As in comment in the code - in my opinion, pascal creates a copy of this variable.
Hope it will help!
If yes please let me know by voting up.
Regards!

The point here is the Pascal compiler will set the parameters for the for once, at the first execution. Then it sets a start point i:=1 and and end point 7 before doing anything with the control value, then starts the loop.
But I should point that this is bad practice in programming. Unless you are just making an academical or speculative question, I see no reason to "save" a variable name doing something like this.
It is interesting to notice too that this abuse of the control variable name may cause unpredictable results if this is done inside the loop.
As they use to say in those programs who show dangerous adventures, don't try to do this at home!

Related

Basic question from a beginner. Problem with definitions in a bucle. Maple

Let's suppose we are in this case (I'm using Maple)
add:=function()
e1:=0;
e2:=1;
for j in [1..2]do
ej:=ej+1
od;
return e1,e2;
end;
This program gives me a global variable error. I understand why that happens -- because ej is not defined as local -- but if you define it then the program just doesn't do anything. ) I don't know how to solve it. My objective (in a bigger program) is to call e1,e2 in a for loop.
Maybe I didn't express myself correctly simplifying my problem, there is my Program, it is made with program GAP but it works similar to Maple:
G12Decode:=function(c)
localx,G,C,sG,sH,a,u,b1,e1,b2,e2,b3,e3,b4,e4,b5,e5,b6,e6,h1,h2,i,j;
x:=Codeword(c,GF(3));
G:=[[1,0,0,0,0,0,0,1,1,1,1,1],[0,1,0,0,0,0,1,0,1,2,2,1],
[0,0,1,0,0,0,1,1,0,1,2,2],[0,0,0,1,0,0,1,2,1,0,1,2],
[0,0,0,0,1,0,1,2,2,1,0,1],[0,0,0,0,0,1,1,1,2,2,1,0]];
C:=GeneratorMatCode(G,GF(3));
sG:=x*TransposedMat(GeneratorMat(C));
sH:=x*TransposedMat(CheckMat(C));
a:=[0,0,0,0,0,0];
b1:=Codeword([0,1,1,1,1,1],GF(3));
e1:=Codeword([1,0,0,0,0,0],GF(3));
b2:=Codeword([1,0,1,2,2,1],GF(3));
e2:=Codeword([0,1,0,0,0,0],GF(3));
b3:=Codeword([1,1,0,1,2,2],GF(3));
e3:=Codeword([0,0,1,0,0,0],GF(3));
b4:=Codeword([1,2,1,0,1,2],GF(3));
e4:=Codeword([0,0,0,1,0,0],GF(3));
b5:=Codeword([1,2,2,1,0,1],GF(3));
e5:=Codeword([0,0,0,0,1,0],GF(3));
b6:=Codeword([1,1,2,2,1,0],GF(3));
e6:=Codeword([0,0,0,0,0,1],GF(3));
if Weight(sH)<=2 then
sH:=ShallowCopy(VectorCodeword(sH));
Append(a,sH);
a:=Codeword(a,GF(3));
u:=x-a;
return u;
elif Weight(sG)<=2 then
sG:=ShallowCopy(VectorCodeword(sG));
Append(sG,a);
sG:=Codeword(sG,GF(3));
u:=x-sG;
return u;
else
for i in [1..6] do
for j in [1..6] do
if sG-bi=ej or sG-bi=2*ej then
h1:=sG-bi;
h2:=ei;
h1:=ShallowCopy(VectorCodeword(h1));
h2:=ShallowCopy(VectorCodeword(h2));
Append(h1,h2);
h1:=Codeword(h1,GF(3));
u:=x-h1;
return u;
elif sG-2*bi=ej or sG-2*bi=2*ej then
h1:=sG-2*bi;
h2:=ei;
h1:=ShallowCopy(VectorCodeword(h1));
h2:=ShallowCopy(VectorCodeword(h2));
Append(h1,h2);
h1:=Codeword(h1,GF(3));
u:=x-h1;
return u;
fi;
od;
od;
fi;
end;
The program dont send me an error but i know it don't work because of the ej,bi and ei. I want to do what it says after the last "else" but i don't know how to solve it to make it work.
Your syntax is invalid. It is proc, not function.
And add is already a Maple command, so it's a protected name and cannot be assigned to. You have to use another name.
And your syntax for the do-loop is likely not what you want. You probably want for j from 1 to 2 do .
And you really should initialize ej with a value before doing the recursive assignment ej:=ej+1 .
And you might as well declare the procedure's local variables.
Personally, I favour using end do instead of od , and end proc instead of just end , in modern Maple. It makes it easier to tell what's being terminated.
For example,
restart;
my_add:=proc()
local e1,e2,ej,j;
e1:=0;
e2:=1;
ej:=0;
for j from 1 to 5 do
ej:=ej+1
end do;
return ej,e1,e2;
end proc:
my_add();
5, 0, 1
There is a Maple Programming Guide, which you can read online or inside Maple's own Help system. It has a nice introduction to writing procedures. And there is a more detailed Help page for the proc command.

Should I expect to see the counter in `for` loop changed inside its body? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I'm reading someone else's code and they separately increment their for loop counter inside the loop, as well as including the usual afterthought. For example:
for( int y = 4; y < 12; y++ ) {
// blah
if( var < othervar ) {
y++;
}
// blah
}
Based on the majority of code others have written and read, should I be expecting to see this?
The practice of manipulating the loop counter within a for loop is not exactly widespread. It would surprise many of the people reading that code. And surprising your readers is rarely a good idea.
The additional manipulation of your loop counter adds a ton of complexity to your code because you have to keep in mind what it means and how it affects the overall behavior of the loop. As Arkady mentioned, it makes your code much harder to maintain.
To put it simply, avoid this pattern. When you follow "clean code" principles, especially the single layer of abstraction (SLA) principle, there is no such thing as
for(something)
if (somethingElse)
y++
Following the principle requires you to move that if block into its own method, making it awkward to manipulate some outer counter within that method.
But beyond that, there might be situations where "something" like your example makes; but for those cases - why not use a while loop then?
In other words: the thing that makes your example complicated and confusing is the fact that two different parts of the code change your loop counter. So another approach could look like:
while (y < whatever) {
...
y = determineY(y, who, knows);
}
That new method could then be the central place to figure how to update the loop variable.
I beg to differ with the acclaimed answer above. There is nothing wrong with manipulating loop control variable inside the loop body. For example, here is the classical example of cleaning up the map:
for (auto it = map.begin(), e = map.end(); it != e; ) {
if (it->second == 10)
it = map.erase(it);
else
++it;
}
Since I have been rightfully pointed out to the fact that iterators are not the same as numeric control variable, let's consider an example of parsing the string. Let's assume the string consists of a series of characters, where characters prefixed with '\' are considered to be special and need to be skipped:
for (size_t i = 0; i < s_len; ++i) {
if (s[i] == '\\') {
++i;
continue;
}
process_symbol(s[i]);
}
Use a while loop instead.
While you can do this with a for loop, you should not. Remember that a program is like any other piece of communication, and must be done with your audience in mind. For a program, the audience includes the compiler and the next person to do maintenance on the code (likely you in about 6 months).
To the compiler, the code is taken very literally -- set up a index variable, run the loop body, execute the increment, then check the condition to see if you are looping again. The compiler doesn't care if you monkey with the loop index.
To a person however, a for loop has a specific implied meaning: Run this loop a fixed number of times. If you monkey with the loop index, then this violates the implication. It's dishonest in a sense, and it matters because the next person to read the code will either have to spend extra effort to understand the loop, or will fail to do so and will therefore fail to understand.
If you want to monkey with the loop index, use a while loop. Especially in C/C++/related languages, a for loop is exactly as powerful as a while loop, so you never lose any power or expressiveness. Any for loop can be converted to a while loop and vice versa. However, the next person who reads it won't depend on the implication that you don't monkey with the loop index. Making it a while loop instead of a for loop is a warning that this kind of loop may be more complicated, and in your case, it is in fact more complicated.
If you increment inside the loop, make sure to comment it. A canonical example (based on a Scott Meyers Effective C++ item) is given in the Q&A How to remove from a map while iterating it? (verbatim code copy)
for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
if (must_delete)
{
m.erase(it++); // or "it = m.erase(it)" since C++11
}
else
{
++it;
}
}
Here, both the non-constant nature of the end() iterator and the increment inside the loop are surprising, so they need to be documented. Note: the loop hoisting here is after all possible so probably should be done for code clarity.
For what it's worth, here is what the C++ Core Guidelines has to say on the subject:
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-loop-counter
ES.86: Avoid modifying loop control variables inside the body of raw
for-loops
Reason The loop control up front should enable correct
reasoning about what is happening inside the loop. Modifying loop
counters in both the iteration-expression and inside the body of the
loop is a perennial source of surprises and bugs.
Also note that in the other answers here that discuss the case with std::map, the increment of the control variable is still only done once per iteration, where in your example, it can be done more than once per iteration.
So after the some confusion, i.e. close, reopen, question body update, title update, I think the question is finally clear. And also no longer opinion based.
As I understand it the question is:
When I look at code written by others, should I be expecting to see "loop condition variable" being changed in the loop body ?
The answer to this is a clear:
yes
When you work with others code - regardless of whether you do a review, fix a bug, add a new feature - you shall expect the worst.
Everything that are valid within the language is to be expected.
Don't make any assumptions about the code being in acordance with any good practice.
It's really better to write as a while loop
y = 4;
while(y < 12)
{
/* body */
if(condition)
y++;
y++;
}
You can sometimes separate out the loop logic from the body
while(y < 12)
{
/* body */
y += condition ? 2 : 1;
}
I would allow the for() method if and only if you rarely "skip" an item,
like escapes in a quoted string.

better alternative on for loop verilog

I am a newbie in verilog. I have been searching online and most of them suggest to not use for-loop in verilog coding. So is there a better alternative to replace for-loop?
The problem that I am facing now is that I need to perform 1 or 2 for-loop in a case statement. And I have been thinking of better alternatives but come up with none. It will be great if any one of you can shed some light on this.
Example of my code:
always #(*)
case (help)
4'd1: for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; end
4'd2: for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; B=B+1; end
4'd3: begin
for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; B=B+1; end
for (i=A; i>=1;i=i-B)
begin temp[i-1]=1; B=B+1; end
end
default: temp = 0;
For-loops are fine in Verilog, but they need to able to static unroll if you plan on synthesizing. Static unroll means the loop is not depended on any external variables. For example for(i=0;i<10;i=i+1) is static. for(i=A; i<=20;i=i+B) is not static as it is a depends on the variables A and B.
You can make a loop static my moving the variables as a condition inside the for-loop. for(i=A; i<=20;i=i+B) becomes:
tmp_var = A;
for (i=0; i<=20;i=i+1) begin
if (i==tmp_var) begin
// ... your logic here ...
tmp_var = tmp_var+B;
end
end
Issues that need to be addressed beyond the scope of the question:
They way you are using B and temp is a little concerning.
B appears to be an input, but you are also incrementing it. For synthesis it is illegal to manipulate an input. If it is an input, then create a local variable with default value as B and you may change this value later in the within same always block. If it is not an input, then it is creating latching logic; which is not good and I will cover that next with temp.
temp is latching logic. Latching logic are troublesome because timing is critical; knowing when the latch is transparent or closed, and respecting the hold time requirements. The more complex the logic the harder it is to predict. In RTL one way latches are inferred is by incomplete assignments inside an combinational blocks (ie always #*). To resolve this, make sure every bit is assigned each pass of the combinational blocks. One way to safe guard this is to assign default values before staring your logic. Example:
always #(*) begin
temp = 0; // default to a constant
temp_B = B; // default to an input value
// ... your logic ...
end

I keep getting a comparison between number and nil when trying to sort a table by myself

taula = {};
function randomNumber()
return math.random(100);
end
function startArray()
for x=0, 10 do
taula[x]=randomNumber();
end
end
function printArray()
for i=0,#taula do
print(taula[i]);
end
end
function organizeArray()
for i=0,#taula do
for j=1,#taula do
if taula[i]>taula[j] then
tmp = taula[j];
taula[j]=taula[i];
taula[i]=taula[tmp];
end
end
end
end
startArray()
organizeArray()
printArray()
This is not working! The initial idea is to have printed the table declared as 'taula' but in the function organizeArray() there is a problem in the if, it says I compare a number with a nil value when I have both j and i variables declared. I need help.
You're referencing tala[tmp] instead of tmp (at line 27) when you're shuffling the array around. That's what's causing the bug.
A few pointers:
You're using globals for everything. This can cause headaches later on, when globals collide (i.e tmp could be set to something, and you do something with it). See: Local Variables and Blocks
Using randomNumber() makes your code kind of obscure, since randomNumber is just an alias for math.random(100).
Lua starts at 1, not 0. You can start at 0, but this is just something to keep in mind. #table will not count the index 0.
When asking questions, please give the full error message -- this'll let us look at the code without having to run it ourselves :)
You can put print(x) in your code, so you can see what's happening. This'll help you find bugs, since you know whats going on.

My sorting algorithm runtime errors

I developed the following sorting algorithm but there are some run time errors that I cant figure out. The program terminates when it comes to the part of filling the array. I'm still a beginner in ada so I couldn't figure out where the problem is...
With Ada.Text_IO;
With Ada.Integer_Text_IO;
Use Ada.Integer_Text_IO;
Use Ada.Text_IO;
Procedure sort is
n,i,x : Integer;
-- Max_Heapify Function...
Procedure Max_Heapify ( i, n : integer) is
j, Temp : Integer;
begin
Temp:=Int_Acc(i);
j:=2*i;
if Temp>Int_Acc(j) then
elsif Temp<=Int_Acc(j) then
Int_Acc(j/2):=Int_Acc(j);
j:=2*j;
end if;
end loop;
Int_Acc(j/2):=Temp;
end Max_Heapify;
begin
Get(n);
for i in MyArr'range loop
Put_Line("Enter Element " & Integer'Image(i));
Get(MyArr(i));
end loop;
end;
end sort;
Thanks in advance :)
Your Problem is that you are insisting on writing Ada code using c - Style programming paradigms.
Firstly:
The declarations:
Type Arr is array(1..20) of Integer;
Type int_access is access Arr;
MyArr : int_access;
Where you use Int_Acc : in out int_access as parameters to procedures are useless in Ada. You are trying to pass a pointer to an array in (which you are doing!), but you should just pass your Type Arr as in out - The Ada compiler knows to do this as a pointer!
Secondly:
I cannot see where you actually allocate any memory to MyArr. This is a possible source of your runtime error. (when you write to or index an array that does not exist, i would expect to have a problem!)
Thirdly:
You seem to be mixing fixed length arrays with variable length input. If N > 20, you will have a problem.
Fourthly:
Insulting the language is not the best way of getting help from those who like it.
NWS has nailed it : there is a pointer, but no array there.
But it's clear that you have learned C, which leaves you with a lot to learn about other languages including Ada. There really are better ways of doing many things, that aren't taught to C programmers because C doesn't allow them.
Allocating variable sized arrays without pointers, malloc and free for example...
Type Arr is array(positive range <>) of Integer; -- of any size
begin
Put_Line("Enter Number Of Elements Of Array");
Get(n);
declare -- now we know the size
My_Arr : Arr(1 .. n);
begin -- My_Arr is in scope until the end of this block
...
end;
end sort;
Using the type system better...
Bad programming :
for i in 1 .. n loop
Get(MyArr(i));
end loop;
HeapSort(MyArr,n);
for i in 1 .. n loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
This is bad because it violates the DRY principle : loop bounds repeated, and something that hopefully represents the array size passed around as a separate parameter... a maintenance nightmare if you decide to rename n to something meaningful for example.
better programming : Use the type system. Recognise that merely declaring an array has declared a new subtype of integer, representing the index of the array. You can access it as My_Arr'range, and the high bound as My_Arr'last.
for i in My_Arr'range loop
Get(MyArr(i));
end loop;
HeapSort(MyArr);
for i in My_Arr'range loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
And accidents such as redefining n after the array declaration can no longer generate buffer overflows.
NOTE: Heapsort now gets its range from the array. (Max_Heapify may still need a separate parameter to operate on subsets of the array)
Arguably best - if it makes the intent clearer - name the index datatype explicitly and use it...
declare -- now we know the size
subtype My_Range is positive range 1 .. n;
My_Arr : Arr(My_Range);
begin -- My_Arr is in scope until the end of this block
for i in My_Range loop ...
And lastly, which do you prefer; a Storage_Error exception immediately the bug occurs (writing to memory you forgot to allocate) or something odd happening much later because something scribbled across another variable?
EDIT
Having cleared up the major issues two more subtle ones remain...
If I compile the modified program (in Gnat 4.8) I get several warnings : one of them is important and tells you exactly what the problem is...
Most of the warnings stem from the fact that
for i in My_Arr'range loop
declares its own loop variable i which hides any existing in-scope declaration. So you can tidy up the code by removing the unnecessary declarations.
What remains is:
sort.adb:51:28: warning: loop range may be null
sort.adb:51:28: warning: bounds may be wrong way round
The for loop bounds are empty ranges, reversed...
1 .. 3 declares a subtype with 3 values
reverse 1 .. 3 declares the same subtype and iterates backwards over it.
But 3 .. 1 declares an EMPTY subtype (containing NO valid values) so iterating over it - either way round - does precisely nothing.
Hopefully that is the missing part of the puzzle. I'm not clear why one faulty loop gets this warning while the other (at line 38) doesn't...
if j<n **and then** Int_Acc(j+1)>Int_Acc(j) then
j:=j+1;
I think you want just 'and' instead of 'and then,' although I haven't looked at Ada code in years.
Did that compile?

Resources