The meta-polyglot quine

18

3

In my time on PPCG, I've noticed that quine problems and polyglot problems are quite popular. Also, meta-solutions to problems, that is, scripts which generate a program which is the solution to a problem, tend to get a lot of positive feedback from the community. Therefore, I have created this challenge, which implements these three ideas.

Your task then, reader and enthusiast, is to create as short as possible a script which can run in two languages A and B to generate quines for A and B. When your program is run in language A, it should generate a program that is a quine in language B but not in language A and vice versa. The languages A and B can be different version of the same language, provided you keep in mind that the generated quines should only work in one of the versions.

Keep in mind that the standard loopholes should be considered closed and only proper quines are allowed.

Good luck, fewest characters wins!

Pavel

Posted 2016-11-08T04:34:17.283

Reputation: 8 585

1A quine is basically a meta-meta-meta-meta-meta-meta-meta-etc. program anyways :) – Esolanging Fruit – 2016-11-08T04:50:57.193

How to count bytes if the two languages use different character encodings? You should probably score in characters rather than bytes – Luis Mendo – 2016-11-08T08:13:06.833

1If I run the quine in language A to generate a quine for language B, should that be runnable in A? – corvus_192 – 2016-11-08T08:33:55.330

2@LuisMendo When writing a polyglot for languages with different encodings, I'd assume that they both receive the same byte stream (not different encodings of the same characters). – Martin Ender – 2016-11-08T14:11:18.093

@corvus_192 it doesn't matter how it runs in language A as long as it is not a quine. – Pavel – 2016-11-08T14:53:17.823

1

@Pavel I actually wrote a similar challenge here, but it got closed as a duplicate.

– Oliver Ni – 2016-11-11T04:22:56.547

Answers

5

CJam 0.6.6 dev / GolfScript, 15 14 12 bytes

"0$p"0$~a:n;

Thanks to @jimmy23013 for golfing off 2 bytes!

Rest to be updated.

Verification

Since the submission involves significant whitespace, it's best to compare hexdumps.

$ xxd -g 1 mpquine
0000000: 22 60 30 24 7e 22 30 24 7e 4e 4d 3a 6e 3b        "`0$~"0$~NM:n;
$
$ cjam mpquine | tee quine.gs | xxd -g 1
0000000: 22 60 30 24 7e 22 60 30 24 7e 0a                 "`0$~"`0$~.
$ golfscript quine.gs | xxd -g 1
0000000: 22 60 30 24 7e 22 60 30 24 7e 0a                 "`0$~"`0$~.
$ cjam quine.gs | xxd -g 1
0000000: 22 60 30 24 7e 22 60 30 24 7e                    "`0$~"`0$~
$
$ golfscript mpquine | tee quine.cjam | xxd -g 1
0000000: 22 60 30 24 7e 22 60 30 24 7e                    "`0$~"`0$~
$ cjam quine.cjam | xxd -g 1
0000000: 22 60 30 24 7e 22 60 30 24 7e                    "`0$~"`0$~
$ golfscript quine.cjam | xxd -g 1
0000000: 22 60 30 24 7e 22 60 30 24 7e 0a                 "`0$~"`0$~.

CJam

CJam prints "`0$~"0$~ and a trailing linefeed. Try it online!

The generated program prints "`0$~"0$~ with the trailing linefeed in GolfScript (Try it online!), but without the linefeed in CJam (Try it online!).

How the metaquine works

"`0$~"         e# Push that string on the stack.
      0$~      e# Push a copy and evaluate it:
               e#   `     Inspect the string, pushing "\"`0$~\"".
               e#    0$   Push a copy.
               e#      ~  Evaluate, pushing "`0$~".
               e# Both "\"`0$~\"" and "`0$~" are now on the stack.
         NM    e# Push "\n" and "".
           :n; e# Map print over the elements of "" (none) and pop the result.
               e# "\"`0$~\"", "`0$~", and "\n" are now on the stack, and the
               e# characters they represent will be printed implicitly.

How the quine works

"`0$~"          # Push that string on the stack.
      0$~       # As in CJam.
         <LF>   # Does nothing.
                # "\"`0$~\"" and "`0$~" are now on the stack, and the characters
                # they represent will be printed implicitly, plus a linefeed.

