18
\$\begingroup\$

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.

\$\endgroup\$
8
  • \$\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\$ May 20 at 8:19
  • \$\begingroup\$ @NickKennedy No. Will add \$\endgroup\$
    – emanresu A
    May 20 at 8:42
  • \$\begingroup\$ This ruins my answer though. I did spend time on it. Oh well \$\endgroup\$ May 20 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
    May 20 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\$ May 20 at 8:54

10 Answers 10

17
\$\begingroup\$

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)'

Try it online!

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
\$\endgroup\$
5
  • \$\begingroup\$ Nice job! Beating tsh's 10-flavors-of-js by 1 byte! \$\endgroup\$
    – emanresu A
    May 20 at 11:09
  • \$\begingroup\$ I would assume to work a:x=0 (where x is 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
    May 20 at 11:47
  • 1
    \$\begingroup\$ @ovs postponed annotation evaluation requires a __future__ import before 3.10, so it wouldn't save any bytes. \$\endgroup\$ May 21 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
    May 21 at 13:11
  • \$\begingroup\$ Technically from typing import*;IO would work for 3.11 (relevant commit), but since the first alpha version is still in development, this doesn't feel quite right. \$\endgroup\$
    – ovs
    May 22 at 9:06
16
\$\begingroup\$

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"@
# <#/.
#-10\8
"
> 0.0
> 7
> 6
>> Output 2
x::=~5
::=
x
";
$-|'main';print (4)&&3
#\-[2]o]<-[<-]>[+.>]1

Explanations coming soon...

\$\endgroup\$
11
9
\$\begingroup\$

Jelly => py 2, py 3, Jelly, Vyxal, Brain-Flak: 2.28

“1or"”©Ɠ“,Q"
”“£Ỵġcȯ9VĊƤ¿»⁶¹;¹⁾or⁶¹;⁸⁾)
®“(1)”Ɠẋ@Ø(j“"
”⁵

Try it online!

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.

\$\endgroup\$
0
9
\$\begingroup\$

Vyxal , => Grok, 05AB1E, brainfuck, Vyxal, tcsh, ;#, Vim, Jelly - .7778 .7755 .6719 46 bytes / 82 = .71875

\I?\Z?\q\+?*‛. ?`,|echo `?\#\;?*`#dH`?\¶?

Try it Online!

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\$.

\$\endgroup\$
5
  • \$\begingroup\$ +1 because this is the first time I’ve ever seen brainfuck in a competitive answer \$\endgroup\$ May 20 at 18:09
  • \$\begingroup\$ Invalid, this outputs I1Z2q+++. 4,|echo 5 #dH6¶1 instead of the program you said it outputs. And your link is wrong. \$\endgroup\$
    – Makonede
    May 20 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\$ May 20 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
    May 20 at 20:15
  • \$\begingroup\$ I've edited your answer to include the actual unprintable characters. Also, nice job using ;# ;) \$\endgroup\$ May 23 at 16:22
7
\$\begingroup\$

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...

\$\endgroup\$
4
\$\begingroup\$

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.

Try it online!

Try All The Test Cases Online!

\$\endgroup\$
4
\$\begingroup\$

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);"

Try it online!

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 $n for 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 $n so 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. An eval is 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. The return keyword allows to have a return value for the eval call in PHP
  • $n.''-$n caused an arror in PHP 8, which cannot subtract strings anymore, and was replaced by $n.''&0 which is actually shorter
\$\endgroup\$
4
  • \$\begingroup\$ Why do I get a “Parse error: syntax error, unexpected '=>' (T_DOUBLE_ARROW) in […] on line 2”? \$\endgroup\$ May 22 at 16:01
  • \$\begingroup\$ @PierrePaquette in which language? \$\endgroup\$
    – Kaddath
    May 24 at 7:13
  • \$\begingroup\$ Sorry! In PHP 7. \$\endgroup\$ May 24 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
    May 25 at 9:50
2
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

Zsh => Zsh, Bash, Ruby, Python, 51 bytes, score 3.1875

<<Q
'\';print $1||echo $2 #'
0and p($4)or print($3)

Try it online!

  • <<Q essentially just prints the rest of the file, but $1 to $4 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", so echo 2 gets executed instead
    • In Zsh, print 1 just gets executed and doesn't fail
  • In Python and Ruby, 0and p(4)or print(3) is what gets executed
    • In Ruby, 0 is truthy, so p(4) gets executed
    • In Python, 0 is falsey, so print(3) gets executed
\$\endgroup\$
1
\$\begingroup\$

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])"

Try it online!

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.

\$\endgroup\$
2
  • \$\begingroup\$ using Julia is shorter: Try it online! \$\endgroup\$
    – MarcMush
    Jun 9 at 8:23
  • 1
    \$\begingroup\$ @MarcMush Thanks! It's been implemented. \$\endgroup\$ Jun 9 at 11:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.