24
\$\begingroup\$

Inspired by this question on SO, your task is to produce a program that is valid in (at least) two major versions of your chosen language that produce different output.

Rules

  • Any language that has more than one major version can be used.
    • For the purposes of this challenge, I would suggest a "major version" is where the first number in the version number changes.
      • PHP 4 and PHP 5 are different, PHP 5.3 and PHP 5.4 are not.
    • However, since I don't know the versioning scheme for all languages, if you can argue your case well enough, I'm sure the community will determine if you have been fair in determining "major version" yourself.
  • The code must be compiled and run with the same flags and input each time
    • Except to change the version of the language if this is pertinent
  • Errors don't count as output and answers that produce errors are disqualified (rather than error output is just ignored)
  • The program should take no input other than that required to make it run.
  • For each given version, the output should always be the same
  • The intention is that the change should be a consequence of a change in the language spec rather than the VM spec or environmental metadata

Scoring

  • type scoring for length, so +1 for each char/byte
  • -1 for each character difference in the length of the output.
    • e.g. Version 1 outputs abcde (5 characters), Version 2 outputs 123abc (6 characters) = -1

Other Rules

  • Standard exceptions apply - no external programs,web requests etc.
  • Your program should terminate (within 2 seconds)
  • Lowest score wins.

"Better" Scoring

Keep your original answers, in the interest of fairness, I'll mark the winner based on the original rules.

Since my original scoring is fundamentally broken, why not re-score / retry with the following scoring system:

  • type scoring for length, so +1 for each char/byte
  • +1 for each character difference in length of output
    • abcde and 123456 -> +1
  • -1 for each unique character difference in the output (capped to length of shortest output)
    • abcde and 123456 -> -5
    • 12345 and 123456 -> -1
    • 12345 and 123455 -> 0
  • Scores closest to zero win
  • In the event of a second tie break, simple score wins.
\$\endgroup\$
8
  • \$\begingroup\$ Note: in Ruby, the first number is the epoch, it signifies major events in Ruby's history, not a version number (0->1 was the initial release, 1->2 was Ruby's 20th birthday). The major number is the second number. So, Ruby 1.8->1.9 would be crossing a major release. \$\endgroup\$ Apr 16, 2014 at 12:43
  • 1
    \$\begingroup\$ I think the new scoring is too different from the original, it's practically a new question \$\endgroup\$
    – Tal
    Apr 16, 2014 at 14:14
  • \$\begingroup\$ I'd say the PHP example is arguable, 5.4 has quite a few basic features that would break on 5.3 (traits, []arrays, array dereferencing). It was going to be PHP6, but then decided to save the 6 to something more radical as unicode strings by default IIRC \$\endgroup\$
    – Einacio
    Apr 16, 2014 at 15:24
  • 2
    \$\begingroup\$ What is the unique character difference? If I output zzzz and aaaa, does that give me -4? That's what it seems like to me. \$\endgroup\$
    – Justin
    Apr 16, 2014 at 17:29
  • 1
    \$\begingroup\$ So, assuming that the program can detect in which version it runs, the winner is who can output the most characters in two seconds? I think this question would be better as a popularity-contest to encourage people to find interesting and subtle language bugs. \$\endgroup\$
    – Cephalopod
    Apr 17, 2014 at 9:03

27 Answers 27

39
\$\begingroup\$

Revised answer for "better" scoring system

C89 / C99, Score: 0

My program is 52 characters long and uses the same mechanism as in my original answer to achieve the different output. This works because C89 doesnt treat // as a comment:

i=32;main(){putchar(i+++0//**/
+52)&&i<84&&main();}

The results:

$ ./diff2c89
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRS
$ ./diff2c99
TUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂Çüéâäàåç
$ ./diff2c99 | wc
      0       1      52
$ ./diff2c89 | wc
      0       1      52
$ wc diff2.c
      1       2      52 diff2.c

Old answer:

C89 / C99, Score: -Infinity?

I'm not entirely sure if this program doesn't break the rules, but never mind. This program exploits the fact that in C89 // is not a valid comment but /* ... */ is.

Using the comment trick an other function is executed. In C89 the function just prints "trolololol..." until the stack overflows (so it might finish within 2 seconds).

f1(){printf("ol");f1();}
f2(){printf("oll");}
main(){
    printf("tr");
    void (*f[])() = {f1,f2};
    f[0 //* trollololol */
      +1]();
}

C99

$ ./diffc99
troll

C89