Unlike GolfScript, CJam doesn't print a trailing linefeed by default, so this is not a quine in CJam.

GolfScript

GolfScript prints "`0$~"0$~, without trailing whitespace. Try it online!

The generated program prints "`0$~"0$~ without trailing whitespace in CJam (Try it online!), but GolfScript appends a linefeed (Try it online!).

How the metaquine works

"`0$~"0$~       # As in CJam.
         NM     # Unrecognized token. Does nothing.
           :n   # Store the top of the stack – "`0$~" – in the variable n. n holds
                # "\n" by default. When the program finishes, the interpreter
                # prints n implicitly, usually resulting in a trailing linefeed.
                # By redefining n, it will print "0$~" instead.
             ;  # Pop the string from the stack so it won't be printed twice.

How the quine works

"`0$~"0$~      e# Works as in GolfScript.

Unlike CJam, GolfScript will append a linefeed to the contents of the stack, so this is not a quine in GolfScript.

Dennis

Posted 2016-11-08T04:34:17.283

Reputation: 196 637

Just curious, in a broad sense, what's the difference between CJam and GolfScript, and why does your code work? – Pavel – 2016-11-08T20:54:24.313

CJam was heavily inspired by GolfScript and is mostly backwards compatible. One big difference is that GolfScript, by default, appends a linefeed to the output, while CJam doesn't, which is what I'm exploiting here. I'll add a detailed explanation asap. – Dennis – 2016-11-08T20:56:22.723

1"0$p"0$~a:n;. – jimmy23013 – 2016-11-10T18:34:07.800

@jimmy23013 Nice, thank you! I had toyed with a:n, but using p didn't occur to me. – Dennis – 2016-11-10T18:37:52.283

8

CJam / Fission, 22 bytes

"'!+OR'")5-"{'_'~}_~";

Try it in CJam. Try it in Fission.

In CJam, this prints the standard Fission quine:

'!+OR"

Try the Fission quine.

In Fission, this prints a "-less variant of the standard CJam quine:

{'_'~}_~

Try the CJam quine.

This also works for 22 bytes (printing the same quines):

"& *NQ!":)R"{'_'~}_~";

Explanation

In CJam:

"'!+OR'"    e# Push this string.
)           e# Pull off the last character.
5-          e# Subtract 5, turning ' into ".
"{'_'~}_~"  e# Push this string.
;           e# And discard it again.

So at the end of the program, the stack contains the string "'!+OR" and the character ", both of which are implicitly printed.

In Fission, program flow starts at the R with a right-going atom. '" just changes the atoms mass, ), 5 and - are ignored for various reasons. Then the atom enters print mode at the " and prints {'_'~}_~. ; destroys the atom and terminates the program.

Martin Ender

Posted 2016-11-08T04:34:17.283

Reputation: 184 808

4+1 for emoticon {'_'~} – betseg – 2016-11-08T14:26:39.153

5destroys the atom I'd rather not be anywhere near when that happens – Luis Mendo – 2016-11-08T16:20:36.403

6

Clojure / Common Lisp, 274 bytes

(defmacro t []"((fn [s] (print (list s (list (quote quote) s)))) (quote (fn [s] (print (list s (list (quote quote) s))))))")(if '()(print(let[s clojure.string/replace](.toUpperCase(s(s(s(s(s(t)"fn""lambda")"[s]""(s)")"(quote ""'")"e)""e")")))))""))))"))))(eval '(princ(t))))

Some spaces added for readability

(defmacro t []"((fn [s] (print (list s (list (quote quote) s))))
     (quote (fn [s] (print (list s (list (quote quote) s))))))")
