DEV Community

Cover image for Quine Clique: 51 programs in 51 languages that all print each other
Yusuke Endoh
Yusuke Endoh

Posted on

Quine Clique: 51 programs in 51 languages that all print each other

A quine is a program that prints itself. And a multiquine is a set of programs that print themselves and each other.

I have created Quine Clique, which is a 51-language multiquine:

Quine Clique

 

Here is the video explanation:

 

The repository is here:

GitHub logo mame / quine-clique

51 quines in 51 languages, every one able to print every other

Quine Clique

qc.rb is a quine written in Ruby: a program that prints itself Ask it for Python, and it prints a Python quine instead Or a JavaScript quine. Or a Rust quine. Or a C quine. Or any of 50 languages in all.

Every one of those quines can do the same: all of them can generate each other. A clique of quines.

Quine Clique

▶ Video explanation (9 min)

Quine Clique 101

Ruby Quine

Here is qc.rb:

The text of qc.rb

This is a Ruby program. It is a quine. Run it, and it prints itself.

$ ruby qc.rb > out.bin
$ diff -s qc.rb out.bin
Files qc.rb and out.bin are identical
Enter fullscreen mode Exit fullscreen mode

Ruby → Python

Run qc.rb with the argument py, and it prints a quine written in Python.

$ ruby qc.rb py > qc.py
Enter fullscreen mode Exit fullscreen mode

Let's run it.

$ python3 qc.py > out.bin
$ diff -s qc.py out.bin
Files qc.py and
Enter fullscreen mode Exit fullscreen mode

 

What is Quine Clique?

Let me walk you through it.

The Ruby quine: qc.rb

First, this is qc.rb, which is the Ruby member of the Quine Clique.

qc.rb

It is a quine written in Ruby. That is, it prints itself when you run it.

# The output of qc.rb is identical to qc.rb itself
$ ruby qc.rb > out.bin
$ diff -s qc.rb out.bin
Files qc.rb and out.bin are identical
Enter fullscreen mode Exit fullscreen mode

Ruby → Python

It is not just a quine. Run ruby qc.rb py, and it prints a Python program, qc.py.

# qc.rb can print qc.py
$ ruby qc.rb py > qc.py
Enter fullscreen mode Exit fullscreen mode

And that Python program is a quine.

# The output of qc.py is identical to qc.py itself
$ python3 qc.py > out.bin
$ diff -s qc.py out.bin
Files qc.py and out.bin are identical
Enter fullscreen mode Exit fullscreen mode

Ruby ↔ Python

Run python3 qc.py rb, and it prints the original Ruby program, qc.rb.

# qc.py can print qc.rb
$ python3 qc.py rb > out.bin
$ diff -s qc.rb out.bin
Files qc.rb and out.bin are identical
Enter fullscreen mode Exit fullscreen mode

So qc.rb and qc.py are each a quine, and they can regenerate each other when you tell them which language you want.

This is a multiquine of two languages, Ruby and Python.

qc.rb and qc.py printing each other

+ JavaScript

That is not the end of it. JavaScript is supported too.

Run ruby qc.rb js, and it prints a JavaScript quine, qc.js. Run node qc.js and it prints itself; run node qc.js rb and it prints the original qc.rb.

# qc.rb can print qc.js
$ ruby qc.rb js > qc.js

# The output of qc.js is identical to qc.js itself
$ node qc.js > out.bin
$ diff -s qc.js out.bin
Files qc.js and out.bin are identical
Enter fullscreen mode Exit fullscreen mode

And qc.js and qc.py can print each other as well.

# qc.js can print qc.py
$ node qc.js py > out.bin
$ diff -s qc.py out.bin
Files qc.py and out.bin are identical

# qc.py can print qc.js
$ python3 qc.py js > out.bin
$ diff -s qc.js out.bin
Files qc.js and out.bin are identical
Enter fullscreen mode Exit fullscreen mode

qc.rb, qc.py and qc.js printing one another

50 + 1 languages in total

In the same way, it supports Rust, Go, TypeScript, C, C++, Objective-C, C#, Java, Kotlin, Swift, Zig, Lua, R, Perl, PHP, Haskell, OCaml, Standard ML, Scala, Haxe, Groovy, Clojure, Erlang, Elixir, F#, Racket, Scheme, Common Lisp, Prolog, D, Nim, Crystal, Vala, Pascal, Fortran, Forth, Octave, Tcl, AWK, Bash, CoffeeScript, Pike, and PostScript.

Notably, it also supports five esoteric languages: brainfuck, Piet, Befunge, Whitespace, and Unlambda. Getting all of these to run at a realistic size and in a realistic time is quite something -- if you know, you know.

The sizes and running times look like this.

  • Size: the smallest is qc.rb at 17 KB. The largest is Piet (qc.piet.gif) at 5.3 MB.
  • Time: the slowest is Bash → Piet at about 7 minutes, followed by Piet → Piet at 4 minutes.

Anyway, we now have a 50-language multiquine (51 if you count Ruby itself): programs that can all print one another. All 51 x 51 = 2,601 combinations are tested on GitHub Actions.