$ ./diffc89
trolololololololololololololololololololololololololololololololololololololololololo
lolololololololololololololololololololololololololololololololololololololololololol
ololololololololololololololololololololololololol ....
\$\endgroup\$
3
  • 1
    \$\begingroup\$ I'm not sure either whether it's against the rules, but I like it :) \$\endgroup\$
    – Tal
    Apr 16, 2014 at 12:33
  • 9
    \$\begingroup\$ According to the "better rules", Scores closest to zero win so this is actually very far from zero. \$\endgroup\$
    – user80551
    Apr 16, 2014 at 18:02
  • 1
    \$\begingroup\$ Indexing an array of function pointers by either division or addition depending on the C standard's definition of comments... beautiful. \$\endgroup\$
    – Desty
    Apr 17, 2014 at 10:46
16
\$\begingroup\$

Python - 10 points less than the next best answer

print(range(100))

In Python 2, this will print the entire list of integers from 0 to 99.

In Python 3, range is a generator and so it will print only "range(0,100)".

Seeing as I've never run into a size limit on numbers in Python, I can replace that 100 with a much bigger number (2**1000, for example) and end up with a virtually infinite difference in the output.

Edited to reflect the fact that, while I can get a score that is infinitely low for any practical purpose, I cannot reach actual infinity with a program that terminates under 2 seconds

For the updated tie-breaker scoring system, I'd submit:

print(range(4))

Output:

Python 2: [0, 1, 2, 3]

Python 3: range(0, 4)

The first print has 5 unique characters ([123]), the second print has 8 unique characters (range(4)), the difference in length of output is 1, the code has 15 characters, the shortest output is 11 characters... these rules are pretty confusing but I think this brings me to a final score of 15+1-min(11,5+8) = 5.

\$\endgroup\$
11
  • \$\begingroup\$ However, "your program should terminate", even on a very (finitely) fast machine, your "much bigger" (finite) number is still nowhere near -∞ so I dispute your score (give or take ;] ) \$\endgroup\$ Apr 16, 2014 at 10:31
  • \$\begingroup\$ @JamesWebster Thank you for bringing this terrible technical mistake to my attention, I have edited my answer accordingly ;) \$\endgroup\$
    – Tal
    Apr 16, 2014 at 10:36
  • \$\begingroup\$ Other similar answers will surely come. I guess that scoring for these answers should be calculated on how fast they get to infinity. \$\endgroup\$
    – Vereos
    Apr 16, 2014 at 10:38
  • \$\begingroup\$ @Vereos I'd hope that, if other answers of this sort show up, the question will be edited with additional scoring details. \$\endgroup\$
    – Tal
    Apr 16, 2014 at 10:44
  • 1
    \$\begingroup\$ @Tal I think everyone who reads the scoring rules will make up a solution that can produce negative scores, only limited by the language or hardware, before having read any answer to the problem ;) The scoring is just broken by design... \$\endgroup\$
    – foobar
    Apr 16, 2014 at 13:09
13
\$\begingroup\$

C#

I also changed the generic method type inference algorithms between C# 2, 3 and 4. For example:

using System;
class C
{
  static int M<T>(T x, T y) { return 1; }
  static int M(object x, object y) { return 2; }
  static void Main() 
  {
    Console.WriteLine(M(1, new int?()));
  }
}

In C# 2 method type inference says that T cannot be both int and int?, and so produces 2. In C# 3 method type inference says "the best compromise between int and int? is int?" and so chooses M<int?> and produces 1.

\$\endgroup\$
1
  • 12
    \$\begingroup\$ > I also changed What do you mean you changed the... oh. OH. \$\endgroup\$
    – Bob
    Apr 20, 2014 at 6:00
13
\$\begingroup\$

Python - 0 points

No idea how this one works :P Just stumbled upon it while trying out random code.

int

On Python 3, it's <class 'int'> and on Python 2, it's <type 'int'> (using interative console)
"Better" Score: 3 (length) + 1 (char diff.) - 4 (unique chars)

Older Python 1 - 7 points

print()

Big thanks to @grc for this version and helping me subtract four points !

In Python 2, this statement is interpreted as print () which prints the empty tuple ().
In Python 3, the print is a function and results in nothing being printed.
"Better" Score: 7 (length) + 2 (char diff.) - 2 (unique chars)

Older Python 2 - 13 points:

print(1,2)

"Better" Score: 12 (length) + 2 (char diff. o/p) - 1 (unique chars o/p)

I know this isn't going to win but still gave an answer, as this is my first Python try :)

\$\endgroup\$
2
  • \$\begingroup\$ I think this could be shortened to print(). \$\endgroup\$
    – grc
    Apr 16, 2014 at 12:39
  • \$\begingroup\$ @grc Thanks a lot for the advice ! Looking back at my compiler, I see that I had tried it, but was so lost in the docs, that I deleted it to try dict.itertools() :P \$\endgroup\$ Apr 16, 2014 at 12:46
9
\$\begingroup\$

Ruby, 4 characters + 0 char length difference - 3 unique char difference = score of 1

p ?d

On Ruby 1.9, it will print "d". On 1.8, it prints 100.

