Pristine and Unique Code Bowling

85

10

Your challenge is simple: write as long of a pristine program as possible in the language of your choice using only unique bytes. (The full definition of a pristine program, copied from that link, is at the bottom of this question.)

That's right, no strings attached. Your code doesn't have to do anything at all, just run without erroring, meet the requirements for a pristine program (linked above), and include no duplicate bytes in the encoding you use.

For the purposes of the above explanation and linked definition of "pristine program", an error is defined as anything that causes the program to either entirely fail to run or to terminate with a nonzero exit code after a finite amount of time.

As this is , longest, not shortest, code wins (measured by byte count). The maximum theoretically possible score is 256, as there are 256 distinct bytes possible. In case of a tie, the first answer at the highest score wins.


Here's the full definition of a pristine program, copied from the above link:

Let's define a pristine program as a program that does not have any errors itself but will error if you modify it by removing any contiguous substring of N characters, where 1 <= N < program length.

For example, the three character Python 2 program

`8`

is a pristine program because all the programs resulting from removing substrings of length 1 cause errors (syntax errors in fact, but any type of error will do):

8`
``
`8

and also all the programs resulting from removing substrings of length 2 cause errors:

`
`

If, for example, `8 had been a non-erroring program then `8` would not be pristine because all the results of substring removal must error.

Aidan F. Pierce

Posted 2018-04-15T19:23:24.760

Reputation: 1 365

38Hats off to you for managing to create a good [tag:code-bowling] challenge! – ETHproductions – 2018-04-15T21:35:35.633

If a subprogram runs forever but does not error does that make the answer invalid? – dylnan – 2018-04-16T02:28:15.157

1@dylnan "an error is defined as [...] terminate [...] after a finite amount of time." – user202729 – 2018-04-16T02:30:24.570

I would do great if this was code-golf instead! – Redwolf Programs – 2018-04-16T02:45:45.113

is '8' allowed? ' isn't unique... – Baldrickk – 2018-04-16T12:24:57.030

3@Baldrickk No, it wouldn't be allowed for this challenge. (If you're referring to the example in the question, it's a demonstration of what a pristine program is, but which doesn't meet the additional requirement of unique bytes.) – Aidan F. Pierce – 2018-04-16T12:58:56.647

Are pristine functions allowed? In other words, does this intentionally deviate from the default for code golf? I recognize that this isn't code golf, but I think [tag:restricted-source] gives similar motivations for deciding which structure to use.

– Kamil Drakari – 2018-04-16T15:28:07.143

@KamilDrakari I can think of arguments both ways, but I don't think I want to allow them for this challenge. – Aidan F. Pierce – 2018-04-16T18:12:47.210

1Nice choosing a question ID with unique digits (though not pristine ;-) ) – Paŭlo Ebermann – 2018-04-16T19:20:09.117

1Can we count undefined behavior as an error if in practice it usually results in an error? I'm thinking of something like JMP <address outside of the program's memory> in assembly. In principle on a real computer it could loop infinitely or exit with a non-zero error, but it will usually crash spectacularly. – Chris – 2018-04-17T01:06:53.440

@Chris It's a bit of a borderline case, but I'll allow it. – Aidan F. Pierce – 2018-04-17T01:49:46.047

Answers

26

Jelly, 253 254 256 bytes

M“¢£¥¦©¬®µ½¿€ÆÇÐÑ×ØŒÞßæçðıȷñ÷øœþ !"#%&'()*+,-./0145689:;<=>?@ABCDEFGHIJKNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|~¶°¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ƁƇƑƓƘⱮƝƤƬƲȤɓƈɗƒɠɦƙɱɲƥʠɼʂƭʋȥẠḄḌẸḤỊḲḶṂṆỌṚṢṬỤṾẈỴẒȦḂĊḊĖḞĠḢİĿṀṄȮṖṘṠṪẆẊẎŻḅḍẹḥịḳḷṃṇọṛṣṭụṿẉỵẓȧḃċḋėḟġḣŀṁṅȯṗṙṡṫẇẋẏż”L»«’Ɗạ‘}237$¤¡

Try it online! or Verify it!

Turns out golfing languages can bowl...

  • +1 byte by working in . Now only «» are not used
  • +2 bytes with with «». Now have the optimal score!

How?

The crucial feature of Jelly that makes this possible is that the opening and closing characters for string literals are not the same like in nearly all other languages.

The program structure is as follows:

M <239 character long string> L»«’Ɗạ‘}237$¤¡

M finds the indices of its argument that point to maximal elements. All that matters is that with no argument to this program Jelly assigns 0 to the chain and Jelly errors when M is applied to 0.

To prevent M from acting on 0 in the full program, we use the ¡ quick, which applies M a number of times determined by the result of the link immediately preceding it. In this case that link is <239 character long string> L»«’Ɗạ‘}237$¤.

L takes the length of this string (239), and »«’Ɗ decrements this to 238. The »« part doesn't do anything but Ɗ (last three links as a monad) makes it so that if they are deleted an error will occur. Then takes the absolute difference between the result of »«’Ɗ and the monad ‘}237$ applied to the string. increments and is a monad, but the } turns this into a dyad and applies it to it's right argument, 237, yielding 238. Thus yields 0 in the full program.

¤ links back to the string literal forming a nilad. The result of this is 0, so M is not applied at all, preventing any error.

Possible subprograms:

  • If any part of the string is removed, <string>..¤ will be nonzero and M gets applied to 0, causing an error.
  • If any part of L»«’Ɗạ‘}237$ is removed either M will get applied to 0 or there will be operations between the string and a number, resulting in a TypeError.
  • If any of ¤¡ is removed, M gets applied to 0.
  • If the string closing character and both of ’‘ get removed and doesn't, everything after M turns into a string so M will act on 0.
    • If the string closing character and get removed and doesn't, everything between and turns into a list of integers.
  • If M alone is removed there is a an EOFError because ¡ expects a link before the preceding nilad.
  • If M“ and any number of characters after it is removed, there will be an EOFError because the ¤ looks for a nilad preceding it but doesn't find one. 238 doesn't count because it is part of a monad.

This pretty much covers everything.

I previously hadn't used «»‘ because the latter two cannot be included in the string because they match the character to form things other than strings. « can't be in a “” string either but I don't know why.

dylnan

Posted 2018-04-15T19:23:24.760

Reputation: 4 993

32

Haskell, 39 45 50 52 60 bytes

main=do{(\	陸 ⵙ商ߜ 新->pure fst)LT
EQ[]3
2$1}

Identifier main has to have type IO a for some type a. When the program is executed, the computation main is performed, and its result is discarded. In this case its type is IO ((a,b)->a).

The result is an application of the function (λ a b c d e f → return fst), a six-argument constant function returning the function fst (which gives the first element of a 2-tuple), injected into the IO monad. The six arguments are LT (enum for less than), EQ (enum for equality), empty list [], 3, 2 and 1.

What would be spaces are replaced with unique characters that count as spaces: a tab, a non-breaking space, a formfeed, vertical tab, OGHAM SPACE MARK, regular space, newline and carriage return. If any of these are missing, there will be a mismatch in the number of arguments. The parameter names are chosen as three or four byte UTF-8 characters, 陸ⵙ商ߜ新, carefully choosing characters that don't result in duplicate bytes.

Thanks to @BMO for his valuable contributions.

Hex dump:

00000000: 6d61 696e 3d64 6f7b 285c f0a4 b6b8 09ef  main=do{(\......
00000010: a793 c2a0 e2b5 990c e595 860b df9c e19a  ................
00000020: 80e6 96b0 2d3e 7075 7265 2066 7374 294c  ....->pure fst)L
00000030: 540a 4551 5b5d 330d 3224 317d            T.EQ[]3.2$1}

Try it online!

Angs

Posted 2018-04-15T19:23:24.760

Reputation: 4 825

Hm, '\109999' seems to be valid, at least in GHC 8.2.2. '\10999a' produces a lexical error. – chepner – 2018-04-18T16:41:46.283

@chepner: I just tested with GHC 8.2.2 and `` produces a lexical error as well. – ბიმო – 2018-04-18T18:43:03.637

2@chepner: largest Char is maxBound :: Char, i.e. '\1114111'. Note: numbers are decimal by default, so if you want hex, you have to put an x after the \, e.g. '\x10999a'. – nimi – 2018-04-19T16:05:05.763

@nimi Aaaand I think we've established how often I actually use Unicode escapes :) Using the correct form for hex values, \x10ffff works fine, and \x110000 provides an out-of-range error as one would expect. – chepner – 2018-04-19T16:23:17.057

26

Python 2,  20 21 33 39 45  50 bytes

Now very much a collaborative effort!

+2 thanks to Aidan F. Pierce (replace sorted({0}) with map(long,{0}))

+8 thanks to dylnan (use of \ and newline to replace space; suggestions to move from 0 to a mathematical expression; replacing -1 with -True; use of hexadecimal)

+11 thanks to Angs (4*23+~91 -> ~4836+9*1075/2 then later ~197836254+0xbCABdDF -> ~875+0xDEAdFBCbc%1439/2*6)


if\
map(long,{~875+0xDEAdFBCbc%1439/2*6})[-True]:q

Try it online! Or see the confirmation suite

0xDEAdFBCbc is hexadecimal and evaluates to 59775106236.
~ is bit-wise complement so ~875 evaluates to -876.
% is the modulo operator so 0xDEAdFBCbc%1439 evaluates to 293.
/ is integer division so 0xDEAdFBCbc%1439/2 evaluates to 146.
* is multiplication so xDEAdFBCbc%1439/2*6 evaluates to 876.
+ is addition so ~875+xDEAdFBCbc%1439/2*6 evaluates to 0.
...no stripped version also evaluates to 0.

{0} is a set containing a single element, 0.

Calling sorted with a set as the argument yields a list, which may be indexed into with [...].

Without sorted the code ({0}) would just yield the set and this cannot be indexed into in the same fashion, if({0})[-True]:q would raise a TypeError.

Indexing in Python is 0-based and allows negative indexing from the back and True is equivalent to 1, hence sorted({0})[-True] finds the element 0, while sorted({0})[True] will raise an IndexError, as will sorted({})[-True] and sorted({0})[] is invalid syntax.

The 0 that is found is falsey so the body of the if, q, is never executed, however if it were it would raise a NameError since q has not been defined.

Since a non-empty list is truthy we cannot trim down to if[-1]:q either.

See the confirmation suite to see: confirmation the bytes being unique; all the errors; and the success of the code itself.

Jonathan Allan

Posted 2018-04-15T19:23:24.760

Reputation: 67 804

18

C (tcc), x86_64, 29 31 33 39 40 bytes

main[]={(23*8),-~0xABEDFCfebdc%95674+1};

Returns 0. Thanks to @feersum for suggesting uppercase hex digits.

Try it online!

How it works

The assignment writes two ints (184 and 49664) to the memory location of main. With 32-bit ints and little-endian byte order, the exact bytes are b8 00 00 00 00 c2 00 00.

Since tcc doesn't declare the defined array as .data (most compilers would), so jumping to main executes the machine code it points to.

  • b8 00 00 00 00 (mov eax, imm32) stores the int 0 in the eax register.

  • c2 00 00 (ret imm16) pops 0 extra bytes from the stack and returns. (The value in the eax register is the function return value).

Dennis

Posted 2018-04-15T19:23:24.760

Reputation: 196 637

1The TIO link is showing a segmentation fault for me. – pppery – 2019-10-23T21:53:02.693

16

><>, 122 bytes

e"~l=?!z6-d0p}xwutsrqonmkjihgfcba`_]\[>ZYXWVUTSRQPONMLKJIHGFEDCB@<:98754321/,+*)('&%$# .	|{Ay

Try it online!

Does nothing. Based on the same format as my Programming a Pristine World answer.

First, we check that the length of the code is 122 and error if it isn't. ><> programs can't end without the use of the ; command, but if this command is in the program, we can just remove everything before it to make the program end immediately. To combat this, we use the p command to place a ; in the code during runtime. To do this, we subtract 6 from A and place it after the p.

I'll probably add most of the other values above 127 once I figure out the right two byte values. The missing 5 values are v^; and the two newlines.

Of the 7502 sub-programs, 7417 of them errored from invalid instructions, 72 from memory underflow, and 13 from running out of memory.

Jo King

Posted 2018-04-15T19:23:24.760

Reputation: 38 234

13

JavaScript, 42 bytes

if([0XacdCADE*Proxy.length]!=362517948)田
  • Removing i, f, or if will cause SyntaxError: missing ; before statement;
  • Removing will cause SyntaxError: expected expression, got end of script;
  • Removing 1 or 2 bytes from will cause Invalid or unexpected token;
  • Modify the boolean expression will cause either Syntax Error or Reference Error on

00000000: 6966 285b 3058 6163 6443 4144 452a 5072  if([0XacdCADE*Pr
00000010: 6f78 792e 6c65 6e67 7468 5d21 3d33 3632  oxy.length]!=362
00000020: 3531 3739 3438 29e7 94b0                 517948)...

(function () {
  let valid = code => { try { eval(code); return true; } catch (e) { return false; } };
  let test = P => {
    for (let i = 0; i < P.length; i++) for (j = i + 1; j <= P.length; j++) {
      let Q = P.slice(0,i) + P.slice(j);
      if (Q && valid(Q)) {
        console.log(Q);
        return false;
      }
    }
    return true;
  };
  let unique = P => !/(.).*\1/.test(P);
  let P = 'if([0XacdCADE*Proxy.length]!=362517948)田';
  console.log(unescape(encodeURIComponent(P)).length);
  console.log(valid(P));
  console.log(unique(P));
  console.log(test(P));  
}());

tsh

Posted 2018-04-15T19:23:24.760

Reputation: 13 072

10

Brain-Flak, 2 bytes

<>

Try it online!

Alternatively, [], {} or (). Removing either bracket causes the other bracket to become unmatched.

Proof that this is the optimal solution:

A Brain-Flak program is made out of nilads (a pair of brackets on their own) or monads (a pair of brackets containing 1 or more nilads). A monad cannot be in a pristine program, as you can simply remove one or more of the nilads. Similarly, you cannot have more than one nilad in the program, since you can remove one of them without breaking the program.

As such, this might be the least optimal language for pristine or unique programming.

Jo King

Posted 2018-04-15T19:23:24.760

Reputation: 38 234

6

Ada, 110 bytes (latin1)

Probably the best answer you'll get out of any language in use in industry?

Hexdump:

0000000: 7061 636b 4167 4520 6266 686a 6c6d 6f71  packAgE bfhjlmoq
0000010: 7274 7576 7778 797a e0e1 e2e3 e4e5 e6e7  rtuvwxyz........
0000020: e8e9 eaeb eced eeef f0f1 f2f3 f4f5 f6f8  ................
0000030: f9fa fbfc fdfe 0d69 730b 656e 6409 4246  .......is.end.BF
0000040: 484a 4c4d 4f51 5254 5556 5758 595a c0c1  HJLMOQRTUVWXYZ..
0000050: c2c3 c4c5 c6c7 c8c9 cacb cccd cecf d0d1  ................
0000060: d2d3 d4d5 d6d8 d9da dbdc ddde 3b0a       ............;.

Compile by saving to any file ending in .ads and running gcc -c <filename>. Produces an executable that does nothing. (Can't provide TIO link since TIO puts code in a .adb file and gcc by default tries to find a matching spec for them)

Basically declares a package with a name abusing capital/lowercase latin1 letters. Needs a different whitespace character for each of the spaces, so it uses space, CR, LF, and TAB.

How it looks in vim version:

packAgE bfhjlmoqrtuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ^Mis^Kend^IBFHJLMOQRTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ;

How it works

In Ada even spec's can be compiled. Spec's are like c's header files, but are more full-featured and can compile some basic code. In order to be valid any specification must have the format: package <NAME> is ... end <NAME>; with <NAME> matching. The nice thing about Ada is that it is completely case insensitive. Thus as long as your name has uppercase and lowercase variants, you'll be good to go!

The hard part was getting a compilable unit. Normally Ada programs have a 'main' procedure or function lying outside of any package that will become the final executable. Unfortunately procedures require the begin keyword, which leads to too many es (only 2 cases known) while functions require the return keyword, which leads to too many ns. Thus I had to just compile a package.

LambdaBeta

Posted 2018-04-15T19:23:24.760

Reputation: 2 499

5

C, 8 bytes

main(){}

Does nothing.

Try it online!

Steadybox

Posted 2018-04-15T19:23:24.760

Reputation: 15 798

1Maybe I don't understand the challenge but what about main(){short x;} – Jerry Jeremiah – 2018-04-16T22:52:46.610

@JerryJeremiah: no, main(){short;} compiles with only a warning: useless type name in empty declaration. I think C99 and C++ require an explicit return type, so int main (or maybe unsigned main) could work, but not with gcc which only warns even with -std=c11. – Peter Cordes – 2018-04-17T00:30:30.897

@JerryJeremiah: a return 0; might be possible with C89, where there's no implicit return 0 at the end of main. Exiting with non-zero status can be considered failure, according to other answers. Does adding compiler flags like -Werror count towards the score in a good way in code bowling? Because strictly enforcing violations of C11 could allow a much longer program. Hmm, #include<> something and then use it; you can't remove both include and usage, and if it crashes without a prototype or macro def, you win. – Peter Cordes – 2018-04-17T00:43:05.277

@PeterCordes I thought about that, but main and include both contain i, so you can't have both. Similarly for declaring and using a function. Also using return at all come to think of it. – Chris – 2018-04-17T00:48:04.223

oops, I forgot about the unique bytes requirement; of course int main can't work. – Peter Cordes – 2018-04-17T00:48:05.690

4

Python 3 + Flask-Env, 7 13 14 17 bytes

import\
flask_env

No TIO because it doesn't have flask-env.

Found the longest module name that has no intersection with import and doesn't have any numbers at the end of the name. _sha256 is longer but 256 on it's own doesn't error. I did find one library, b3j0f.sync that is one byte longer but I could not get it to import properly.

  • +1 byte by replacing a space after import with \<newline>. Taking out either or both causes an error.

There still may be longer options than flask_env, I didn't really do an exhaustive search but I did look through ~70,000 modules. Open to suggestions.

dylnan

Posted 2018-04-15T19:23:24.760

Reputation: 4 993

1256 runs without erroring. – Aidan F. Pierce – 2018-04-15T20:51:09.890

@AidanF.Pierce Thanks, fixed. – dylnan – 2018-04-15T20:53:03.610

I tried import *[hawkey] and similar but unfortunately doesn't work... – dylnan – 2018-04-15T21:07:40.483

2hawkey is not in the standard library, so this is "Python with hawkey" (probably can do better with some other module somewhere) – Jonathan Allan – 2018-04-15T21:09:19.500

@JonathanAllan Good point. Have to go right now but I'll search later – dylnan – 2018-04-15T21:33:14.720

4

JavaScript, 22 bytes

with(0xF?JSON:[])parse

Try it online!

Possible errors

When altered, it will throw one of the following errors1:

[some_identifier] is not defined
expected expression, got ')'
expected expression, got ':'
expected expression, got '?'
expected expression, got ']'
expected expression, got end of script
identifier starts immediately after numeric literal
missing ( before with-statement object
missing ) after with-statement object
missing : in conditional expression
missing ] after element list
missing exponent
missing hexadecimal digits after '0x'
missing octal digits after '0o'
unexpected token: ')'
unexpected token: ']'
unexpected token: identifier

1. The exact number of distinct errors depends on the engine. This list was generated with SpiderMonkey (Firefox).

Arnauld

Posted 2018-04-15T19:23:24.760

Reputation: 111 334

3

R, 14 bytes

(Sys.readlink)

Try it online!

This might be the longest possible in R. Calling any function is doomed to failure, because you would be able to remove everything but the function name, which would just result in printing the function's source code. This is the longest named object in the default R setup with no duplicate characters and no object name left over when removing contiguous characters.

This first try didn't work, but I learned a lot by trying!

dontCheck({family;NROW})

ngm

Posted 2018-04-15T19:23:24.760

Reputation: 3 974

2

Perl 5, 3 bytes

y=>

=> is the "fat comma," which quotes the bareword on the left. So this is equivalent to

"y",

which does nothing.

Without the fat comma, y is the transliteration operator, which is invalid without three of the same character repeated later.

The fat comma alone is also invalid, as is = and > alone.

Chris

Posted 2018-04-15T19:23:24.760

Reputation: 1 313

2

brainfuck, 2 bytes

[]

Try it online!

Inspired by Jo King's Brain-Flak answer. This is optimal because the only error in brainfuck is unmatched brackets. (Again thanks to Jo King for this info.)

dylnan

Posted 2018-04-15T19:23:24.760

Reputation: 4 993

Yup. The only error brainfuck can have is unmatched brackets – Jo King – 2018-04-17T07:46:54.317

2

Ruby, 28 bytes

(?2*0xA)[%r<\d{1}>].unpack$/

Try it online!

Verify it!

lfvt

Posted 2018-04-15T19:23:24.760

Reputation: 121

1

Tcl, 6 bytes

puts a

Try it online!


Tcl, 3 bytes

pwd

Try it online!


Tcl, 2 bytes

cd

Try it online!

sergiol

Posted 2018-04-15T19:23:24.760

Reputation: 3 055

valid and pristine. – NH. – 2018-04-18T17:32:12.057

1

Standard ML, 22 bytes

val 1089=op-(765,~324)

Try it online! op-(a,b) is the de-sugared form of a-b. ~ denotes the unary minus, so we are actually computing 765+324. This expression is pattern-matched on the constant 1089. This match succeeds if the program has not been tampered with and does - well, nothing.

If the match does not succeed because some digits were removed one gets an unhandled exception: Bind. Removing op- results in a type error because a tuple is matched on an int. All other removals should result in an syntax error.

Laikoni

Posted 2018-04-15T19:23:24.760

Reputation: 23 676

1

Swift 4, 19 bytes

[].contains{1 !=
0}

Try it online!

All the possible errors I have found are:

  • Removing any of [, ], { or } will result in a syntax error
  • Removing []. will result in Use of unresolved identifier 'contains'
  • Removing . will result in Consecutive statements on a line must be separated by ';'
  • Removing [] will result in Reference to member 'contains' cannot be resolved without a contextual type
  • Removing {1 !=␊0} will result in Expression resolves to an unused function
  • Removing 1 !=␊0 will result in Missing return in a closure expected to return 'Bool'
    • Removing the newline will result in '!=' is not a prefix unary operator
    • Removing the space will result in '=' must have consistent whitespace on both sides
    • Removing != will result in Missing return in a closure expected to return 'Bool'
      • Also removing the newline will result in Consecutive statements on a line must be separated by ';'
      • Removing the space and the newline (and zero or one of the digits) will result in Contextual type for closure argument list expects 1 argument, which cannot be implicitly ignored
  • Removing [].contains will result in Closure expression is unused

Some other interesting programs are (one on each line):

[].isEmpty
[:].values
[1:2]

Herman L

Posted 2018-04-15T19:23:24.760

Reputation: 3 611

This contains two as – caird coinheringaahing – 2018-04-19T15:42:39.643

0

Batch, 7 bytes

set/px=

A nice start

ericw31415

Posted 2018-04-15T19:23:24.760

Reputation: 2 229

0

Retina, 2 bytes

I wouldn't be surprised if this is optimal...

()

Try it online!

The regex contains an empty group. Removing either paren will cause a parse error due to unmatched parentheses.

Other solutions are: \(, \), \[, \], \*, \+, \?, a]

mbomb007

Posted 2018-04-15T19:23:24.760

Reputation: 21 944

a] doesn't error. – jimmy23013 – 2018-04-19T07:22:31.660

@jimmy23013 Ah, I don't know how I missed that. Rolled back. – mbomb007 – 2018-04-19T13:45:57.487