A Quine in Oberon
One of the courses I took this term was the imaginatively titled "Imperative Programming I" (aka. Programming II as "Functional Programming" - Haskell - was last term). The lecturer for this course is very good, but the language used for this course is one that most people won't have heard of: Oberon 2. The rationale for choosing this language is given here and here - in short saying that "modern" languages (Lua, Python, Ruby, etc.) are too high-level, and languages like C are too hard. After using Oberon for a term, I still have no love for the language (unlike using Haskell for a term, which resulted in some affection for it), and could argue for using C / Lua instead of Oberon for a long time (the Physics dept. teaches their 1st year undergrads C, so it can't be too hard for the 1st year Comp Sci undergrads, and so on...), but doing so wouldn't benefit anyone (as the choice of language is at the lecturer's discretion, and he likes Oberon - as I like Lua).
As previously said, the lecturer for this course is very good. One of the reasons for this is the interesting practical exercises and problem sheets which he set. For example, the last question on the last problem sheet was to "Write an Oberon program that, when you run it, prints out its own source text". The question nicely avoids using the term "quine" (giving that term would allow students to easily search the web for information), but it is asking you to write a quine in Oberon. One simple way to implement a quine is to list each line of the source text as a string literal, along with some logic to reproduce this list of string literals from the string literals themselves, which is what I did:
MODULE Quine;
IMPORT Out;
VAR i: INTEGER; L: ARRAY 13,57 OF CHAR;
BEGIN
L[0]:="MODULE Quine;";
L[1]:="IMPORT Out;";
L[2]:="VAR i: INTEGER; L: ARRAY 13,57 OF CHAR;";
L[3]:="BEGIN";
L[4]:="FOR i := 0 TO 3 DO Out.String(L[i]); Out.Ln END;";
L[5]:="FOR i := 0 TO LEN(L)-1 DO";
L[6]:=" Out.Char('L'); Out.Char('['); Out.Int(i, 0);";
L[7]:=" Out.Char(']'); Out.Char(':'); Out.Char('=');";
L[8]:=" Out.Char(22X); Out.String(L[i]); Out.Char(22X);";
L[9]:=" Out.Char(';'); Out.Ln";
L[10]:="END;";
L[11]:="FOR i := 4 TO LEN(L)-1 DO Out.String(L[i]); Out.Ln END;";
L[12]:="END Quine.";
FOR i := 0 TO 3 DO Out.String(L[i]); Out.Ln END;
FOR i := 0 TO LEN(L)-1 DO
Out.Char('L'); Out.Char('['); Out.Int(i, 0);
Out.Char(']'); Out.Char(':'); Out.Char('=');
Out.Char(22X); Out.String(L[i]); Out.Char(22X);
Out.Char(';'); Out.Ln
END;
FOR i := 4 TO LEN(L)-1 DO Out.String(L[i]); Out.Ln END;
END Quine.
We can express exactly the same idea in Lua, with the resulting code being shorter and (in my opinion) looking nicer: (largely due to keywords being in lowercase, and assignment using =
rather than :=
)
L = {
"L = {",
"}",
"print(L[1])",
"for i = 1, #L do print((\" %q,\"):format(L[i])) end",
"for i = 2, #L do print(L[i]) end",
}
print(L[1])
for i = 1, #L do print((" %q,"):format(L[i])) end
for i = 2, #L do print(L[i]) end
We can of course strip out a a lot of the code in the above, to leave a quine seen in a previous post:
s="s=%q print(s:format(s))" print(s:format(s))
Footnote: I suspect that at least some of the recent updates to the rationale for Oberon were due to some of my comments on the course feedback form. This is great, as it shows that the lecturer is reading and responding to feedback. I'm slightly confused by the statement on that page "I can't stand the 'used to be the bees knees, but is deprecated in version 5.1' business" - I suspect that he is referencing Lua 5.1 as neither Python nor Ruby are anywhere near a version 5.1, yet the list of things changed / made deprecated in Lua 5.1 contains nothing that I would class as "the bee's knees". One could also the discuss the general point of whether languages changing (or, if you prefer, evolving) is a good thing or a bad thing, but again, this is not the place to do so.