The first time I read the Wikipedia article about quines, I was trying to understand it but couldn't have figured it out. Looking back, I think it was because I was programming in Java at that point, and Java isn't the best language for writing quines.
Recently, I revisited the concept and it clicked this time. I can now understand how they work. In this article, I'll share everything I've learnt as simple as possible.
Note: I used AI to proofread my article, but I wrote all of the code in this article.
Anatomy of a Quine
In this article, I use Python because of its concise syntax and popularity. Once you understand the principles here, you can write quines in the language of your choice.
Here is the quine in Python, which we will create in this article:
s='s=%c%s%c; print(s%%(39,s,39)'; print(s%(39,s,39))
You can run this code in your browser using an online Python interpreter like https://pythononline.net/
Don't worry if you don't understand what's going on yet. I'll explain it step by step.
First Step: Data and Print
I want to build a quine incrementally, starting from the basics.
Here is the first version of the code.
# version 1
s="print(s)"
print(s)
# output
print(s)
This code simply prints the string print(s)
, but it already contains the two essential parts of a quine:
- Data definition — storing the code as data
- Data printing — outputting that data
s="print(s)" # data definition
print(s) # printing data
The Paradox of Updating the Data Definition
Version 1 only prints the printing part. To turn this into a proper quine, we need to print the data definition as well. So I edited the code like this:
# version 2
s="""s="print(s)"
print(s)""" # define data including data definition
print(s) # print data
# output of version 2
s="print(s)"
print(s)
(I used Python's """
syntax to include a newline in the string.)
Now it prints the previous code. But here's the problem: because we changed the data definition, the original code is now different! This is the paradox that makes quines tricky. Every time you change the data to print the code, the code itself changes.
Include the Data in the Data Itself
If you look closely at version 2, you'll notice there are actually two data definitions: the actual definition and the one inside the double quotes.
# version 2
s="""s="print(s)"
print(s)"""
print(s)
# Its result
s="print(s)"
print(s)
↓ Outside definition:
s="""s="print(s)"
↑ Inside definition
The trick to making a quine work is to use the data from the outside definition to fill in the inside definition.
More specifically, in Python, you can use the %
operator inside print()
to insert values into strings:
print("I like %s!" % "Python")
# this prints "I like Python!"
If I apply this to our code, it would look like this:
# version 3
s="""s="%s"
print(s)"""
print(s%s) # Replace %s with the value of s
# output of version 3
s="s="%s"
print(s)"
print(s)
The output looks quite similar to the original code!
Tidy the Code
You're almost there! In the last section, you handled the core concept of quines. What's left is the somewhat tedious part: tidying up the code by dealing with special characters.
Let's look at version 3 again:
# version 3
s="""s="%s"
print(s)"""
print(s%s)
At this point, we need to handle special characters that can't be printed directly:
- Newlines
- Quotes
- Percent symbols
In general, I prefer to make quines one-liners to keep the code simpler. If the code includes a newline, the data needs to be quoted specially in most languages (like the triple quotes in Python).
So I removed the newline and used a semicolon instead. Since we no longer need triple quotes, I replaced them with single quotes.
# version 4
s='s='%s'; print(s)'; print(s%s)
But this code causes a syntax error because you can't use a single quote inside single quotes.
In normal programming, you could escape the quote, but in a quine, that doesn't work because the output would have a syntax error.
# version 4.1
s='s=\'%s\'; print(s)'; print(s%s) # this is correct
# output
s='s='%s'; print(s)'; print(s) # syntax error!
One way to handle this is to use %c
in the format string, just like we used %s
to expand the data.
# version 4.2
s='s=%c%s%c; print(s)'; print(s%(39,s,39))
# output
s='s=%c%s%c; print(s)'; print(s)
The magic number 39 is the ASCII code for a single quote.
What's left is the printing part inside the data: print(s%(39,s,39))
.
The only tricky bit here is that you need to escape the percent sign in the data. Luckily, you can just use double percent (%%
) to escape it.
Here's the final version and it's a proper quine!
# version 5
s='s=%c%s%c; print(s%%(39,s,39))'; print(s%(39,s,39))
# output
s='s=%c%s%c; print(s%%(39,s,39))'; print(s%(39,s,39))
Quine Relay
Now that we know how to write a quine, let's take it to the next level!
A quine relay is a program that prints code in a different language, which prints code in yet another language, and so on until it eventually prints the original code again.
I'll create a quine relay between Python and PHP, walking through the process step by step.
Python Printing PHP
Here's version 1:
# version 1
s='here is some python code';print('<?php print("%s");' % s)
# result
<?php print("here is some python code;");
The printed result is actually valid PHP code. The idea here is that instead of printing "here is some python code"
, we want the PHP code to print the original Python code.
Let's replace the content of variable s
with a more realistic value.
# version 2
s='s=\'%s\';print(\'<?php print(%s);\' %% s)';print('<?php print("%s");' % s)
# result PHP
<?php print("s='%s';print('<?php print(%s);' %% s)");
# result of result PHP
s='%s';print('<?php print(%s);' %% s)
Hopefully you can see where we're going. If you look at the final result, you'll notice we only need to replace the first %s
with the value of s
from the original code.
Add Self-Replicating Code
So I added the replacement:
# Version 3
s='s=\'%s\';print(\'<?php print(%%s);\' %% s)';print('<?php print("%s");' % (s%s))
# result PHP
<?php print("s='s='%s';print('<?php print(%%s);' %% (s%%s))';print('<?php print(%s);' % (s%s))");
This part is where the magic happens.
print('<?php print("%s");' % (s%s))
(s%s)
is expanding s
inside s
itself, and the result gets added to the PHP code output.
The string that PHP is trying to print is quite close to the original Python code, but the PHP code itself is no longer valid. Let's fix the escaping.
After some trial and error, I managed to make the escaping work:
# Version 4
s="s=%r;print('<?php print(%%r);' %% (s%%s))";print('<?php print(%r);' % (s%s))
# Result PHP
<?php print('s="s=%r;print(\'<?php print(%%r);\' %% (s%%s))";print(\'<?php print(%r);\' % (s%s))');
# Result Python of Result PHP
s="s=%r;print('<?php print(%%r);' %% (s%%s))";print('<?php print(%r);' % (s%s))
The trick here is Python's %r
formatter. This is similar to %s
, but it prints strings as valid Python code, automatically handling quote escaping for you.
Obfuscate the Code
You'll notice that many quine examples online are somewhat obfuscated, so let's make our quine relay harder to read. This is a rare opportunity—in your day job, you don't normally get to obfuscate your code!
First, I'll use _
instead of s
as the variable name to make the code look more eccentric. We can also remove all unnecessary whitespace.
# Version 5
_="_=%r;print('<?php print(%%r);'%%(_%%_))";print('<?php print(%r);'%(_%_))
In PHP, you can also use a shorthand syntax: instead of <?php print("something");
, you can write <?="something"?>
.
Here's my final version of the quine relay:
# Version 5
_="_=%r;print('<?=%%r?>'%%(_%%_))";print('<?=%r?>'%(_%_))
# Result PHP
<?='_="_=%r;print(\'<?=%%r?>\'%%(_%%_))";print(\'<?=%r?>\'%(_%_))'?>
Conclusion
Quines available online are often optimised for strangeness most of the time (which is cool, but not good for explanation purposes 😅).
Hopefully this article helped you to understand this strange and beautiful concept in a readable code.
To be fair, once I understood the concept, what I enjoyed the most was obfuscating the code. What I learned from this experience is that reading obfuscated code is much harder than writing obfuscated code. So, I might write another article about explaining tricky code!
Thanks for reading 😆
Reference
If you are interested in writing your own quines, these articles are useful and inspiring.
Wikipedia quine
Top comments (0)