(if '()(print(let[s clojure.string/replace](.toUpperCase
    (s(s(s(s(s(t)"fn""lambda")"[s]""(s)")"(quote ""'")"e)""e")")))))""))))"))))
    (eval '(princ(t))))

Basically defines a macro which returns a quine in Clojure. Clojure requires parameters for macro definition provided as vector ([]) whereas Common Lisp (thankfully) just ignores it. After that we differ 2 languages by evaluating '() which equals to nil and thus falsey in Common Lisp and is true in Clojure. Then we do string manipulations using Clojure which Common Lisp doesn't even try to evaluate as it goes in another if branch. Clojure on the other hand tries to check if another branch is at least correct before executing so had to use eval there to both be correct in Clojure and output correct string in Common Lisp.

Note: just returning two different string might probably be shorter but then it won't be different to a polyglot challenges about outputing different strings in different languages. ¯\_(ツ)_/¯

Clojure original source run: https://ideone.com/SiQhPf

Common Lisp original source run: https://ideone.com/huLcty

Clojure output : ((LAMBDA (S) (PRINT (LIST S (LIST 'QUOTE S)))) '(LAMBDA (S) (PRINT (LIST S (LIST 'QUOTE S)))))

Common Lisp output : ((fn [s] (print (list s (list (quote quote) s)))) (quote (fn [s] (print (list s (list (quote quote) s))))))

Clojure output run in Common Lisp: https://ideone.com/T1DF7H

Vice versa: https://ideone.com/Fezayq

cliffroot

Posted 2016-11-08T04:34:17.283

Reputation: 1 080

4

Jelly / GolfScript, 18 16 bytes

0000000: 3a 6e 22 ff cc cc 22 7d 7f fe 22 3a 6e 60 ff 3b  :n"..."}..":n`.;

Verification

Testing all involved programs with the exact byte streams can only be done locally.

$ LANG=en_US # Latin-1. Jelly doesn't care about the exact encoding,
$            # as longs as it's not UTF-8.
$
$ xxd -g 1 mpquine
0000000: 3a 6e 22 ff cc cc 22 7d 7f fe 22 3a 6e 60 ff 3b  :n"..."}..":n`.;
$
$ jelly f mpquine | tee quine.gs | xxd -g 1
0000000: 22 3a 6e 60 22 3a 6e 60                          ":n`":n`
$ golfscript quine.gs | xxd -g 1
0000000: 22 3a 6e 60 22 3a 6e 60                          ":n`":n`
$ jelly f quine.gs 2> /dev/null | xxd -g 1
$
$ golfscript mpquine | tee quine.jelly | xxd -g 1
0000000: ff cc cc                                         ...
$ jelly f quine.jelly | xxd -g 1
0000000: ff cc cc                                         ...
$ golfscript quine.jelly | xxd -g 1
0000000: 0a

Jelly

With Jelly's code page, the program looks as follows.

:n"”ṘṘ"}
“":n`”;

This prints (Try it online!)

":n`":n`

which is a quine in GolfScript (Try it online!), but a parser error in Jelly (Try it online!).

GolfScript

In Latin-1, the program looks as follows, with an unprintable DEL character between } and þ.

:n"ÿÌÌ"} þ":n`ÿ;

This prints (Try it online!)

ÿÌÌ

or, visualized with Jelly's code page,

”ṘṘ

which is a quine in Jelly (Try it online!), but only prints a linefeed in GolfScript (Try it online!).

Dennis

Posted 2016-11-08T04:34:17.283

Reputation: 196 637

1Good old ”ṘṘ, thus ØV should be gone, right? – Erik the Outgolfer – 2016-11-13T11:37:57.147

3

JavaScript / C 278 bytes

At a staggering 278 bytes:

//\
console.log('int main(){char*A="int main(){char*A=%c%s%c;printf(A,34,A,34);}";printf(A,34,A,34);}');/*
int main(){puts("A='A=;B=String.fromCharCode(39);console.log(A.slice(0,2)+B+A+B+A.slice(2));';B=String.fromCharCode(39);console.log(A.slice(0,2)+B+A+B+A.slice(2));");}//*/

The C quine:

int main(){char*A="int main(){char*A=%c%s%c;printf(A,34,A,34);}";printf(A,34,A,34);}

The JavaScript quine:

A='A=;B=String.fromCharCode(39);console.log(A.slice(0,2)+B+A+B+A.slice(2));';B=String.fromCharCode(39);console.log(A.slice(0,2)+B+A+B+A.slice(2));

user61383

Posted 2016-11-08T04:34:17.283

Reputation:

Holy mother of quines... – MD XF – 2017-05-26T04:20:02.133

3

Befunge / Fission, 35 bytes

"$TQ-#'">,#-:#2_@;"+1_@#`+66:,g0:"L

Try it in Befunge | Try it in Fission

In Befunge this produces the Fission quine:

'!+OR"

In Fission this produces the Befunge quine:

:0g,:66+`#@_1+

James Holderness

Posted 2016-11-08T04:34:17.283

Reputation: 8 298

1

Python 3 / Python 2, 62 bytes

_='_=%r;print(_%%_['+'~'*-~int(-1/2)+'int(-1/2):])';print(_%_)

Try it in Python 2, Python 3.

Based on the Python quine here. The distinguishing factor between the two versions is what they do with int(-1/2): in Python 2, / is integer division (rounding down), with a result of -1; in Python 3, / is floating point division (-0.5), which int truncates to 0.

We build a string _ in three parts. '_=%r;print(_%%_[' and 'int(-1/2):])' are always the same. The interesting part is '~'*-~int(-1/2):

  • In Python 2, -~int(-1/2) is 0, and the tilde is not added to the string;
  • In Python 3, -~int(-1/2) is 1, and the tilde is added to the string.

Thus, Python 2 outputs the Python 3 quine

_='_=%r;print(_%%_[int(-1/2):])';print(_%_[int(-1/2):])

and Python 3 outputs the Python 2 quine

_='_=%r;print(_%%_[~int(-1/2):])';print(_%_[~int(-1/2):])

In each version, the expression inside [ :] evaluates to 0, which makes the slice include the entire string, whereas in the wrong language it evaluates to -1, which makes the slice include only the last character, truncating the output so it's not a full quine.

DLosc

Posted 2016-11-08T04:34:17.283

Reputation: 21 213

1

Brain-Flak, brainfuck 4617 4009 bytes

((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((()()()())))()())[()()])))()()())[()()])))())[()])[()()()()])))))))))))))))))))))))))))))))))))))))))))()()())()())[()()()()])()()())[()()])()())[()()()()])()()()))()()())[()()])[()()()()])))))))))))))))))))()())))()()())[()()()()])()()()()())[()()]))()())[()()()])()())[()()])))()()())[()()])))())[()()])[()()()])))))))))))))))))))))))))))))))))))))))))))()()()())[()()()])()()()())[()()])[()()()]))()()()())[()()()])()()()())[()()])[()()()])()()()())[()()()])()()()())[()()])[()()()]))))))))))))))()()()())[()()()])()()()())[()()])[()()()]))()()()())[()()()])()()()())[()()])[()()()])))))))))))))))))))))))))))))()()()())[()()()])()()()())[()()])[()()()]))()()()())[()()()])()()()()()))))))[()()()])[()])()()))))()()){({}<>)<>}<>([]){({}[()]<(({}[()]<((((((()()()){}())){}{}){}())<>)>)<>){({}[()]<({}()())>){({}[()]<({}())>){({}[()]<({}((()()()){}()){})>){({}[()]<({}()())>){({}[()]<({}(((()()()){}()){}){}())>){(<{}({}()())>)}}}}}}{}([]<({}<{({}<>)<>}<>>)>){({}[()]<({}<>)<>>)}{}{({}[()]<(({}))>)}{}(((({})(((()()())){}{}){}())))<>>)}{}{<>({}<>)}{+++++++>>>+>>>+++++++>>>++++++++>>>+++>>>++++>>>++>>>+++>>>++++>>>++++++++>>>+++>>>++++>>>+>>>+++++>>>++++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>+>>>++>>>+>>>++>>>+>>>++>>>+>>>++>>>+>>>++>>>++>>>+++++++>>>++++++++>>>++>>>+++++++>>>++++++++>>>++>>>+++++++>>>++++++++>>>++>>>+++>>>++++>>>++>>>++>>>+>>>++>>>++>>>++>>>++++>>>++>>>+++>>>++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+>>>++>>>++>>>++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+>>>+>>>+>>>+>>>++>>>+>>>++>>>+>>>++>>>++>>>++>>>+++++++>>>++++++++>>>+++++++>>>++++++++>>>++>>>+++++++>>>++++++++>>>+>>>++>>>++>>>++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+>>>++>>>+>>>++>>>++>>>++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+>>>+>>>+>>>+>>>++>>>+>>>++>>>+>>>++>>>++>>>+++++++>>>++++++++>>>+>>>++>>>++>>>+++++++>>>++++++++>>>++>>>+++++++>>>++++++++>>>+>>>++>>>++>>>++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+>>>++>>>+>>>++>>>++>>>++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+>>>+>>>+>>>+>>>++>>>+>>>++>>>+>>>++>>>+>>>++>>>+>>>++>>>++>>>++>>>+++++++>>>++++++++>>>+++++++>>>++++++++>>>++>>>+++++++>>>++++++++>>>++>>>++++>>>++>>>+++++++>>>+>>>+++>>>+++++++>>>++++++++>>>+>>>+++++++>>>++++++++>>>+>>>++>>>+>>>++>>>++>>>++++>>>++>>>++++++++>>>++++++++>>>++++++++>>>++++++++>>>++++++++>>>++++++++>>>++++++++>>>+++++++>>>++++++++>>>+>>>+++++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++>>>++++>>>++>>>+++>>>++++>>>++++++++>>>+++>>>++++>>>++++>>>++>>>++++>>>++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+++++++>>>++++++++>>>+++>>>++++>>>++>>>+++>>>++++>>>++++>>>++>>>++++++++>>>+++++++>>>++++++++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>+++>>>+>>>+>>>+>>>+++++++>>>++++++++>>>+++++>>>+>>>++>>>++++++>>>++>>>+>>>++>>>++>>>++>>>++++>>>++>>>++++++++>>>+++++++>>>++++++++>>>+++>>>++++>>>++++>>>++>>>++++++++>>>+++++++>>>++++++++>>>+++>>>++++>>>+++++++>>>+>>>+++++++>>>++++++++>>>+++>>>++++>>>++>>>+++>>>++++>>>++++++++>>>+++>>>++++>>><<<[<<<]>>>[>++++++++++++++++++++++++++++++++++++++++.<[->.+.->+<<]>+.[-]>>]<[<<<]>>>[<++++++++++++++++++++++++++++++++++++++++>-[<+>-[<+++++++++++++++++++>-[<++>-[<+++++++++++++++++++++++++++++>-[<++>-[<++++++++++++++++++++++++++++++>-[<++>-]]]]]]]<.>>>>]}{}

Try it online!

Try it online!

Explanation is on its way I am still golfing this

Post Rock Garf Hunter

Posted 2016-11-08T04:34:17.283

Reputation: 55 382

This generates a brainfuck quine in brainfuck, and a Brain-Flak quine in Brain-Flak. It should generate a brainfuck quine when run in Brain-Flak and a Brain-Flak quine when run in brainfuck. – Pavel – 2017-01-27T01:10:29.457

I will do it again. I am sorry I just have a hard time following the As and Bs – Post Rock Garf Hunter – 2017-01-27T01:11:17.233

1

Python / Retina, 70 65 64 66 bytes

I used the same strategy I used in my previous Python / Retina polyglot.

#
print"\nS`((.+))"*2+"\n\n"
#?
#_='_=%r;%_\n';_
#?;
#;print _%
#

Try in Python | Try in Retina

# is a comment in Python, so it simply prints the Retina quine in Python. In Retina, the first stage (2 lines) does nothing, because no # will be found in the input. The next stage replaces nothing with the basis of the Python quine. The third stage replaces each semicolon with the #print _% piece. The last stage removes all #'s.


Quine in Retina:


S`((.+))
S`((.+))


Quine in Python:

_='_=%r;print _%%_\n';print _%_

The quines used may be seen in this challenge. The Retina quine is an error in Python, and the Python quine has no output in Retina.

mbomb007

Posted 2016-11-08T04:34:17.283

Reputation: 21 944

Can you add an explanation to your answer for how the metaquine works? – Pavel – 2016-11-10T23:59:04.693

@Pavel Added it. – mbomb007 – 2016-11-11T03:58:49.940