Explanation: ?d is "d" in 1.9 and 100 (the ASCII code for d) in 1.8. p x is equivalent to puts x.inspect. * is both string repetition and multiplication.


"Optimized" version for old scoring:

Ruby, 8 characters - 999999989 chars difference = score of -999999981

p ?!*1e9

Prints 33000000000.0 for 1.8 and "!!!!!!...!!!" for 1.9. (?! is 33 in 1.8 and "!" in 1.9, and * is both string repetition and multiplication.)

Really, you could go as far as you wanted with the multiplication, it just depends on how fast your computer is.

\$\endgroup\$
2
  • \$\begingroup\$ Could you explain what exactly is happening in that second line? \$\endgroup\$
    – Tal
    Apr 16, 2014 at 13:22
  • \$\begingroup\$ @Tal Okay, edited \$\endgroup\$
    – Doorknob
    Apr 16, 2014 at 13:28
8
\$\begingroup\$

Bash — -∞ (up to practical limits)

Effectively, however much memory you have. E.g. with about 10GB:

echo {0..999999999}

Bash 2: doesn't support ranges in brace expansion, so prints {0..999999999}.

Bash 3:


Any language — -∞ (up to practical limits)

You'll have this in pretty much any language, even if it ends up being a little more complex. As soon as you can make two different values, you can write code that produces arbitrarily different output. A better scoring method would ignore the differences in the output.

version = … # some arbitrarily weird stuff
if version = 2:
    while not timed_out():
        print "version2"
\$\endgroup\$
1
  • \$\begingroup\$ @foobar The in the “any language” version stands for whatever tricks you use to make your program depend on achange in the language spec. It is version detection, whether you do if $version >= 3 or if isinstance(range(0),list). \$\endgroup\$ Apr 16, 2014 at 13:02
4
\$\begingroup\$

Python, -14 Points ( 3 - 17 char length difference = -14)

2/3

Python 2 outputs: 0

Python 3 outputs: 0.6666666666666666

Better Scoring version, 5 points (3 + 2 char length difference = 5)

3/2

Python 2 outputs: 1

Python 3 outputs: 1.5

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

C#

I added covariance and contravariance to C# 4, so programs of the form:

using System;
using System.Collections.Generic;
class C
{
  static void Main() 
  {
    Console.WriteLine((new List<string>()) is IEnumerable<object>);
  }
}

Would produce false in C# 2 and 3 and true in C# 4.

However, one might argue that this does not count because the library containing the definition of IEnumerable<T> also had to change.

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

C#

Following code would produce the different output for C# 5.0 and previous versions of C#

using System;
using System.Collections.Generic;

namespace TestConsoleAppClosure
{
    class Program
    {
        static void Main(string[] args)
        {
            var actions = new List<Action>();
            List<int> list = new List<int> { 10, 20, 30, 40 };
            foreach (var item in list)
            {
                  actions.Add(() => Console.WriteLine(item));
            }
            foreach (var act in actions) act();
        }
    }
}

Output: C# 5.0

10
20
30
40

Output: C# 4.0

40
40
40
40

The reason is explained in this blog post by Eric Lippert: Closing over the loop variable considered harmful.

\$\endgroup\$
0
3
\$\begingroup\$

C++98/11 - "Better" Scoring (115 characters - 115 unique character differences in output = score of 0)

A slightly edited version to comply to the new scoring rules

Golfed:

#include<cstdio>
#define u8 "\x0B"
int main(){int i=116;char c[i];c[--i]=0;while(i-->0)c[i]=u8"\x7E"[0]+i;puts(c);}

Ungolfed version:

#include <cstdio>
#define u8 "\x0B"
int main() {
    int i = 116;
    char c[i];
    c[--i] = 0;

    while(i-- > 0)
        c[i] = u8"\x7E"[0] + i;

    puts(c);
}

The new solution doesn't differ much to the old one. In the new solution the output in both C++11 and C++98 is with 116 characters equally long, but the only character they have in common is the new line character appended by the puts function.

For C++98 the u8 in u8"\x7E"[0] will still be replaced, but now with "\x0B". So the resulting value after preprocessing will be "\x0B""\x7E"[0]. The two strings will be concatenated to "\x0B\x7E" and the subscript operator will access the first element, in this case the character with the value 11 in the character encoding. Additionally the value of i will be added, which intially is 114. So the character with the value 125 will be written to the resulting array. As i goes to zero all values from 125 to 11 will be written to the array and puts will print all characters with the values from 11 to 125, plus the trailing new line.

In C++11 u8"\x7E"[0] will be interpreted as an UTF-8 string consisting of the single character with the hexadecimal value 7E. The subscript operator will now access this character and the value of i is added to it, resulting in the decimal value 241 during the first iteration. While i goes to zero, all the values down to 126 will be written to the array and puts will print the characters with the values from 126 to 241, plus the trailing new line.

