Quine and narcissist: how does it work?

Sat 30 July 2016 by TWal

Quines and narcissists are quite useless, but I find them quite interesting. A quine is a program that prints its own source code, and a narcissist is a program that recognizes its own source code.

Quine

With Python

Let’s see how we can write a quine in Python with a little exercise. Start with the following code:

data = """abc
def
ghi"""

I used Python’s multi-line string with triple-quotes """.

The exercise is (warning: answer just below): write a program that prints the code above to initialize data, in a way that if you change the value of data then, your code still works.

One way to do this is:

threequote = '"'*3
print("data = " + threequote + data + threequote)

Okay, so now you have a program that prints half of its source code. Now try to modify it to print the other half.

One way to do this is:

data = """threequote = '"'*3
print("data = " + threequote + data + threequote)
print(data)"""
threequote = '"'*3
print("data = " + threequote + data + threequote)
print(data)

To print the other half, we use data!

Shorter quines exists, but they are often less readable, like:

a="print('a='+repr(a)+';'+a)";print('a='+repr(a)+';'+a)

using Python’s repr function, or

a='a=%r;print(a%%a)';print(a%a)

using the %-formatting functionality.

With Brainfuck

We can use the same pattern using Brainfuck. Here is a quine I wrote a while ago:

>>+>>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>+++++>+>++++>+>++>+>+>+>+>+>++++++>+>>+>>+>>+>>+>>+>>+>>+>>+>>+>>+>>+>>+>>+>+>+>++>+>+++++>+>+++++>+>+++++>+>+++++>+>++>+>+>+>++>+>+>+>+>+>+>+>+>+>+>+>++>+>+>+>++>+>+>+>+>+>+>+>++>+>+>+>++>+>+>+>++>+>+>+>++>+>++>+>+>+>++>+>+>+>+>+>+>+>++>+>+>+>++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>+>+>>+>>+>+++>+>++>+>++>+>+++++>+>>+>>+>+++++>+>>+>>+>+++>+>>+>>+>++++>+>>+>++++++>+>>+>>+>++++++>+>++>+>++>+>++++++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>+++>+>>+>+++>+>>+>>+>++++>+>>+>>+>>+>++++++>+>++>+>++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>++>+>+>+>>+>>+>>+>+++++>+>++++>+>++>+>++>+>++>+>+++>+>>+>>+>>+>+>+>++>+>++>+>++>+>+++++>+>++++>+>+>+>>+>>+>+>+>>+>>+>++++>+>>+>>+>+++++>+>++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>>+>+++++>+>>+>>+>+++>+>+++++>+>>+>+++>+>>+>+++>+>>+>>+>++++>+>>+>>+>+++>+>>+>>+>++++>+>+>+>>+>>+>+++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>+++++>+>++++>+>>+>+++>+>>+>>+>++++>+>>+>>+>+++>+>>+>>+>++++>+>++>+>++++++>+>>+>+>+>+++>+>++>+>++>+>++++>+>>+>>+>+++++>+>++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>>+>++++>>>++++++++++[<++++++>>++++>>++++++>>+++++++++>>+++++++++>>++++>>+++++<<<<<<<<<<<-]<++.>>>>>>>>>>>>>+<----<+<+++++<+<+++<+<+<+<<+<+++<+<<<<[<<]+>>[<<->>->>[>>]>.>>.<<.<<<[<<]>[>[>>]>>>.<<<<<[<<]<<+>>>-]<<<[>>>+<<<-]+>>+>>]>>-<<<<[<<]>>->>[->[>[>>]>>[>>]+>>-<<[<<]<<[<<]>-]>[>>]>>[>>]<.>+[<<]>>-<<<<[<<]>>]

You can view its SimpleBrainfuck source code here.

It uses the same pattern: set up some data, print the data initialization code, print the content in data (that contains the second part of the source code).

Again, you can find shorter quines on the Internet.

Narcissist

With Python

To program a narcissist, you can read the whole input using sys.stdin.read(). See if you can make a narcissist using the same ideas used in the quine!

One way to do it is like this:

data = """import sys
inp = sys.stdin.read()
threequote = '"'*3
newline = chr(10)
res = "data = " + threequote + data + threequote + newline + data + newline
print(res == inp)"""
import sys
inp = sys.stdin.read()
threequote = '"'*3
newline = chr(10)
res = "data = " + threequote + data + threequote + newline + data + newline
print(res == inp)

res contains the program source code, and we compare it to the input inp

With Brainfuck

A narcissist I wrote a while ago in brainfuck looks like this:

>>+>>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>>+>>+>+>+>+>+>+>+>+>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>++>+>+++++>+>++++>+>++>+>+>+>+>+>>+>+>+>>+>+>+>+>+>+>+>>+>+>+>>+>>+>+>+>>+>+>+>>+>+>+>>+>+>+>+>+>+>+>>+>+>+>>+>+>+>+>+>+>+>+>+>+>+>>+>+>+>>+>+++++>+>+++++>+>+++++>+>+++++>+>>+>+>+>>+>+>+>+>+>+>+>+>+>>+>+>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+++>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>++>+>+++++>+>++++>+>>+>>+>>+>+>+>++>+>++>+>+++++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>+>+>>+>>+>+++>+>++>+>++>+>+++++>+>>+>>+>+++++>+>>+>>+>+++>+>>+>>+>++++>+>>+>>+>+++>+>>+>>+>++++>+>>+>>+>>+>+++>+>>+>>+>>+>++++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>>+>>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>++>+>++>+>++>+>++>+>++>+>+++++>+>++++>+>++>+>+++++>+>>+>>+>+>+>>+>+>+>>+>>+>+>+>>+>+++++>+>>+>>+>+>+>+++>+>++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>+++>+>>+>+++>+>>+>>+>++++>+>>+>>+>+++>+>>+>>+>++++>+>>+>>+>>+>+++>+>>+>>+>>+>++++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>+++++>+>++++>+>++>+>+>+>>+>>+>+>+>+++>+>++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>++>+>+>+>>+>>+>>+>+++++>+>++++>+>++>+>++>+>++>+>+++>+>>+>>+>>+>+>+>++>+>++>+>++>+>+++++>+>++++>+>+>+>>+>>+>+>+>>+>>+>++++>+>>+>>+>+++++>+>++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>>+>+++++>+>>+>>+>+++>+>+++++>+>>+>+++>+>>+>+++>+>>+>>+>++++>+>>+>>+>+++>+>>+>>+>++++>+>+>+>>+>>+>+++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>+++++>+>++++>+>>+>+++>+>>+>>+>++++>+>>+>>+>+++>+>>+>>+>++++>+>++>+>+++>+>>+>>+>>+>+++>+>>+>>+>++++>+>++>+>+>+>>+>>+>>+>>+>+++>+>>+>>+>>+>++++>+>++>+>++>+>+>+>++>+>+++>+>++>+>++>+>++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>++>+>+++++>+>++++>+>>+>>+>>+>+++>+>>+>>+>++++>+>>+>>+>>+>+++>+>>+>>+>>+>++++>+>+>+>+++>+>++>+>++>+>++>+>++++>+>++>+>+++>+>+++>+++>+>++>+>++>+>++++>+>++>+>+>+>>+>>+>>+>+++>+>>+>>+>++++>+>++>+>+++++>+>++++>+>++>+>+++>+>++>+>++>+>++++>+>+>+>+++>+>++>+>++>+>++++>+>>+>>+>+++++>+>++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++++>+>>+>>+>++++>+>>+>>+>+>+>+++>+>>+>>+>++++>+>>+>>+>>+>+++>+>>+>>+>>+>++++>+>++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>++>+>+++>+>++>+>++>+>++>+>++++>+>>+>>+>+++++++>+>+++>+>>+>+++>+>+++++>+>++++>+>+>+>>+>>+>+++++++>+>++++>+>++>+>++>+>+++>+>++>+>++>+>++>+>++++>+>++>+>+>+>>+>>+>>+>>+>+++>+>+++++>+>++>+>+++>+>++>+>+++++>+>>+>+++++>+>++++>+>++>+>+++>+>++>+>+++>+>++>+>++>+>++>+>++++>+>++>+>+++>+>+++++>+>++++>+>>+>>+>>+>>+>+++>+>>+>>+>>+>++++>+>++>+>++>+>+++>+>+++++>+>++++>+>++++>+>>+>>+>+>+>>+>>+>>+>++++>+>++>+>++>+>++>+>+++>+>++>+>++>+>++>+>++++>+>+>+>+>+>+>+>+>+>+>+>+>+>+++>+>++>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>>+>+++++>+>++++>+>++>+>++++++>>>++++++++++[<++++++>>++++>>++++++>>+++++++++>>+++++++++>>++++>>+++++>>++++<<<<<<<<<<<<<-]<++>+>+++>+>>+>+>+>+++>+>+++++>+>---->+>++++>+>>+++++++[>+++++++++<-]>>>+<<-<<<[<<]<<[<<]+>>[<<->>->>[>>]>>[>>]>>>[>>>]<+++++++[<+++++++++>>>++++++>>>+++++++++<<<<<-]<->>+>+>>+>->>+[<<<]<<[<<]<<[<<]>[>[>>]>>[>>]>>>[>>>]<+++++++[<++++++>-]<+>>+[<<<]<<[<<]<<[<<]<<+>>>-]<<<[>>>+<<<-]+>>+>>]>>-<<<<[<<]>>->>[->[>[>>]>>[>>]+>>-<<[<<]<<[<<]>-]>[>>]>>[>>]<[>>>[>>]<+>>>>[>>>]<<+<[<<<]<<[<<]<-]>>>[>>]>>>[>>>]+[<<<]<[<[<<]<+>>>[>>]<-]<[<<]+[<<]>>-<<<<[<<]>>]>>+[>>]>>>[>>>]<<++++++++++<[<<<]>>,[>[-]+>>,]<<[<<<]<+>>>>[-<[<->-]<[<[<<<]<[-]>>>>[>>>]<<[-]]>>+>>>]<<<[<<<]++++++[<++++++++>-]<.

You can view its SimpleBrainfuck source code here.

Strange ways to make quines

Here is the shortest Python quine in the world:


Yes, it’s an empty file. It prints nothing, so it prints its own source code. Therefore, interesting quines are non-empty.

print(open(__file__).read(), end='')

This one reads its own source code from the disk. It shows that interesting quines shouldn’t read any input.

Now a fun one: (<stdin> should be replaced by the name of the file where it is stored).

  File "<stdin>", line 1
    File "<stdin>", line 1
    ^
IndentationError: unexpected indent

This quine produce an error, and the error is the quine’s source code.

How do we discover it? Let \(P(s)\) the output of Python with the source code \(s\). Then a quine \(q\) verifies \(P(q) = q\): it’s a fixed-point of \(P\)!

A general principle in mathematics is that if the sequence \(x_0, f(x_0), f(f(x_0)), ...\) converge, then its limit is a fixed-point of \(f\) (given some hypotheses on \(f\)).

Let’s apply this principle with \(f = P\) and \(x_0={}"blah"\):

$ echo blah
blah
$ echo blah | python 2>&1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'blah' is not defined
$ echo blah | python 2>&1 | python 2>&1
  File "<stdin>", line 1
    Traceback (most recent call last):
                         ^
SyntaxError: invalid syntax
$ echo blah | python 2>&1 | python 2>&1 | python 2>&1
  File "<stdin>", line 1
    File "<stdin>", line 1
    ^
IndentationError: unexpected indent
$ echo blah | python 2>&1 | python 2>&1 | python 2>&1 | python 2>&1
  File "<stdin>", line 1
    File "<stdin>", line 1
    ^
IndentationError: unexpected indent

\(P(P(P("blah")))\) is a quine!

Conclusion

If you have enough motivation, you can try to write a quine and a narcissist in your favorite language!