Quine Relay: a circular quine in 50 languages

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
3rdtry
Posts: 152
Joined: Sat Feb 16, 2013 1:46 pm UTC

Quine Relay: a circular quine in 50 languages

Postby 3rdtry » Tue Dec 03, 2013 12:33 am UTC

I thought this was so cool it deserved its own thread: Quine relay, an uroboros program with 50 programming languages. As its name indicates, it's a Ruby program that when run outputs a Scala program, that when run outputs a Scheme program, and so on with Bash, Smalltalk, Tcl, Unlambda, Vala, Verilog, Whitespace, Ada, ALGOL69, Awk, Boo, Brainfuck, C, C++, C#, Clojure, Cobol, CoffeeScript, Common Lisp, Forth, FORTRAN77, Fortran90, Go, Groovy, Haskell, Icon, INTERCAL, Jasmin, Java, LLVM asm, Logo, Lua, Makefile, MSIL, NodeJS, Objective-C, OCaml, Octave, Parrot, Pascal, Perl, PHP, Pike, Prolog, Python, R and REXX, which outputs back the original Ruby program.

This is its code, and this is the first iteration. I haven't tested all of them (stupid buggy scheme-mit package in Ubuntu) but I'm assuming they work.

I mean, I often struggle to see how a quine works in just one language, but 50? In just 54 lines of code? Including Brainfuck, Whitespace and Intercal? :shock:

The guy who made it has also made tons of other cool things, including "ASCII fluid dynamics".

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Quine Relay: a circular quine in 50 languages

Postby Jplus » Tue Dec 03, 2013 9:30 am UTC

FWIW, there's a name for this kind of thing: iterative multiquine.

Anyway, yes, it's very cool.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
skeptical scientist
closed-minded spiritualist
Posts: 6142
Joined: Tue Nov 28, 2006 6:09 am UTC
Location: San Francisco

Re: Quine Relay: a circular quine in 50 languages

Postby skeptical scientist » Sat Dec 14, 2013 2:40 am UTC