Depending on the used character set, this will produce different results, as most character sets only have the first 128 characters in common.

For ISO-8859-2 the output would be the following:

C++98: Output for C++98

C++11: Output for C++11

C++ (106 characters - 107 difference in output = score of -1) (OLD RULES)

Golfed:

#include<cstdio>
#define u8 "f"
int main(){int i=108;char c[i];c[--i]=0;while(i-->0)c[i]=u8""[0];puts(c);}

Ungolfed version:

#include <cstdio>
#define u8 "f"

int main() {
    int i = 108;
    char c[i];
    c[--i] = 0;

    while(i-- > 0)
            c[i] = u8""[0];

    puts(c);
}

Compiled with g++ -std=c++98 main.cpp and g++ -std=c++11 main.cpp.

Actually you can replace 108 with any positive number in integer range to achieve negative scores. As long as it's bigger than 108 ;)

In C++98 #define u8 "f" will cause the preprocessor to replace u8""[0] with "f"""[0]. This will result in "f"[0], which finally becomes the single character 'f', which is written to an array.

puts(c) will print the resulting array, consisting of i-1 'f'.

In C++11 u8""[0] will cause the empty string to be interpreted as an UTF-8 string, so no string concatenation is done. As this is a C-string, the subscript operator will access the terminating null-byte and write it to an array.

In the end puts(c) will print the resulting array, which consists only of null-bytes. But as puts stops reading the input as soon as it encounters a null-byte, it will only print a newline and nothing more.

\$\endgroup\$
8
  • \$\begingroup\$ I get your score to be 1. Both c++89 and c++11 output a ? (on my (Mac) system at least) \$\endgroup\$ Apr 16, 2014 at 16:55
  • \$\begingroup\$ Though I only count 115 characters in the solution. \$\endgroup\$ Apr 16, 2014 at 16:58
  • \$\begingroup\$ @James Webster true, wc -c lied to me ;) I'll append a newline to the end of my solution ;) ...Or just adjust it. \$\endgroup\$
    – foobar
    Apr 16, 2014 at 17:03
  • \$\begingroup\$ @James Webster I guess that you're using UTF-8 encoding in your terminal. As the most significant bit in a byte is reserved in UTF-8, it can't map the characters the program outputs in the range from 128 to 232. So you should see up to 104 '?' or less with binary trash in between. With WINDOWS-1256 encoding as an example, your terminal would display this for the C++11 version: tuvwxyz{|}~€پ‚ƒ„…†‡ˆ‰ٹ‹Œچژڈگ‘’“”•–—ک™ڑ›œ‌‍ں ،¢£¤¥¦§¨©ھ«¬­®¯°±²³´µ¶·¸¹؛»¼½¾؟ہءآأؤإئابةتثجحخدذرزسشصض×طظعغـفقكàلâمنهو \$\endgroup\$
    – foobar
    Apr 16, 2014 at 17:19
  • \$\begingroup\$ For the C++98 version it's possible that your terminal displays '?' for values below 32 as that are control characters. My terminal for example replaces most of them with a square and their hexadecimal value printed into it. Except for the new line and tab characters as examples. But now that I mention it myself. the C++98 version contains new line twice, but that's easy to fix ;) \$\endgroup\$
    – foobar
    Apr 16, 2014 at 17:24
2
\$\begingroup\$

CSS2 vs CSS3 48 points

<i style='font-feature-settings:"smcp" on;'>abcdefghijklmnopqrstuvwxyz</i>

Rendered as ABCDEFGHIJKLMNOPQRSTUVWXYZ (small caps) on CSS3 browsers

Rendered as abcdefghijklmnopqrstuvwxyz on non-CSS3 browsers

74 chars - 26 unique chars difference = 48

\$\endgroup\$
2
2
\$\begingroup\$

Python - 0

a='a=%r\ntry:print a%%a\nexcept:pass'
try:print a%a
except:pass

Python 2 prints a quine, while Python 3 prints nothing.

EDIT: Updated, fixed.

\$\endgroup\$
2
  • \$\begingroup\$ Can your computer really print ~9 billion digits in 2 seconds? \$\endgroup\$ Apr 21, 2014 at 8:19
  • \$\begingroup\$ @JamesWebster This is actually the return value of a function - thus, it only needs to exist in memory for the program to finish. It requires a /lot/ of RAM, but it would finish within 2 seconds on a well-specced computer. \$\endgroup\$
    – cjfaure
    Apr 21, 2014 at 9:10
1
\$\begingroup\$

Perl, 24 characters - (9*(10^9))-1 char difference = score of -((9*(10^9))-1)+24

print$]>=5?"a":"a"x9e9;

