In the previous adventures of the Quine blog series, we explored how to write our own Quines and Introns. Today we will see what QuineRelays are and how you can leverage Introns to create them.
Imagine a circle of programs, each written in a different language. Each program in this circle has a single purpose: to print the source code of the next program in the sequence. The last program then closes the loop by printing the source code of the very first program.
Essentially, QuineRelays are a set of n programs, in n different languages such that:
- Each program outputs the source of the next.
- The last program outputs back the source of the first one. Think Circular-Linked-List here. The last example is a mind-blower!
Let's see some examples to grasp the concept better.
2nd-order relay
This 2nd-order QuineRelay features a JavaScript program that prints a Python program, which then prints the original JavaScript program back. It's a dynamic duo of self-replication.
JavaScript → Python ⥀
JavaScript: Try it online!
console.log((q=_=>`print(${JSON.stringify(`console.log((q=${q+[]})())`)})`)())
Python: Try it online!
print("console.log((q=_=>`print(${JSON.stringify(`console.log((q=${q+[]})())`)})`)())")
3rd-order relay
Things get even more interesting with a 3rd-order QuineRelay. This one starts with a Haskell program, which outputs a Python program, which outputs a Ruby program, and finally, the Ruby program loops back to the original Haskell program.
Haskell → Python2 → Ruby ⥀
Haskell: Try it online!
q a b c=putStrLn $ b ++ [toEnum 10,'q','('] ++ show b ++ [','] ++ show c ++ [','] ++ show a ++ [')']
main=q "q a b c=putStrLn $ b ++ [toEnum 10,'q','('] ++ show b ++ [','] ++ show c ++ [','] ++ show a ++ [')']" "def q(a,b,c):print b+chr(10)+'q('+repr(b)+','+repr(c)+','+repr(a)+')'" "def e(x) return 34.chr+x+34.chr end;def q(a,b,c) print b+10.chr+'main=q '+e(b)+' '+e(c)+' '+e(a)+' '+10.chr end"
Python2: Try it online!
def q(a,b,c):print b+chr(10)+'q('+repr(b)+','+repr(c)+','+repr(a)+')'
q("def q(a,b,c):print b+chr(10)+'q('+repr(b)+','+repr(c)+','+repr(a)+')'","def e(x) return 34.chr+x+34.chr end;def q(a,b,c) print b+10.chr+'main=q '+e(b)+' '+e(c)+' '+e(a)+' '+10.chr end","q a b c=putStrLn $ b ++ [toEnum 10,'q','('] ++ show b ++ [','] ++ show c ++ [','] ++ show a ++ [')']")
Ruby: Try it online!
def e(x) return 34.chr+x+34.chr end;def q(a,b,c) print b+10.chr+'main=q '+e(b)+' '+e(c)+' '+e(a)+' '+10.chr end
q("def e(x) return 34.chr+x+34.chr end;def q(a,b,c) print b+10.chr+'main=q '+e(b)+' '+e(c)+' '+e(a)+' '+10.chr end","q a b c=putStrLn $ b ++ [toEnum 10,'q','('] ++ show b ++ [','] ++ show c ++ [','] ++ show a ++ [')']","def q(a,b,c):print b+chr(10)+'q('+repr(b)+','+repr(c)+','+repr(a)+')'")
4th-order relay
Here's a 4th-order QuineRelay: Ruby → Java → C# → Python ⥀
GitHub
Across cultures, there are several shared symbolisms. One of them is the Ouroboros, which has references in Egyptian, Greek, Roman, Hindu, Siberian, Norse, African, and South American mythologies. The Ouroboros is an ancient symbol depicting a serpent or dragon consuming its own tail, representing the eternal cycle of creation and destruction.
In Norse mythology, Jörmungandr is a colossal serpent, the middle child of Loki and the giantess Angrboða. Odin cast Jörmungandr into the ocean surrounding Midgard (the realm of humans), where the serpent grew so immense that it encircled the world and grasped its own tail. As a result of it surrounding Midgard (the Earth) it is referred to as the World Serpent - Ouroboros. Jörmungandr releasing its tail is one of the signs of the beginning of Ragnarök (the final battle of the world).
Quine relays embody this symbolism quite neatly, as each program in the cycle gives rise to the next, only to be reborn in the end, and hence are nicknamed Ouroboros programs.
128th-order Ouroboros relay
Hold on to your seats. Here's a 128th-order Ouroboros QuineRelay. Yes, you read that right. 128 !!!
Ruby → Rust → Scala → ... (120 others) ... → Python → R → Ratfor → rc → REXX ⥀
GitHub
As if this wasn't impressive enough, it includes an easter egg. The original Ruby code when zoomed out contains an Ouroboros dragon!
Writing your own QuineRelay
Let's start the Python intron we wrote earlier and try to turn it into a 2nd-order QuineRelay.
Python Intron: Try it online!
intron = 'wubbalubbadubdub'
data = "print('intron =', repr(intron)); print('data =', repr(data)); print(data)"
print('intron =', repr(intron)); print('data =', repr(data)); print(data)
Using the magic of introns, we can now easily put the code part of a sibling Quine of a different language into the intron. Producing a program of the form:
Python:
intron = "code part of sibling"
data = "code part of self"
print('intron =', repr(intron)); print('data =', repr(data)); print(data)
Since, each variable is just, acting as data of a different Quine. Let's rename data
and intron
, into d1
and d2
respectively.
Python:
d1 = "code part of self"
d2 = "code part of sibling"
print('d1 =', repr(d1)); print('d2 =', repr(d2)); print(d1)
Now, d2
acts as an intron, but the above program still tried to print code part of self. To have it print source of the next, let's print(d2)
instead of print(d1)
at the end.
Python:
d1 = "code part of self"
d2 = "code part of sibling"
print('d1 =', repr(d1)); print('d2 =', repr(d2)); print(d2)
We already know that the contents of d1
is just a copy of line 3. But we don't yet have the contents of d2
.
Say, we wanted to create a QuineRelay with JavaScript. Let's write a similar intron in JS.
JavaScript:
d1 = "code part of sibling"
d2 = "code part of self"
console.log(`d1 = ${JSON.stringify(d1)}`); console.log(`d2 = ${JSON.stringify(d2)}`); console.log(d1);
Now, line 3 of the above JS intron, is the code of the sibling program we wanted!
Paste each other's code as introns in the other.
Note. We need to add d1 + ''
in js to avoid some quoting mismatches
Python: Try it online!
d1 = "print('d1 =', repr(d1)); print('d2 =', repr(d2)); print(d2)"
d2 = "console.log(`d1 = ${JSON.stringify(d1)}`); console.log(`d2 = ${JSON.stringify(d2)}`); console.log(d1 + '');"
print('d1 =', repr(d1)); print('d2 =', repr(d2)); print(d2)
JavaScript: Try it online!
d1 = "print('d1 =', repr(d1)); print('d2 =', repr(d2)); print(d2)"
d2 = "console.log(`d1 = ${JSON.stringify(d1)}`); console.log(`d2 = ${JSON.stringify(d2)}`); console.log(d1 + '');"
console.log(`d1 = ${JSON.stringify(d1)}`); console.log(`d2 = ${JSON.stringify(d2)}`); console.log(d1 + '');
There you go. It's a proper 2nd order QuineRelay! A Python program, that prints a JavaScript program, that prints the original Python program back in a cycle.
Creating a QuineRelay is an exercise in creative coding and understanding how different languages represent and manipulate strings. It involves weaving together introns from various programs, each containing the code to replicate its next neighbour.
At its core, an nth-order relay is a game of n clever ways to escape quotes across n programming languages.
Stay tuned for the next post on MultiQuine!
Sources and references:
- Ouroboros programs, wiki page.
- A Third Order Quine in Three Languages, blog by sigfpe.
- Chain Quine, GitHub repo by Ibragimov Ruslan.
- 128 Quine Relay, GitHub repo by Yusuke Endoh.
- QuineRelay: Birth of the Quine serpent, self-referencing blog where a word in each n-order example hyperlinks to the next, cyclically. (May not work in dev.to; checkout the canonical blog)
- Jörmungandr, wiki page.
- Ouroboros, wiki page.
- Art of Code, talk by Dylan Beattie
Top comments (0)