How it works

Let me explain how it is implemented. The key is QCLang, a minimal language made for Quine Clique.

QCLang in a nutshell

It is a very simple language. Or maybe it is better to call it a VM. The only operation is subtraction, the only control structure is a loop, and the only storage is an accumulator and eight registers.

Instruction Meaning
!.../ print ... verbatim (H is the escape; Hx prints the character x - 33)
& read one character from its own source into the accumulator
(...) loop while the accumulator is non-zero
* print the accumulator as a character code
0..7 store the accumulator into a register
8..? load a register into the accumulator
@..G subtract a register from the accumulator
H..~ set the accumulator to an immediate (the character code of the instruction)

It is this simple so that an interpreter for QCLang can be written in a great many languages.

A quine in QCLang

QCLang is specialized for writing quines, so a quine takes only these five characters.

&(*&)
Enter fullscreen mode Exit fullscreen mode

& reads one byte of the source itself, and (...) loops. Inside the loop, * prints the character that was read, and & reads the next one. When & reaches the end of the source, the accumulator becomes 0, the loop exits, and the program ends.

A Ruby quine using QCLang

If you prepare some Ruby code that runs QCLang, you can write a Ruby quine using QCLang.

core = '!core = HH/&(*&)!HH;run_qclang_in_ruby(core)/';
run_qclang_in_ruby(core)
Enter fullscreen mode Exit fullscreen mode

core contains QCLang code. And run_qclang_in_ruby is a Ruby function that interprets QCLang (in reality its implementation has to be included too).

The QCLang code in core does the following.

  • !core = HH/ prints the string core = ' (HH is the escaped form of ')
  • &(*&) is the QCLang quine, and prints the contents of core
  • !HH;run_qclang_in_ruby(core)/ prints the string ';run_qclang_in_ruby(core)

Concatenating these outputs gives back the code above. In other words, it is a Ruby quine.

A Ruby/Python multiquine using QCLang

Next is a Ruby and Python multiquine (the Ruby side of it). The QCLang part is pseudocode.

core = '
  if "rb" is asked: !core = HH/&(*&)!HH;run_qclang_in_ruby(core)/
  if "py" is asked: !core = HH/&(*&)!HH;run_qclang_in_python(core)/
';
run_qclang_in_ruby(core, ARGV[0] || "rb")
Enter fullscreen mode Exit fullscreen mode

It looks at the command-line argument, and prints the Ruby quine if rb is given, or the Python quine if py is given.

The nice thing about this structure is that you can keep adding languages just by adding a branch to core, like if "js" is asked: !core = HH/&(*&)!HH;run_qclang_in_js(core)/. This means that when you add a language, you do not have to worry about its relationship with every existing language; you can add it modularly. Ideally.

Constraints and tricks

In practice there were all sorts of constraints: string literals are handled differently in each language, character codes are handled differently, some languages limit the source length, and so on. So you cannot add languages quite as cleanly and modularly as that. But writing all of this out would be endless, so I will skip it.

Side notes

A clique in graph theory means a set of vertices that are all connected to each other. The programs in 50 + 1 languages can all reach each other, so it really is a clique.

By the way, "clique" in English also has that slightly awkward meaning of an exclusive little group at school or at work, but there is no intent to shut out the languages that are not in here. Still, it is hard to add more languages to the Clique, so sorry to the ones that did not make it.

The spider in the middle was drawn by @hirekoke. The same person drew the ouroboros for Quine Relay. It is a spider because a clique diagram looks like a spider web.

Related work

Quine Relay (2013). A quine that goes through 128 languages in order and comes back to itself. It is a one-way chain of 128 languages, not a multiquine.

Quine Chameleon (2015). A multiquine of 25 languages. It stays compact and elegant by restricting itself to languages with C-style string literals. Our advantage is that we also support brainfuck, Piet and others, which that approach can never cover.

Multiquine with ELVM (2016, in Japanese). A prototype multiquine built on ELVM, a compiler infrastructure for esoteric languages. In principle it could produce a multiquine over many languages, but the code was far too big to run at a realistic size or in a realistic time.

Thank you, AI

As you can see from the conceptual prototype in Multiquine with ELVM, the idea of Quine Clique had been with me since before 2016. But writing a QCLang interpreter in every language was too much of a chore, so it never happened.

The reason it happened this time is, quite simply, AI coding agents. Tell them to write QCLang interpreters in 51 languages and they do so without complaint, and when the QCLang spec changes, they follow along. Though we did fight a lot over the beauty of the code. AI has no eye for beauty yet.

I was a little worried that building a weird program with Claude Code might spoil the sense of accomplishment, but the moment it worked I still felt on top of the world, so all is well.

By the way, what impressed me most about the AI was not the code it wrote but the explainer video it made. I handed it the README and a draft of this article as an outline, and it casually whipped up the video at the top of this article.

Conclusion

I introduced Quine Clique, a 51-language multiquine.

Thanks to AI, a long-standing dream is now actually running, and I could not be happier. Go write your own fun quines with AI, everyone.

Top comments (0)