3rdtry wrote:I thought this was so cool it deserved its own thread: [url=http://pastebin.com/3694KjJf]this is the first iteration.

That is some extreme quote escaping.

I'm not sure how the creator did it, but I know how I would make a multiquine. The basic idea of a simple quine is something like this python quine.

Code: Select all

_PROGRAM = '_PROGRAM = %s\nprint _PROGRAM %% repr(_PROGRAM)'
print _PROGRAM % repr(_PROGRAM)

Nothing clever, just a straightforward use of a simple skeleton,

Code: Select all

_PROGRAM = %s
print _PROGRAM % repr(_PROGRAM)

and we fill out the skeleton by replacing the placeholder %s with the skeleton, modified to be a python string literal. Python (which this is written in) already has a repr() function which is perfect for this, because it escapes our string to produce the appropriate string literal.

In another language, we might have to write our own version of repr (which doesn't have to be perfect, just sufficient for the string we are using). An example is this C quine.

Code: Select all

#include <stdio.h>

char* _PROGRAM = "#include <stdio.h>\n\nchar* _PROGRAM = %s;\n\nvoid repr(const char* input, char* output) {\n  *output++ = \'\"\';\n  while (*input != \'\\0\') {\n    switch (*input) {\n      case \'\\n\':\n        *output++ = \'\\\\\';\n        *output++ = \'n\';\n        break;\n      case \'\\\\\':\n        *output++ = \'\\\\\';\n        *output++ = \'\\\\\';\n        break;\n      case \'\\\'\':\n        *output++ = \'\\\\\';\n        *output++ = \'\\\'\';\n        break;\n      case \'\\\"\':\n        *output++ = \'\\\\\';\n        *output++ = \'\\\"\';\n        break;\n      default:\n        *output++ = *input;\n    }\n    ++input;\n  }\n  *output++ = \'\"\';\n  *output++ = \'\\0\';\n}\n\nint main(void) {\n  char output[10000];\n  repr(_PROGRAM, output);\n  printf(_PROGRAM, output);\n}\n";

void repr(const char* input, char* output) {
  *output++ = '"';
  while (*input != '\0') {
    switch (*input) {
      case '\n':
        *output++ = '\\';
        *output++ = 'n';
        break;
      case '\\':
        *output++ = '\\';
        *output++ = '\\';
        break;
      case '\'':
        *output++ = '\\';
        *output++ = '\'';
        break;
      case '\"':
        *output++ = '\\';
        *output++ = '\"';
        break;
      default:
        *output++ = *input;
    }
    ++input;
  }
  *output++ = '"';
  *output++ = '\0';
}

int main(void) {
  char output[10000];
  repr(_PROGRAM, output);
  printf(_PROGRAM, output);
}

Although it is much longer, it takes exactly the same form as the original python quine, except that it contains a definition of the repr() function.


To get a multiquine, we can combine these two programs. Here is the python version:

Code: Select all

_PYTHON_SKELETON = "_PYTHON_SKELETON = %s\n_C_SKELETON = %s\n\ndef repr_for_c(string):\n  return \'\"%%s\"\' %% repr(string)[1:-1].replace(\'\"\',\'\\\\\"\')\n\nprint _C_SKELETON %% (repr_for_c(_PYTHON_SKELETON), repr_for_c(_C_SKELETON))\n"
_C_SKELETON = "#include <stdio.h>\n\nchar* _PYTHON_SKELETON = %s;\nchar* _C_SKELETON = %s;\n\nvoid repr_for_py(const char* input, char* output) {\n  *output++ = \'\"\';\n  while (*input != \'\\0\') {\n    switch (*input) {\n      case \'\\n\':\n        *output++ = \'\\\\\';\n        *output++ = \'n\';\n        break;\n      case \'\\\\\':\n        *output++ = \'\\\\\';\n        *output++ = \'\\\\\';\n        break;\n      case \'\\\'\':\n        *output++ = \'\\\\\';\n        *output++ = \'\\\'\';\n        break;\n      case \'\\\"\':\n        *output++ = \'\\\\\';\n        *output++ = \'\\\"\';\n        break;\n      default:\n        *output++ = *input;\n    }\n    ++input;\n  }\n  *output++ = \'\"\';\n  *output++ = \'\\0\';\n}\n\nint main(void) {\n  char py_skeleton[10000];\n  repr_for_py(_PYTHON_SKELETON, py_skeleton);\n  char c_skeleton[10000];\n  repr_for_py(_C_SKELETON, c_skeleton);\n  printf(_PYTHON_SKELETON, py_skeleton, c_skeleton);\n}\n"

def repr_for_c(string):
  return '"%s"' % repr(string)[1:-1].replace('"','\\"')

print _C_SKELETON % (repr_for_c(_PYTHON_SKELETON), repr_for_c(_C_SKELETON))

Here the python skeleton is a program to print the C skeleton, with the placeholders replaced with the python and C skeletons, respectively. The C skeleton is the opposite: a program to print the python skeleton, with the placeholders replaced with the python and C skeletons. I am making use of the fact that the format string syntax is similar in both python and C, but this is unnecessary; I could use some other placeholder string and do a replace. The only other difference is that the python version needs to produce C literals rather than python literals, and vice versa.

Using this same idea, the multiquine can be extended in a straightforward way to any number of languages, although in some languages (like brainfuck) "escaping a string" makes no sense; instead, the repr_for_brainfuck() function needs to produce a series of brainfuck statements that results in an in-memory representation of the string in some sort of controlled way. This isn't quite as bad as it sounds as programmatically generating brainfuck is much easier than writing brainfuck by hand. The way this works is with the following skeleton for language k:
_SKELETON_FOR_LANGUAGE_1 = placeholder_1
_SKELETON_FOR_LANGUAGE_2 = placeholder_2
...
_SKELETON_FOR_LANGUAGE_n = placeholder_n

* definition of a function which returns a representation in language n+1 for the input string *

* instructions to take _SKELETON_FOR_LANGUAGE_{k+1}, replace placeholders 1...n with repr_for_next_language(_SKELETON_FOR_LANGUAGE_1...n), and print the modified string *
I'm looking forward to the day when the SNES emulator on my computer works by emulating the elementary particles in an actual, physical box with Nintendo stamped on the side.

"With math, all things are possible." —Rebecca Watson

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Quine Relay: a circular quine in 50 languages

Postby Jplus » Sat Dec 14, 2013 9:40 am UTC

The languages of the Perl family (Perl, Python, Ruby, PHP) are notoriously easy to write quines in, though. Most languages require much more work, especially the esoteric ones like Whitespace, Brainfuck and INTERCAL (which all appear in the list!).
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
3rdtry
Posts: 152
Joined: Sat Feb 16, 2013 1:46 pm UTC

Re: Quine Relay: a circular quine in 50 languages

Postby 3rdtry » Mon Dec 16, 2013 3:12 am UTC

Very nice, but it's not a real quine if it doesn't have snow and christmas music :wink:.

User avatar
phlip
Restorer of Worlds
Posts: 7569
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Quine Relay: a circular quine in 50 languages

Postby phlip » Sun Dec 22, 2013 11:55 pm UTC

Why am I not surprised that all of the quines linked in this thread are by the same person as the spinning-globe quine that was my previous favourite quine ever...

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 9 guests