A polyglot is a program that runs in several languages.
Your challenge is to:
Choose at least two languages (Different versions count as different languages)
Create a program or function that takes several positive integers (one for each language you chose) and returns a program that:
Is a valid program in all of those languages
When run in language A, outputs the first number; When run in language B, outputs the second number; etcetera. Exiting by error is allowed, as long as the generated program prints the number first
The generator does not need to be in one of your chosen languages.
You can assume the inputted numbers within your chosen languages' limits. For example, if BF is one of your languages, the number for BF will be at most 255.
UPDATE
Explicitly checking the version number or implementation of the language is forbidden. To differentiate, use differences in language features.
Scoring
Your score is [code length] / [number of languages]2.
Example:
Let's say you were using JS/Python 3, in a JS program:
(x,y)=>`1//1;'''
console.log(${x})
//''';print(${y})`
Your score would be \$\frac{53}{2^{2}}\$ = 13.25.
The lower your score, the better.
-
\$\begingroup\$ Is it permissible to check the version number directly within the code? If so, this seems open to abuse since many languages have a built-in to read the version number. \$\endgroup\$Nick Kennedy– Nick Kennedy2021年05月20日 08:19:21 +00:00Commented May 20, 2021 at 8:19
-
\$\begingroup\$ @NickKennedy No. Will add \$\endgroup\$emanresu A– emanresu A2021年05月20日 08:42:51 +00:00Commented May 20, 2021 at 8:42
-
\$\begingroup\$ This ruins my answer though. I did spend time on it. Oh well \$\endgroup\$Aykhan Hagverdili– Aykhan Hagverdili2021年05月20日 08:46:53 +00:00Commented May 20, 2021 at 8:46
-
\$\begingroup\$ @AyxanHaqverdili Sorry about that, you'll just have to find some features that differ between different versions of C++. You can probably throw C in there as well. \$\endgroup\$emanresu A– emanresu A2021年05月20日 08:48:20 +00:00Commented May 20, 2021 at 8:48
-
\$\begingroup\$ @Ausername I'll just delete the answer since the requirement is rather vague. The macro I used isn't the version, but rather a timestamp (of the standard revision). Also, could I use version macros for the compiler? Would each compiler version count as a different language? They have different "features", as you phrased it. idk. \$\endgroup\$Aykhan Hagverdili– Aykhan Hagverdili2021年05月20日 08:54:37 +00:00Commented May 20, 2021 at 8:54
12 Answers 12
Backhand, Turtlèd, Gol><>, ><>, Pushy, Wumpus, Fission, Beeswax, Emoji, Emotinomicon, AsciiDots, Cardinal, Befunge-93, Functoid, Alice, Befunge-98, Klein, PingPong, Whispers v1 and v2, Thue, Perl, Raku, Rail, Self-modifying Brainfuck
Score: (削除) 3.04 1.3 0.934 0.693 0.605 (削除ここまで) \${\frac{295}{25^2} = 0.472}\$
puts'#\ v/v"Z"rH"Z"y"#"Z"#>o<~"`Z"#!
# Z#ZOi@R"Z"Y#_`Z`;[💬Z💬➡😭Z😲😎⏪⏬⏩.-$_"Z"x%"Z"
[ #< >Ov"Z"0_F1"Z".# @#
#\ @=.}#"Z">
]; #@ >:#,##_@#1"Z"
#\"Z"@
# <#/.
#-10\Z
"
> 0.0
> Z
> Z
>> Output 2
x::=~Z
::=
x
";
$-|\'main\';print (Z)&&Z
#\-[Z]o]<-[<-]>[+.>]Z'.gsub(?Z){$*.pop}
Try it online! or Try them all at once!
My personal constraints were to only use languages where the number can be placed in without modification, which are represented by each of the Zs. Ruby is used just as a simple formatter to insert the numbers. A typical output using the numbers 1-25 looks like:
#\ v/v"25"rH"24"y"#"23"#>o<~"`22"#!
# 21#20Oi@R"19"Y#_`18`;[💬17💬➡😭16😲😎⏪⏬⏩.-$_"15"x%"14"
[ #< >Ov"13"0_F1"12".# @#
#\ @=.}#"11">
]; #@ >:#,##_@#1"10"
#\"9"@
# <#/.
#-108円
"
> 0.0
> 7
> 6
>> Output 2
x::=~5
::=
x
";
$-|'main';print (4)&&3
#\-[2]o]<-[<-]>[+.>]1
Explanations coming soon...
-
1\$\begingroup\$ If you use Jelly instead of Ruby, you can get the code down to 68 bytes: tio.run/##y0rNyan8//9Rw5xDCyMMDi17uLP14c4FIO7ikoc7Gw/… \$\endgroup\$Nick Kennedy– Nick Kennedy2021年05月20日 08:06:51 +00:00Commented May 20, 2021 at 8:06
-
\$\begingroup\$ Generator of the code from yours: tio.run/##y0rNyan8//9Rw9xD26wNLYwe7u45tOTQksqjkx/… \$\endgroup\$Nick Kennedy– Nick Kennedy2021年05月20日 08:08:02 +00:00Commented May 20, 2021 at 8:08
-
\$\begingroup\$ Actually 67 possible: tio.run/##y0rNyan8//9Rw5xDCyMMDi17uLP14c4FIO7ikoc7Gw/… \$\endgroup\$Nick Kennedy– Nick Kennedy2021年05月20日 08:15:25 +00:00Commented May 20, 2021 at 8:15
-
\$\begingroup\$ And here’s the polyglot generator generator: tio.run/##y0rNyan8//9Rw9xD26wNLYwe7u45tOTQksqjkx/… \$\endgroup\$Nick Kennedy– Nick Kennedy2021年05月20日 08:15:57 +00:00Commented May 20, 2021 at 8:15
-
2\$\begingroup\$ Now should handle any arbitrary Unicode: Try it online! (note link shortened with bitly because it’s too long now). This has been an interesting meta-challenge! \$\endgroup\$Nick Kennedy– Nick Kennedy2021年05月21日 14:05:31 +00:00Commented May 21, 2021 at 14:05
Python 3, 167 bytes, produces Python 3.0, 3.1, ..., 3.9, 3.10, \${167 \over 11^2}\approx1.38\$
thanks to SuperStormer for refreshing my memory, allowing to add 3.10.
lambda r:'try:exec("%s");o=%d\nexcept:0\n'*10%sum(zip("0;int.bit_length;callable;u'';import enum;b''%();f'';breakpoint;(a:=0);{}|{}".split(';'),r),())+'print(o)'
This works by trying to evaluate expressions code that rely on new language features and updating the output value if successful. By including more subversions, the score could probably be decreased by quite a bit.
| Version | Code | New Language feature |
|---|---|---|
| 3.1 | int.bit_length |
New builtin |
| 3.2 | callable |
New builtin |
| 3.3 | u'' |
Old syntax for unicode strings re-added from Python 2 |
| 3.4 | import enum |
New module called enum |
| 3.5 | b''%() |
String formatting with % for bytes objects |
| 3.6 | f'' |
f-strings |
| 3.7 | breakpoint |
New builtin function |
| 3.8 | (a:=0) |
Assignment expressions |
| 3.9 | {}|{} |
Dictionary union with | |
| 3.10 | a:x=0 |
postponed evaluation of annotations is now enabled by default |
-
\$\begingroup\$ Nice job! Beating tsh's 10-flavors-of-js by 1 byte! \$\endgroup\$emanresu A– emanresu A2021年05月20日 11:09:52 +00:00Commented May 20, 2021 at 11:09
-
\$\begingroup\$ I would assume to work
a:x=0(wherexis undefined) in Python 3.7 with Postponed Evaluation of Annotations, but I can only get this to run on my local 3.10 install. As I can't find any information on it in the changelog, I'll exclude this for now. \$\endgroup\$ovs– ovs2021年05月20日 11:47:54 +00:00Commented May 20, 2021 at 11:47 -
1\$\begingroup\$ @ovs postponed annotation evaluation requires a
__future__import before 3.10, so it wouldn't save any bytes. \$\endgroup\$SuperStormer– SuperStormer2021年05月21日 12:13:07 +00:00Commented May 21, 2021 at 12:13 -
\$\begingroup\$ @SuperStormer Now that you say I actually remember having used the exact
__future__import before. I'm going to use it to detect 3.10 now. \$\endgroup\$ovs– ovs2021年05月21日 13:11:40 +00:00Commented May 21, 2021 at 13:11 -
\$\begingroup\$ Technically
from typing import*;IOwould work for3.11(relevant commit), but since the first alpha version is still in development, this doesn't feel quite right. \$\endgroup\$ovs– ovs2021年05月22日 09:06:08 +00:00Commented May 22, 2021 at 9:06
Jelly => py 2, py 3, Jelly, Vyxal, Brain-Flak: 2.28
"1or""©Ɠ",Q"
""£Ỵġcȯ9VĊƤ¿»61;1)or61;8))
®"(1)"Ɠẋ@Ø(j""
"5
Explanation
Taking {α}, {β}, {γ} as command line arguments and {δ} and {ε} from STDIN:
1or"{δ},Q"
print(1/2and {α}or {β})
1or"((1)(1)...(1))"
{γ}
In Python 2, 1or"{δ},Q" is an expression and doesn't do anything. The second line prints the number. Since 1/2 is 0 in Python 2, 1/2and {α} yields 0, and or {β} makes that yield {β}. Finally, {γ} is an expression and does nothing.
In Python 3, the only difference with Python 2 is that 1/2 is 0.5, so 1/2and {α} yields {α}, and or {β} has no effect since the value is positive and therefore truthy.
In Jelly, each line is a link, and only the last link gets evaluated, so {γ} is returned and automatically outputted.
In Vyxal, 1 pushes 1, o pops a,b and pushes a.replace(b, "") which happens to not error here, r does a regex match if the arguments are strings, which also doesn't error, and " pairs the top to values, which also doesn't error. Here, Vyxal automatically supplying zeroes when the stack is too small is very convenient. Then, {δ} pushes {δ}, , prints it, and finally Q exits the program, and thus the rest of the code doesn't matter.
In Brain-Flak, only brackets matter. The () in the print function call don't matter. The main part is (()()...()) with {ε} ()s in between. This pushes {ε} to the stack which gets output. Nothing else is brackets so this is fine.
The 1or is needed otherwise Jelly complains that ", a quick, has no atoms to pop from the command stack, even though the link isn't called. Same goes for ', though Vyxal also has a meaning for that that wouldn't work with this idea.
The (1) is needed otherwise Jelly complains that ), which ends a chain and maps over it, has nothing to pop because ( seems to just yeet the whole chain. Thus, 1 satisfies Jelly.
Vyxal Ṫ, => Grok, 05AB1E, brainfuck, Vyxal, tcsh, ;#, Vim, Jelly - (削除) .7778 (削除ここまで) (削除) .7755 (削除ここまで) (削除) .6719 (削除ここまで) 46 bytes / 82 = .71875
\I?\Z?\q\+?*‛. ?`,|echo `?\#\;?*`#dH`?\¶?
Resulting programs: Grok, 05AB1E, brainfuck, Vyxal, tcsh, ;#, Vim, Jelly
In brainfuck and ;#, the output is a character, as allowed by this meta post.
Also, ;# only supports \7ドル\$-bit numbers, so any number higher than \127ドル\$ will be output modulo \127ドル\$.
-
\$\begingroup\$ +1 because this is the first time I’ve ever seen brainfuck in a competitive answer \$\endgroup\$Ekadh Singh– Ekadh Singh2021年05月20日 18:09:13 +00:00Commented May 20, 2021 at 18:09
-
\$\begingroup\$ Invalid, this outputs
I1Z2q+++. 4,|echo 5 #dH6¶1instead of the program you said it outputs. And your link is wrong. \$\endgroup\$Makonede– Makonede2021年05月20日 19:43:09 +00:00Commented May 20, 2021 at 19:43 -
\$\begingroup\$ @Makonede Fixed. Turns out the reason the program was wrong was because there were unprintables in the code. However, you were right about the link being wrong. \$\endgroup\$Aaroneous Miller– Aaroneous Miller2021年05月20日 20:09:47 +00:00Commented May 20, 2021 at 20:09
-
\$\begingroup\$ This has score 0.71875, as since neither of those unprintables are in Vyxal's codepage, this cannot be encoded in Vyxal's custom SBCS and must be encoded differently. The most efficient encoding here is good old UTF-8, so that makes your program 46 bytes. \$\endgroup\$Makonede– Makonede2021年05月20日 20:15:00 +00:00Commented May 20, 2021 at 20:15
-
\$\begingroup\$ I've edited your answer to include the actual unprintable characters. Also, nice job using
;#;) \$\endgroup\$2021年05月23日 16:22:11 +00:00Commented May 23, 2021 at 16:22
Not quite sure its correctness, since I don't have all environment installed to test this... So I would just mark this answer non-competitive unless someone may test its correctness
JavaScript (ES6) => ES3, AS, ES5, ES6, ES7, ES8, ES9, ES10, ES11, ES12, 166/102=1.66 (non-competitive)
a=>`function f(){return[${a}][[].removeAt?0:9-![].map-![].fill-![].includes-!''.padEnd-!(this.Promise||f).prototype['finally']-![].flat-!''.matchAll-!''.replaceAll]}`
Input an array with 10 elements... Output is source of a function...
Js => Js, Python 3, Python 2, Deadfish~, Deadfish x, brainfuck - Score \$\frac{118}{36} = 3.278\$
I wanted to have a go too!
(x,y,z,d,X,b)=>`1//1;'''${'i'.repeat(d)}oh${'x'.repeat(X)}k
_=>${x}
//''';print(1/2and ${y}or ${z})#${'+'.repeat(b)}.
Ok, the generated code will look something like this, where {a} to {f} are the inputs:
1//1;'''{'i'*{d}}oh{'x'*{e}}k
_=>{a}
//''';print(1/2and {b}or {c})#{'+'*{f}}.
And let's pick it apart.
1//1;'''{'i'*{d}}oh{'x'*{e}}k
_=>{a}
//''';print(1/2and {b}or {c})#{'+'*{f}}.
This is the standard JS/Python polyglot structure. Everything except the _=>{a} and the 1 at the top (which is a NOP anyway) are ignored.
1//1;'''{'i'*{d}}oh{'x'*{e}}k
_=>{a}
//''';print(1/2and {b}or {c})#{'+'*{f}}.
In Python, // is an operator, so we can just add a NOP expression, followed by a multiline string so all the JS stuff is ignored. The difference is (copied from hyper) that 1/2 in python 2 is 0, but in Python 3 it is 0.5, which is truthy.
In Deadfish~, the only bit that matters is the is at the start, followed by oh. i increments the accumulator, o prints it and h halts the program.
Deadfish X is basically the same, but with x and k, and no halt. Fortunately, it's not like any ks are going to show up in the rest of the program, so we should be safe.
Finally, for brainfuck, there's a string of plusses appended to the end, along with a . to print. This outputs by charcode, because numbers are a pain.
PHP => MY-BASIC, PHP 7, PHP 5, PHP 8, Perl 4, Perl 5, : 111 bytes
Score: 111 / 36 = 3.08
fn($a,$b,$c,$d,$e,$f)=>"\$n.=\"$a\";
print \$n.''&0+true?0==''?eval('return 1<=>2;')?$b:$c:$d:(-1**2+1?$e:$f);"
Code generated with 1, 2, 3, 4, 5, 6:
$n.="1";
print $n.''&0+true?0==''?eval('return 1<=>2;')?2:3:4:(-1**2+1?5:6);
Relies on my usual trick, true added to a numeric value is 1 in PHP but is ignored by perl. And in Perl 4, negation operator - takes precedence over exponentiation ** while in Perl 5 it is the contrary.
Quick answer, I'll try to add languages or shorten the generator later..
EDIT: -1 byte, the last ; is not necessary for an arrow function definition, it belongs to the assignment to the header's variable (moved to footer)
EDIT 2: -1 byte by removing the round brackets for print and using a space, works in both languages
EDIT 3: added MY-BASIC language using these tricks:
.seems to be a valid character for variables names in MY-BASIC, while it's the concatenation operator in PHP and Perl. Allows at the same time to declare a value for$n.in MY-BASIC and$nfor the others (by concatenation to the undefined var). Double quotes are needed here because of the next point.'is the single line comment in MY-BASIC, so the rest of the line is ignored after the var output- for the other languages, it concatenates an empty string and then we remove the value of
$nso that the value is zero like before the edit (thank you, loose types languages!)
EDIT 4: taking in account the inputs are positive integers, I removed the single quotes for PHP and Perl
EDIT 5: added distinction between PHP 5, 7 and 8:
0==''was true before PHP 8- the spaceship operator
<=>didn't exist before PHP 7. Anevalis needed here, not only for PHP 5 not to throw a parse error, but for Perl versions also, where you can eval any incorrect code without errors. Thereturnkeyword allows to have a return value for theevalcall in PHP $n.''-$ncaused an arror in PHP 8, which cannot subtract strings anymore, and was replaced by$n.''&0which is actually shorter
-
\$\begingroup\$ Why do I get a "Parse error: syntax error, unexpected '=>' (T_DOUBLE_ARROW) in [...] on line 2"? \$\endgroup\$Pierre Paquette– Pierre Paquette2021年05月22日 16:01:40 +00:00Commented May 22, 2021 at 16:01
-
\$\begingroup\$ @PierrePaquette in which language? \$\endgroup\$Kaddath– Kaddath2021年05月24日 07:13:04 +00:00Commented May 24, 2021 at 7:13
-
\$\begingroup\$ Sorry! In PHP 7. \$\endgroup\$Pierre Paquette– Pierre Paquette2021年05月24日 20:33:13 +00:00Commented May 24, 2021 at 20:33
-
\$\begingroup\$ @PierrePaquette you mean the generator or the generated code? In TIO the PHP version is 7.4 and it works, I've tried on my local server too.. note that the code may output notices, or even errors from the eval'ed code, but it doesn't stop the execution and you should have the final result \$\endgroup\$Kaddath– Kaddath2021年05月25日 09:50:36 +00:00Commented May 25, 2021 at 9:50
Retina, 28 bytes, produces Retina or Retina 0.8.2, score 7
^
¶
,
$*_
$
$$$*1¶\d+\$*.¶¶.
Try it online! Explanation: For an example input of 3,4 the following program is produced:
3*_4$*1
\d+\*.
.
The first stage operates differently in the two versions. In Retina, * is the repetition operator while $* is a quoted *, while in Retina 0.8.2, * is a literal and $* is the repetition operator. The result in Retina is therefore ___4*1 while in Retina 0.8.2 it is 3*_1111.
The second stage simply deletes the *, the preceding number, and the following character.
The final stage counts the number of characters remaining, which gives the desired result.
Zsh => Zsh, Bash, Ruby, Python, 51 bytes, score 3.1875
<<Q
'\';print 1ドル||echo 2ドル #'
0and p(4ドル)or print(3ドル)
<<Qessentially just prints the rest of the file, but1ドルto4ドルare replaced by the input values.
The generated polyglot looks like:
'\';print 1||echo 2 #'
0and p(4)or print(3)
- In Zsh and Bash, backslashes don't work in single-quotes, so what gets executed is
print 1||echo 2:- In Bash, there is no
print, so the command fails.||means "if this command failed, then execute the following one", soecho 2gets executed instead - In Zsh,
print 1just gets executed and doesn't fail
- In Bash, there is no
- In Python and Ruby,
0and p(4)or print(3)is what gets executed- In Ruby,
0is truthy, sop(4)gets executed - In Python,
0is falsey, soprint(3)gets executed
- In Ruby,
(削除) Python 3 (削除ここまで) Julia 1.0 => Julia 1.0 and Python 3, (削除) 32 (削除ここまで) 23 bytes, score (削除) 8 (削除ここまで) 5.75
Solution by MarcMush using Julia's custom syntax:
a$b="print([$a,$b][1])"
My previous score 8 solution:
f=lambda*a:"print([%s,%s][1])"%a
Try it online! Julia uses 1-based indexes and Python uses 0.
-
\$\begingroup\$ using Julia is shorter: Try it online! \$\endgroup\$MarcMush– MarcMush2021年06月09日 08:23:55 +00:00Commented Jun 9, 2021 at 8:23
-
1\$\begingroup\$ @MarcMush Thanks! It's been implemented. \$\endgroup\$KinuTheDragon– KinuTheDragon2021年06月09日 11:25:22 +00:00Commented Jun 9, 2021 at 11:25
JavaScript => JavaScript (V8), Python 3, Python 2, Foo - (削除) 57 (削除ここまで) 56 bytes, (削除) 3 (削除ここまで) 4 languages = 3.5
Thanks to The Thonnu for -1 byte!
(x,y,z,w)=>`print( ${x}//${x/y}if 1/2else ${z}#"${w}"
)`
Examples for the numbers 1, 2, 3, and 4:
print( 1//0.5if 1/2else 3#"4"
)
-
1\$\begingroup\$ Replacing
\nwith an actual newline also works and reduces the byte count by one \$\endgroup\$The Thonnu– The Thonnu2023年04月06日 15:49:54 +00:00Commented Apr 6, 2023 at 15:49 -
1\$\begingroup\$ @TheThonnu Thank you - did that along with adding Foo. \$\endgroup\$Creative Name– Creative Name2023年04月06日 15:55:25 +00:00Commented Apr 6, 2023 at 15:55
-
1\$\begingroup\$ Nice. You might also want to add TIO links for all languages: 1 2 3 4 \$\endgroup\$The Thonnu– The Thonnu2023年04月06日 16:05:23 +00:00Commented Apr 6, 2023 at 16:05
-
1\$\begingroup\$ @TheThonnu That's a good idea, added the links. \$\endgroup\$Creative Name– Creative Name2023年04月06日 16:13:17 +00:00Commented Apr 6, 2023 at 16:13
Python 3 => Python 3, Python 2, Befunge-93; 67 bytes => \$\frac{67}{3^2}\$=7,4444444444...
lambda x,y,z:f'\'v\';print(1/2 and {x} or {y})\n#<v"{z}"\n# >:#,_@'
Upon giving input to the function above (12, 34 and 56 used as an example), we will get something like the following:
'v';print(1/2 and 12 or 34)
#<v"56"
# >:#,_@
First off is Python 3. It ignores the string at the start, then because 1/2 results in 0.5, 1/2 and 12 will output 12, and orring with 34 still results in 12 so it gets printed. The rest of the lines are comments.
Then is Python 2, in which the only thing that changes is that 1/2 evaluates into 0, so 0 and 12 results in 0 and orring with 34 results in 34, which gets printed.
Then is Befunge-93, where it takes the v (single quotes are not an instruction, only double quotes are) and then the <, which leads to push mode-ing 65 and then a simple printing loop which leads into @ and ends the program.
Explore related questions
See similar questions with these tags.