Prints 9e9-times a for all versions below 5, prints a for all versions above 5. You could make the score infinitely low by just adding more as to the second output.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ In the question: "The intention is that the change should be a consequence of a change in the language spec rather than the VM spec or environmental metadata" \$\endgroup\$
    – Doorknob
    Apr 16, 2014 at 12:11
  • \$\begingroup\$ I'm not using any VM spec or environmental metadata. Just the installed version. \$\endgroup\$
    – Vince
    Apr 16, 2014 at 12:35
1
\$\begingroup\$

Befunge, 36 - 378 = -342; 164 - 2576 = -2412

"v
"<v
" <v
"  <v
"   <v
 <v:,<
 ^_@

In Befunge 93, this would output 3 spaces, followed by <v, followed by 76 spaces, followed by <v, then 76 space, then <v, then 76 spaces, then <v followed by 77 spaces, then v followed by 78 spaces. Length: 3 + 2 + 76 + 2 + 76 + 2 + 76 + 2 + 77 + 1 + 78 = 395This is trivially extendable by adding extra lines similar to the first 5 lines.

In Befunge 98, this would output <v <v <v <v v.

The difference in length: 395 - 17 = 378. So the score would have been (by the old rules): -342

Note: I could have gotten an even bigger difference if I used . instead of ,; the difference would have been -684


Rule change:

This is a bit more tricky.

"  "-v>"Befunge 93 very long strings"v>"F"0g" "1-`!#v_   "F"0g1-"F"0pvz
     _^p0"F"-1g0"F"_v#    `-1" "g0"F"<^"j++a81zzzzzz]zzzzzzzzzzzzzzz"<
             _@#`0:,<

Befunge 93 output:

sgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeBsgnirts gnol yrev 39 egnufeB

Befunge 98 output:

j++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzzj++a81zzzzzz]zzzzzzzzzzzzzzz

Lengths: 2576. None of the characters between the strings are the same, so if I understood the challenge correctly, my score is 164 - 2576 = -2412 (yes I was supposed to aim for 0, but this was more fun). If I need to make it so that each character in each string are unique and different from each other, I can do so, please tell me.

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

Powershell, "Better" scoring, -163 (15 - 178 char diff = -163 )

$PSVersionTable

Powershell V2

Name                           Value                                                                   
----                           -----                                                                   
CLRVersion                     2.0.50727.5477                                                          
BuildVersion                   6.1.7601.17514                                                          
PSVersion                      2.0                                                                     
WSManStackVersion              2.0                                                                     
PSCompatibleVersions           {1.0, 2.0}                                                              
SerializationVersion           1.1.0.1                                                                 
PSRemotingProtocolVersion      2.1                                                                     

Powershell V3

Name                           Value                                                                   
----                           -----                                                                   
WSManStackVersion              3.0                                                                     
PSCompatibleVersions           {1.0, 2.0, 3.0}                                                         
SerializationVersion           1.1.0.1                                                                 
BuildVersion                   6.2.9200.16398                                                          
PSVersion                      3.0                                                                     
CLRVersion                     4.0.30319.1022                                                          
PSRemotingProtocolVersion      2.2 
\$\endgroup\$
1
\$\begingroup\$

PHP, Score: 0 (best case)

srand(2);echo rand();

Wow, this is going to be fun to explain.

According to this website, the srand() function appears to be broken from PHP 5.1.5 to PHP 5.3.14. Therefore, we are going to keep under consideration PHP 4.4.9 and one random version of PHP 5 that falls in the version interval specified above.

PHP 4.4.9 output: 1505335290

I don't think this is rule-breaking; Since this appears to be a bug, the output should be the same, but it's not. Our other PHP version will simply skip the srand() function and output a random number.

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

Java (around -2.000.000.000)

The Java versions are sometimes called 1.x, but I think it still is within the rules.

The easy way is to check whether a class exists that was introduced in a specific version.

try {
    Class.forName("java.lang.AutoCloseable");
    // Java 7 or later
    char[] text = new char[Integer.MAX_VALUE];
    Arrays.fill(text, 'a');
    System.out.println(new String(text));
} catch (Exception e) {
    // Java 6 or earlier
    System.out.println("-");
}

(Depends a bit on your terminal whether it is possible to output 2 billion characters in two seconds / For the new scoring, replace Integer.MAX_VALUE with the byte count of the program to achieve perfect zero score.)

This code depends on the version of the VM/JDK that is used (does that count?)

import java.lang.reflect.Field;
import java.util.Arrays;

{
    Field fValue = null;
    for (Field f: String.class.getDeclaredFields()) {
            if (f.getName().equals("value")) {
                    fValue = f;
            }
    }
    char[] text = new char[10];
    Arrays.fill(text, 'a');
    String s1 = new String(text);
    String s2 = s1.substring(1);
    fValue.setAccessible(true);
    text = (char[]) fValue.get(s2);
    Arrays.fill(text, 'z');
    System.out.println(s1);
}

It prints zs for Java 6 and earlier JDKs and as for recent versions.

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

JavaScript (ES3 vs ES5) - 9 points

length 10 + length difference 0 - output difference 1

[].map?1:0

Outputs 1 for modern browsers that support Array.prototype.map. Outputs 0 on older browsers. I tested this with IE8.

With old rules: 0 points

length 26 - length difference 26

Array([].map?27:0).join(0)

Outputs 00000000000000000000000000 on modern browsers. And empty string on old.

\$\endgroup\$
3
  • \$\begingroup\$ IE8 does really support ES4??? \$\endgroup\$
    – Bergi
    Apr 18, 2014 at 18:32
  • \$\begingroup\$ I rather was surprised how they did implement a non-existing standard \$\endgroup\$
    – Bergi
    Apr 18, 2014 at 18:40
  • \$\begingroup\$ Whoops! Fixed :) \$\endgroup\$
    – nderscore
    Apr 18, 2014 at 18:53
1
\$\begingroup\$

C++98/C++11

#include <iostream>

int main()
{
  for (long i = 0; i < __cplusplus; ++i)
     std::cout << "x";
}

For a standard conforming C++98 compiler, this outputs 199711 times the letter 'x', while for a standard conforming C++11 compiler, this outputs 201103 times the letter 'x'. The length difference of the output is therefore 1392 characters. This means that actually golfing the source code is not worthwhile, since a much larger effect can be achieved by just replacing "x" with a longer string, or by multiplying __cplusplus with some number.

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

TI-Basic 83 Plus vs. 84 Plus, score 5-1 = 4

length("setTime(

Outputs 2 on the TI-83 Plus, where the same program is parsed as something that looks like length("?►DMS because the setTime( command had not yet been introduced. So the string contains two 1-byte tokens, its length is 2.

Outputs 1 on the TI-84 Plus, because a string containing a single 2-byte token has length 1.

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

APL (5 - (1988894 - 1) = -1988888)

In old-style APLs (like Dyalog if ⎕ML=0*), means mix, which, on a 1-dimensional vector does nothing. In APL2-style APLs, like GNU APL, (or Dyalog if ⎕ML=3), means first, which takes the first item of a vector.

Thus, the following 5 bytes (the APL charset does fit in a byte),

↑⍳3e5

will output 1988894 bytes (the space separated list of numbers from 1 to 3e5) in old-style APL dialects,

and 1 byte (just the first number in said list, which is 1 and therefore of length 1), in APL2-style APL dialects.

Notes:

  • ⎕ML means migration level. In Dyalog APL, the higher you set ⎕ML, the more APL2-style features are enabled. It defaults to 0. (And it's a global variable! Fun!)
  • 3e5 was the highest 3-character value Dyalog APL would accept with . 4e5 gave me a LIMIT ERROR. This restriction is probably interpreter-dependent. (GNU APL had no trouble with higher values.)
\$\endgroup\$
0
\$\begingroup\$

Bash 7 (14 bytes program length + 0 difference in output length - 7 difference in unique chars in output)

Related to @Gilles answer, but a different expansion feature and different versions. Scoring according to the edited question:

echo {1..9..2}

Output for bash 3.x:

{1..9..2}

Output for bash 4.x:

1 3 5 7 9
\$\endgroup\$
0
\$\begingroup\$

PHP: −134217684 (43 - 134217727)

echo str_pad("",ip2long("")&0x7ffffff,"a");

Usage:

time php -r 'echo str_pad("",ip2long("")&0x7ffffff,"a");' > /tmp/test
1.61user 0.17system 0:01.79elapsed 99%CPU (0avgtext+0avgdata 142272maxresident)k
0inputs+0outputs (0major+35922minor)pagefaults 0swaps

In PHP5+ this will print nothing since ip2long with invalid argument turns into false which casts to zero. In PHP4 it ip2long("") returns -1 and we pad the empty string with 128MB og a.

The mask is fitted so that it returns long before the 2 seconds on my machine. If you can't make it in 2s buy better hardware!

With new rules: 0 (40 - 40. You can't get any closer to zero.)

echo str_pad("",40,chr(97+ip2long("")));

Outputs:

In PHP4: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
In PHP5: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
\$\endgroup\$
1
  • \$\begingroup\$ With the new scoring rules your score is 39. Both outputs are equally long, so no penalty for that. But there's only one unique character difference. a is not equal to b, so you are allowed to subtract -1 from your score. \$\endgroup\$
    – foobar
    Apr 17, 2014 at 8:58
0
\$\begingroup\$

C89/C99 comment exploit, 45 character, 0 score

main(a){while(++a<47)putchar(79-a//**/~0
);}

c89 output

QRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} - 45 char.

c99 output

MLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"! - 45 char.

\$\endgroup\$
5
  • \$\begingroup\$ This in fact uses exactly the same logic as the other C answer. \$\endgroup\$
    – user12205
    Apr 16, 2014 at 18:43
  • \$\begingroup\$ I mean, considering the fact that there is already an answer of this question using the exact same language and the exact same logic, this answer is not very interesting. \$\endgroup\$
    – user12205
    Apr 16, 2014 at 19:06
  • \$\begingroup\$ This entry is superior to the initial 'other C answer' on multiple levels. It's shorter, scores perfect, completes in under two seconds, and doesn't crash or abort. As far as the updated version... in fairness you should probably leave a comment linking this code. \$\endgroup\$ Apr 18, 2014 at 21:14
  • \$\begingroup\$ Your answer is better than the "initial" other C answer because that other C answer was submitted BEFORE the rule change. \$\endgroup\$
    – user12205
    Apr 18, 2014 at 23:25
  • \$\begingroup\$ Maybe, but the updated version rips my implementation. Not only does it use the same offsets and switch from printf to putchar; most damning is that for r5 I misread the rules and accidentally combined new and old scoring. Output for [r5,r6] is an error. r3 in the other C answer contains the exact same error. If you look at the timestamps, you'll see it was r5 that was posted here when the other answer updated. Not that it matters, since this is code golf, and this entry satisfies the challenge in fewer characters, period. \$\endgroup\$ Apr 19, 2014 at 15:57
0
\$\begingroup\$

SmileBASIC 3 / SmileBASIC 2, Score: -5 (original scoring)

?1E9

In modern versions of SB, this prints 1000000000 as expected, but in version 2 and earlier it printed 10 due to a bug.

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

Go 1.9->1.10. Score = 1 - 1 = 0

From 1.10 notes:

There is no longer a limit on the GOMAXPROCS setting. (In Go 1.9 the limit was 1024.)

package main 
import (r"runtime")
var g=r.GOMAXPROCS
func main() {g(10340)
print(g(0))}

1.8: 256

1.9: 1024

1.10: 10340

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

ARMv4T/ARMv5TE+ with libc, pop {pc} bug, for old scoring system, 42 40 bytes, old score -4294967252 -4294967255

1009 e28f 4002 e92d e001 e04f f004 e49d
e002 e201 ff11 e12f 4674 2021 f7ff fffe
3401 d1fa bc01 4700

ARMv4T, the ISA used in the ARM7TDMI, famous for powering the Game Boy Advance, introduced the Thumb instruction set.

It is a 16-bit (later mixed with 32-bit) instruction set encoding that is more compact, but more limited, than the standard 32-bit ARM instruction set. I write a lot of my golfs in it, because it is torture fun.

Basically, the idea is, since ARM instructions are always 4 byte aligned, if you jump to an odd address, the CPU will switch to Thumb execution mode at the address rounded down, and vice versa for an even address.

One cool thing that ARM lets you do is pop the return address directly into the program counter from the stack, resulting in incredibly easy stack cleanup (similar to leave; ret in x86, but you can pop ALL registers at once)

        push    {..., lr} @ put the return address in the link register on the stack
        pop     {..., pc} @ pop the return address into the program counter to return

On ARMv5TE and later, this will magically switch between ARM and Thumb state.

However, ARMv4T had an infamous bug here.

They forgot to implement Thumb switching: pop {pc} will ignore the lowest two bits and not switch to Thumb mode. Source: ARM docs

So all we have to do is write a polyglot that will do something different if it is in ARM or Thumb state, which is easy because the encodings are entirely different.

        .text
        .arm
        .globl main
main:
        add     r1, pc, #9
        push    {r1, lr}
        sub     lr, pc, r1
@ define to simulate ARMv4T behavior
#ifdef SIMULATE_ARMV4T
        b       simulate_armv4t_bug
#else
        pop     {pc}
#endif
.Larmv4t_polyglot:
        and     lr, r1, #2      @ b     .Lthumb_entry; (skipped)
        bx      r1

        .thumb
.Lthumb_entry:
        mov     r4, lr
.Lloop:
        movs    r0, #'!'
        bl      putchar
        adds    r4, #1
        bne     .Lloop
        pop     {r0}
        bx      r0

#ifdef SIMULATE_ARMV4T
        .arm
        .align 2
simulate_armv4t_bug:
        pop     {r12}
        @ clear thumb bit
        bic     r12, r12, #3
        bx      r12
#endif

This program starts in ARM state.

We need r1 to contain the address of .Larmv4t_polyglot, with the Thumb bit set. (So .Larmv4t_polyglot | 1, or .Larmv4t_polyglot + 1)

Therefore, we add 9 to the program counter (which points 8 bytes after the currently executing instruction because of questionable design decisions) to get 16 bytes, or 4 instructions, ahead, with the Thumb bit set.

        add     r1, pc, #9

Push r1 and lr to the stack. The former is so we can perform the pop {pc} bug, and the latter is to save the return address so we can use lr as a temp register and make function calls.

        push    {r1, lr}

Subtract r1 from pc. This results in lr being -1.

        sub     lr, pc, r1

Then, we pop the value from r1 into the program counter.

An ARMv5+ processor will execute the polyglot in Thumb mode, but an ARMv4T processor will ignore the low 2 bits (rounding down) and execute .Larmv4t_polyglot as ARM code.

To simulate the buggy behavior, define SIMULATE_ARMV4T which will replace pop {pc} with a veneer that jumps to that address in ARM mode.

        pop     {pc}

Now, it is time for our polyglot.

ARM mode: Set lr to 0 by setting it to r1 & 2. Since that contains the address of .Larmv4t_polyglot plus one, we know the second bit is clear.

Then, jump to the polyglot again on ARMv4T (the address is still in r1), this time using bx, which DOES switch to Thumb mode.

.Larmv4t_polyglot:
        and     lr, r1, #2
        bx      r1

Thumb mode: Jump to .Lthumb_entry.

.Larmv4t_polyglot.thumb:
        b       .Lthumb_entry
        @ skipped

Now, we are in Thumb mode on both machines, we can do our output loop.

We first need to make a copy, because lr will be overwritten.

      mov     r4, lr

Then, we loop calling putchar('!'), until r4 += 1 == 0.

.Lloop:
        movs    r0, #'!'
        bl      putchar
        adds    r4, #1
        bne     .Lloop

On ARMv5TE+, r4 will be -1, so the loop will only run for one iteration, but on ARMv4T, r4 will be 0, so it will run 4294967296 times (0x100000000) until it wraps back around to zero.

I could technically make this infinite, but the rules say that it must eventually finish.

Equivalent C:

uint32_t r4 = lr;
do {
    putchar('!');
} while (++r4);

Finally, do an ARMv4T compatible return using the "Thumb interworking" hack: We pop into a low register and bx to it to return from main.

        pop     {r0}
        bx      r0

Program size: 40 bytes

Output length in ARMv5TE+: 1 byte

Output length in ARMv4T: 4294967296 bytes

Score: -4294967255

ARMv4/ARMv5TE+ with libc, same bug, for new scoring system, 42 bytes, score 0

Mostly the same, but instead of dumping near-infinite '!'s, both will dump 42 bytes to stdout. However, for a maximum negative score, all you have to do is change movs r5, #42 to movs r5, #128 for a score of -86.

Machine code:

1009 e28f 4002 e92d e080 e3b0 f004 e49d
e002 e201 ff11 e12f 252a 4676 19a8 f7ff
fffe 3d01 d1fa bc01 4700

(ARMv4T simulator left out, it is the same)

Assembly:

        .text
        .arm
        .globl main
main:
        add     r1, pc, #9
        push    {r1, lr}
        movs    lr, #128
        pop     {pc}

.Larmv4t_polyglot:
        and     lr, r1, #2      @ b     .Lthumb_entry; (skipped)
        bx      r1

        .thumb
.Lthumb_entry:
        movs    r5, #42
        mov     r6, lr
.Lloop:
        adds    r0, r5, r6
        bl      putchar
        subs    r5, #1
        bne     .Lloop
        pop     {r0}
        bx      r0

The main differences are that instead of initially setting lr to -1, we set lr to 128, and that our print loop will always run 42 times, subtracting 1 from the char it prints each time.

The equivalent C loop looks like this:

uint32_t r5 = 42, r6 = ARMv4T ? 0 : 128;
do {
    putchar(r5 + r6);
} while (--r5);

ARMv5TE+ output

termux ~/golf $ clang -m32 valid-through-the-ages.S
termux ~/golf $ ./a.out | hexdump -C | cut -d' ' -f 3-19
aa a9 a8 a7 a6 a5 a4 a3  a2 a1 a0 9f 9e 9d 9c 9b
9a 99 98 97 96 95 94 93  92 91 90 8f 8e 8d 8c 8b
8a 89 88 87 86 85 84 83  82 81

ARMv4T (simulated) output:

As stated before, the compiler option is just to emulate the bug on my device. It is not needed on actual hardware.

termux ~/golf $ clang -m32 valid-through-the-ages.S -DSIMULATE_ARMV4T
termux ~/golf $ ./a.out | hexdump -C | cut -d' ' -f 3-19
2a 29 28 27 26 25 24 23  22 21 20 1f 1e 1d 1c 1b
1a 19 18 17 16 15 14 13  12 11 10 0f 0e 0d 0c 0b
0a 09 08 07 06 05 04 03  02 01

Program size: 42 bytes

Difference in output length: None

Differing bytes: 42.

Score: 0

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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