-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent Behaviour of For Loop #33
Comments
Hi,
To check the given FOR loops for correct behaviour, all you have to do is translate them into the equivalent forms described in the Oberon-04 Report (3.5.2016).
Regards,
K
…________________________________
From: Geekstakulus ***@***.***>
Sent: Sunday 31 December 2023 10:20
To: lboasso/oberonc ***@***.***>
Cc: Subscribed ***@***.***>
Subject: [lboasso/oberonc] Inconsistent Behaviour of For Loop (Issue #33)
Introduction
In Oberon-07 and its predecessors, the for loop is designed to iterate a fixed number of times. As such, the control variable within the loop should remain constant, and the expression following the "TO" keyword should also be fixed.
Current Behavior
Currently, the Oberonc compiler flags modifications to the control variable within the loop body as errors. However, it doesn't enforce the immutability of the expression following the "TO" keyword. Consider the following two code snippets:
MODULE ForLoop1;
IMPORT Out;
VAR
n : INTEGER;
BEGIN
FOR n := 1 TO 5 DO
DEC(n);
Out.String("i = ");
Out.Int(n, 0);
Out.Ln
END
END ForLoop1.
This code fails to compile due to the attempt to decrement n, which triggers an error. This behavior is expected and thus considered correct.
However, consider the next code snippet:
MODULE ForLimit;
IMPORT Out;
VAR
i, limit : INTEGER;
BEGIN
limit := 4;
FOR i := 1 TO limit + 1 DO
DEC(limit);
Out.Int(limit, 0);
Out.String(", ");
Out.Int(i, 0);
Out.Ln
END;
Out.String(":");
Out.Int(limit, 0);
Out.Ln
END ForLimit.
This code compiles successfully, but produces unexpected output. The expression limit + 1 should only be evaluated once, but in this case, it appears to be reevaluated with each iteration of the loop, resulting in the following incorrect output:
3, 1
2, 2
1, 3
:1
Expected Behavior
The expected behavior would be for the expression limit + 1 to be evaluated only once, producing the following output:
3, 1
2, 2
1, 3
0, 4
-1, 5
:-1
Reproduction Steps
To reproduce this behavior:
1. Compile the code using the Oberonc compiler.
2. Observe that the compiler throws an error on the first example.
3. Observe that the compiler compiles the code without error on the second example, but produces incorrect output.
Additional Information
Interestingly, compiling the same code with obc yields the correct output for the second example. However, it allows the modification of the control variable within the body of the for loop, which is contrary to the expected behavior. oberonc behaves similarly to Java and C.
—
Reply to this email directly, view it on GitHub<#33>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AH3LGZPEAPDUTBNE3QBEDS3YME37DAVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43ASLTON2WKOZSGA3DCMBRGI2DGNA>.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
Hello,
At the time I was dealing with the code generation of the FOR loop I
noticed that Wirth decided not to use a temporary variable to hold the loop
upper bound in his RISC compiler, so I implemented it in oberonc in the
same way. Indeed the latest language report mandates the repeated
evaluation of the "end" variable.
In retrospect I agree it would be better to handle it as defined in the
Oberon-2 report: (https://ssw.jku.at/Research/Papers/Oberon2.pdf), but I
prefer to adhere to the Oberon-07 language report and avoid creating a
dialect.
I can share a patch with the necessary changes to the code to make it work
as in Oberon-2, if you are interested. Years ago I experimented with it
just for fun.
Cheers and happy new year,
Luca
…On Sun, Dec 31, 2023, 16:21 KevinRH ***@***.***> wrote:
Hi,
To check the given FOR loops for correct behaviour, all you have to do is
translate them into the equivalent forms described in the Oberon-04 Report
(3.5.2016).
Regards,
K
________________________________
From: Geekstakulus ***@***.***>
Sent: Sunday 31 December 2023 10:20
To: lboasso/oberonc ***@***.***>
Cc: Subscribed ***@***.***>
Subject: [lboasso/oberonc] Inconsistent Behaviour of For Loop (Issue #33)
Introduction
In Oberon-07 and its predecessors, the for loop is designed to iterate a
fixed number of times. As such, the control variable within the loop should
remain constant, and the expression following the "TO" keyword should also
be fixed.
Current Behavior
Currently, the Oberonc compiler flags modifications to the control
variable within the loop body as errors. However, it doesn't enforce the
immutability of the expression following the "TO" keyword. Consider the
following two code snippets:
MODULE ForLoop1;
IMPORT Out;
VAR
n : INTEGER;
BEGIN
FOR n := 1 TO 5 DO
DEC(n);
Out.String("i = ");
Out.Int(n, 0);
Out.Ln
END
END ForLoop1.
This code fails to compile due to the attempt to decrement n, which
triggers an error. This behavior is expected and thus considered correct.
However, consider the next code snippet:
MODULE ForLimit;
IMPORT Out;
VAR
i, limit : INTEGER;
BEGIN
limit := 4;
FOR i := 1 TO limit + 1 DO
DEC(limit);
Out.Int(limit, 0);
Out.String(", ");
Out.Int(i, 0);
Out.Ln
END;
Out.String(":");
Out.Int(limit, 0);
Out.Ln
END ForLimit.
This code compiles successfully, but produces unexpected output. The
expression limit + 1 should only be evaluated once, but in this case, it
appears to be reevaluated with each iteration of the loop, resulting in the
following incorrect output:
3, 1
2, 2
1, 3
:1
Expected Behavior
The expected behavior would be for the expression limit + 1 to be
evaluated only once, producing the following output:
3, 1
2, 2
1, 3
0, 4
-1, 5
:-1
Reproduction Steps
To reproduce this behavior:
1. Compile the code using the Oberonc compiler.
2. Observe that the compiler throws an error on the first example.
3. Observe that the compiler compiles the code without error on the second
example, but produces incorrect output.
Additional Information
Interestingly, compiling the same code with obc yields the correct output
for the second example. However, it allows the modification of the control
variable within the body of the for loop, which is contrary to the expected
behavior. oberonc behaves similarly to Java and C.
—
Reply to this email directly, view it on GitHub<
#33>, or unsubscribe<
https://github.com/notifications/unsubscribe-auth/AH3LGZPEAPDUTBNE3QBEDS3YME37DAVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43ASLTON2WKOZSGA3DCMBRGI2DGNA>.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
—
Reply to this email directly, view it on GitHub
<#33 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAVJAW2LTUCSHI3QMCURU6LYMFYG5AVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNZSHE3DANRTG4>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Hi,
Sorry, I meant "Oberon-07" report (not "Oberon-04").
Oberon-2 is a different language. For me, the language definition document is "gospel" 🙂 (even if it sometimes doesn't seem "right")!
Thanks, and have a great 2024!
Kevin
________________________________
From: Luca Boasso ***@***.***>
Sent: Sunday 31 December 2023 15:15
To: lboasso/oberonc ***@***.***>
Cc: KevinRH ***@***.***>; Comment ***@***.***>
Subject: Re: [lboasso/oberonc] Inconsistent Behaviour of For Loop (Issue #33)
Hello,
At the time I was dealing with the code generation of the FOR loop I
noticed that Wirth decided not to use a temporary variable to hold the loop
upper bound in his RISC compiler, so I implemented it in oberonc in the
same way. Indeed the latest language report mandates the repeated
evaluation of the "end" variable.
In retrospect I agree it would be better to handle it as defined in the
Oberon-2 report: (https://ssw.jku.at/Research/Papers/Oberon2.pdf), but I
prefer to adhere to the Oberon-07 language report and avoid creating a
dialect.
I can share a patch with the necessary changes to the code to make it work
as in Oberon-2, if you are interested. Years ago I experimented with it
just for fun.
Cheers and happy new year,
Luca
On Sun, Dec 31, 2023, 16:21 KevinRH ***@***.***> wrote:
Hi,
To check the given FOR loops for correct behaviour, all you have to do is
translate them into the equivalent forms described in the Oberon-04 Report
(3.5.2016).
Regards,
K
________________________________
From: Geekstakulus ***@***.***>
Sent: Sunday 31 December 2023 10:20
To: lboasso/oberonc ***@***.***>
Cc: Subscribed ***@***.***>
Subject: [lboasso/oberonc] Inconsistent Behaviour of For Loop (Issue #33)
Introduction
In Oberon-07 and its predecessors, the for loop is designed to iterate a
fixed number of times. As such, the control variable within the loop should
remain constant, and the expression following the "TO" keyword should also
be fixed.
Current Behavior
Currently, the Oberonc compiler flags modifications to the control
variable within the loop body as errors. However, it doesn't enforce the
immutability of the expression following the "TO" keyword. Consider the
following two code snippets:
MODULE ForLoop1;
IMPORT Out;
VAR
n : INTEGER;
BEGIN
FOR n := 1 TO 5 DO
DEC(n);
Out.String("i = ");
Out.Int(n, 0);
Out.Ln
END
END ForLoop1.
This code fails to compile due to the attempt to decrement n, which
triggers an error. This behavior is expected and thus considered correct.
However, consider the next code snippet:
MODULE ForLimit;
IMPORT Out;
VAR
i, limit : INTEGER;
BEGIN
limit := 4;
FOR i := 1 TO limit + 1 DO
DEC(limit);
Out.Int(limit, 0);
Out.String(", ");
Out.Int(i, 0);
Out.Ln
END;
Out.String(":");
Out.Int(limit, 0);
Out.Ln
END ForLimit.
This code compiles successfully, but produces unexpected output. The
expression limit + 1 should only be evaluated once, but in this case, it
appears to be reevaluated with each iteration of the loop, resulting in the
following incorrect output:
3, 1
2, 2
1, 3
:1
Expected Behavior
The expected behavior would be for the expression limit + 1 to be
evaluated only once, producing the following output:
3, 1
2, 2
1, 3
0, 4
-1, 5
:-1
Reproduction Steps
To reproduce this behavior:
1. Compile the code using the Oberonc compiler.
2. Observe that the compiler throws an error on the first example.
3. Observe that the compiler compiles the code without error on the second
example, but produces incorrect output.
Additional Information
Interestingly, compiling the same code with obc yields the correct output
for the second example. However, it allows the modification of the control
variable within the body of the for loop, which is contrary to the expected
behavior. oberonc behaves similarly to Java and C.
—
Reply to this email directly, view it on GitHub<
#33>, or unsubscribe<
https://github.com/notifications/unsubscribe-auth/AH3LGZPEAPDUTBNE3QBEDS3YME37DAVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43ASLTON2WKOZSGA3DCMBRGI2DGNA>.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
—
Reply to this email directly, view it on GitHub
<#33 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAVJAW2LTUCSHI3QMCURU6LYMFYG5AVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNZSHE3DANRTG4>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
—
Reply to this email directly, view it on GitHub<#33 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AH3LGZKOMYI3EWHY7WUABH3YMF6QPAVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNZSHE3TEOBSGQ>.
You are receiving this because you commented.Message ID: ***@***.***>
|
Firstly, happy new year! I appreciate all the comments and discussions on the topic. I've been reviewing the Oberon 07 Language Report, which, as is characteristic of Niklaus Wirth's writings, leaves room for interpretation. Section 9.8 states that "A for statement specifies the repeated execution of a statement sequence for a given number of times," which I took to mean the same behavior as in Modula-2 and Pascal: "... repeated execution of a statement sequence for a given number of numbers", in my opinion means that it shouldn't change mid course. I admire Wirth's brilliance, but I also acknowledge his tendency towards laziness and inconsistency. In good engineering practice, specifications are written and adhered to strictly. However, when the implementation deviates from the stated specification due to laziness, it becomes challenging to understand how the system functions. I stumbled upon the discrepancy regarding the for loop during my study of the Modula-2 compiler. I tested the for loop in the Oberon language using the Unless there exists another document detailing that the for loop in the RISC compiler should function differently from his other languages, I would expect it to behave as described in the language specifications across all his languages. Interestingly, Wirth had originally removed the for loop from the original Oberon due to oversight. While I greatly admire Wirth's contributions, I find it difficult to trust his writings as they often don't align with his implementations. This seems to contradict his reputation as a brilliant engineer. Regarding the experimental features, rather than suggesting a patch, would creating a separate branch be more appropriate? Is this what you intended? |
Happy new Year!
From the latest language report we have a precise definition of the FOR
statement:
"""
The for statement
FOR v := beg TO end BY inc DO S END
is, if inc > 0, equivalent to
v := beg;
WHILE v <= end DO S; v := v + inc END
and if inc < 0 it is equivalent to
v := beg;
WHILE v >= end DO S; v := v + inc END
"""
I'm am traveling so I cannot test this, but if you rewrite your examples as
the WHILE statements above you should get the same results as with the FOR
implementation in oberonc.
Cheers,
Luca
…On Tue, Jan 2, 2024, 00:18 Geekstakulus ***@***.***> wrote:
Hello @KevinRH <https://github.com/KevinRH> and @lboasso
<https://github.com/lboasso>,
Firstly, happy new year! I appreciate all the comments and discussions on
the topic. I've been reviewing the Oberon 07 Language Report, which, as is
characteristic of Niklaus Wirth's writings, leaves room for interpretation.
Section 9.8 states that "A for statement specifies the repeated execution
of a statement sequence for a given number of times," which I took to mean
the same behavior as in Modula-2 and Pascal: "... repeated execution of a
statement sequence for a given number of numbers", in my opinion means that
it shouldn't change mid course.
I admire Wirth's brilliance, but I also acknowledge his tendency towards
laziness and inconsistency. In good engineering practice, specifications
are written and adhered to strictly. However, when the implementation
deviates from the stated specification due to laziness, it becomes
challenging to understand how the system functions.
I stumbled upon the discrepancy regarding the for loop during my study of
the Modula-2 compiler. I tested the for loop in the Oberon language using
the oberonc compiler, only to find that it behaved like C and Java. And
now you tell me that Wirth's RISC compiler behaved in the same way, which
show that he hadn't adhered to his own guidelines once again. It appears he
implemented the for loop differently in Oberon due to sheer laziness.
Unless there exists another document detailing that the for loop in the
RISC compiler should function differently from his other languages, I would
expect it to behave as described in the language specifications across all
his languages. Interestingly, Wirth had originally removed the for loop
from the original Oberon due to oversight.
While I greatly admire Wirth's contributions, I find it difficult to trust
his writings as they often don't align with his implementations. This seems
to contradict his reputation as a brilliant engineer.
Regarding the experimental features, rather than suggesting a patch, would
creating a separate branch be more appropriate? Is this what you intended?
—
Reply to this email directly, view it on GitHub
<#33 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAVJAW3TYJK2AIXKRYCAAIDYMMY3NAVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNZTGUYDEOJXHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Please, improve the following: Hi, @lboasso ! I have analyzed the specifications of the Oberon 7 programming language before providing my insight. The specs doesn't mention any restrictions on modifying the control variable or stating that the end expression should be fixed. This lack of explicitness leads to ambiguity, which in turn causes the Let's look at an example by converting the first example to an equivalent
This code will create an infinite loop because the decrement operation
The exact same spec was found in Pascal and Modula-2, yet he opted to make the end expression fixed, but allowed the control variable to be modified inside of the loop body. Therefore, based on the specs, and here I am referring to semantically equivalence, the correct behaviour should be:
From an engineering standpoint, I agree with your approach to the first example. However, I reject the ambiguity in the current specs. Consider a scenario where you write a specification for a critical system like an airplane or an automobile. If the implementation deviates from the specifications due to laziness or oversight, it could lead to catastrophic consequences. I believe that Wirth, who is indeed a genius, should have involved real engineers in writing and implementing the specifications, because, despite being a good engineer, his laziness renders a lot of ambiguous documents one cannot rely on. Therefore, based on the defensive programming approach, let's just close the issue. I agree with the defensive programming approach, and that is how I would implement. However, in the second case, I would implement it as in the I will close the issue. Thanks for your insights! |
I agree with your observations, indeed I toyed with the idea of creating my
own programming language using Oberon as stating point. I would change many
little details including the FOR statement and most of the
syntax...honestly I am not found of uppercase keywords and BEGINs and ENDs
:)
…On Tue, Jan 2, 2024, 12:38 Geekstakulus ***@***.***> wrote:
Please, improve the following:
Hi, @lboasso <https://github.com/lboasso> !
I have analyzed the specifications of the Oberon 7 programming language
before providing my insight. The specs doesn't mention any restrictions on
modifying the control variable or stating that the end expression should be
fixed. This lack of explicitness leads to ambiguity, which in turn causes
the oberonc compiler to flag an error when you attempt to modify the
control variable, when the specs says something else.
Let's look at an example by converting the first example to an equivalent
while loop as described in the specs:
MODULE WhileLoop1;
IMPORT Out;
VAR
n : INTEGER;
BEGIN
FOR n := 1 TO 5 DO
DEC(n);
Out.String("i = ");
Out.Int(n, 0);
Out.Ln;
INC(n)
END
END WhileLoop1.
This code will create an infinite loop because the decrement operation
DEC(n) followed by the increment operation INC(n) makes the loop counter n
always equal to 1. If you compile and execute the original for loop
example with obc, it will present a behaviour equivalent to this while
loop, which is correct based on the specs. However, oberonc reports this
as an error, and based on the specs, it shouldn't flag an error, because
the specs doesn't say anything about not being allowed to change the
control variable inside the for loop body or not. The only reason you've
done that is because:
1. It causes an infinite loop, and based on that you opted for a
defensive programming approach by forbidding it
2. Wirth himself implemented it this way in his RISC based compiler
The exact same spec was found in Pascal and Modula-2, yet he opted to make
the *end* expression fixed, but allowed the control variable to be
modified inside of the loop body.
Therefore, based on the specs, and here I am referring to semantically
equivalence, the correct behaviour should be:
1. The control variable can be modified and that will produce an
infinite loop
2. The *end* expression can be modified and that will produce the same
behaviour as in C and Java
From an engineering standpoint, I agree with your approach to the first
example. However, I reject the ambiguity in the current specs. Consider a
scenario where you write a specification for a critical system like an
airplane or an automobile. If the implementation deviates from the
specifications due to laziness or oversight, it could lead to catastrophic
consequences. I believe that Wirth, who is indeed a genius, should have
involved real engineers in writing and implementing the specifications,
because, despite being a good engineer, his laziness renders a lot of
ambiguous documents one cannot rely on.
Therefore, based on the defensive programming approach, let's just close
the issue. I agree with the defensive programming approach, and that is how
I would implement. However, in the second case, I would implement it as in
the obc compiler, or Pascal, Modula-2, Rust and Kotlin.
I will close the issue.
Thanks for your insights!
—
Reply to this email directly, view it on GitHub
<#33 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAVJAWZGFRWY3ACRHWVVRMLYMPPSDAVCNFSM6AAAAABBIE5M52VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNZTHA2TQNRUHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
While I personally prefer not to use uppercase keywords, I'm able to adapt to this convention. I utilize a custom plugin for NeoVim that transforms all text to uppercase, providing an appealing syntax highlighting feature. In addition to this, I've conceptualized a programming language inspired by Oberon, but I've yet to dedicate significant time to its development. Instead, I've been engrossed in the task of developing a Modula-2 compiler, based on Wirth's original single-pass compiler. This is where we truly witness the brilliance of Wirth, despite his apparent lack of discipline. Many elements that may initially seem like chaotic or inefficient code were actually ingenious solutions to the limitations of hardware at the time. His compilers are true works of art, demonstrating simplicity and efficiency. The seemingly cryptic variable names were also strategic ways of navigating the hardware constraints. Upon examining the compiler, one can appreciate why he chose to store both identifiers and strings in a single array. This approach, which might seem counter-intuitive, becomes clear upon studying the architecture of the Lilith computer. Despite his occasional laziness and inconsistent documentation, even his books filled with errors, it's crucial to acknowledge that Wirth's genius is undeniable. My admiration for Wirth is quite strong. My admiration for Dikstra, who was a meticulous engineer, is far stronger, because he paid considerable attention to the details. Both Wirth and Dikstra serve as excellent examples of extraordinary programmers, although Dikstra was far more professional and less inconsistent with his specs vs implementations. Anyway... thanks once again for this little chat. |
Hi again! I was reading the specs for Modula-2, and surprisingly enough, it is very clear. Here it is:
The specification underscores that "no components of the expressions determining the range must be affected by the repeated statements, and, above all, the control variable itself must not be changed by the repeated statements." However, in his compiler, the control variable isn't restricted from being modified. The specification also ensures that the second expression of the range isn't affected by the repeated statements. This he decided to implement in the compiler. Anyway... the best thing is to read the specs and the compiler code. |
Introduction
In Oberon-07 and its predecessors, the
for
loop is designed to iterate a fixed number of times. As such, the control variable within the loop should remain constant, and the expression following the "TO" keyword should also be fixed.Current Behavior
Currently, the Oberonc compiler flags modifications to the control variable within the loop body as errors. However, it doesn't enforce the immutability of the expression following the "TO" keyword. Consider the following two code snippets:
This code fails to compile due to the attempt to decrement
n
, which triggers an error. This behavior is expected and thus considered correct.However, consider the next code snippet:
This code compiles successfully, but produces unexpected output. The expression
limit + 1
should only be evaluated once, but in this case, it appears to be reevaluated with each iteration of the loop, resulting in the following incorrect output:Expected Behavior
The expected behavior would be for the expression
limit + 1
to be evaluated only once, producing the following output:Reproduction Steps
To reproduce this behavior:
Additional Information
Interestingly, compiling the same code with
obc
yields the correct output for the second example. However, it allows the modification of the control variable within the body of thefor
loop, which is contrary to the expected behavior.oberonc
behaves similarly to Java and C.The text was updated successfully, but these errors were encountered: