Python 3, no comments or string literals, 106 bytes
x=quit
y=x.__class__
y.__add__=print
y.__pos__=x
x+x++x+x
x=__sop__.y
tnirp=__dda__.y
__ssalc__.x=y
tixe=x
I've never liked how comments and string literals let you "turn off" most of your language's syntax in challenges like this, so I wanted to see how far I could golf things without using either comments or string literals. This is what I came up with.
Since I don't have any way to disable the syntactical significance of parentheses, I cannot use the function call operator. Any attempt to do so would result in the reversed code having a closing parenthesis before the first opening parenthesis, which is invalid outside a comment or string literal. I also can't use def
or container literals (aside from unparenthesized tuples), and my access to language features is in general extremely restricted.
One thing I can do is take advantage of Python's operator overloading to call functions implicitly. My ability to define any classes or functions is extremely limited, but fortunately, there are enough tools lying around in the built-in namespace for me to use. Most built-ins don't let me perform the attribute assignment I need to redefine their operator overloads, but (unless Python is run with one of the flags that disables site
importing) the auto-imported site
module adds quit
and exit
objects to the built-ins. These objects are instances of non-C classes, so I can reassign their operator overloads.
Setting __add__
to print
lets me use addition to print things, and setting __pos__
to quit
or exit
lets me use the unary +
operator to abort the program before the rest of the code runs. Without setting __pos__
, I would need a bunch of additional code to make sure the "backwards" part of the code can find all the variables and attributes it needs to not fail. With __pos__
, I only need to make sure the "backwards" code is still syntactically valid.
Forward, the code prints
Use quit() or Ctrl-D (i.e. EOF) to exit
Backward, the code prints
Use exit() or Ctrl-D (i.e. EOF) to exit
(The messages are slightly different on Windows. For platform-independent output at the expense of 3 extra bytes, you can replace the middle line with x+1++x++2+x
, printing 1
when run forwards and 2
when run backwards.)
I also tried to figure out a way to do this by defining my own class instead of messing with quit.__class__
. I got as far as the following:
if.1j:adbmal=1j
class ton:adbmal
a=lambda:j1.fi
j1=a
a.__dict__=a.__globals__
class ton:adbmal
is one of the very few combinations of class name and class body such that the class statement is syntactically valid backward. tressa
, led
, labolg
, tropmi
, and esiar
would also have been valid class names (with a different class body, such as not fi
), but ton
is the only one where the reversed name can be part of an expression, giving the most flexibility.
if.1j:adbmal=1j
assigns a value to adbmal
to make the class body succeed, while still being syntactically valid backward.
The stuff with a
and j1
lets me use j1.ton
to refer to my ton
class, which is still a valid expression backward.
At this point, I got stuck. I couldn't figure out how to get my class out of j1.ton
and into a more useful variable. I can't assign attributes on j1.ton
and still have valid syntax backward, so I can't set operator overloads. I also wanted to set builtins.__build_class__
to my class so I could abuse the class
statement to construct instances without the function call operator, but trying to put j1.ton
on the right side of an assignment produces invalid syntax backward.
If I had been able to name my class something like fi
or tpecxe
, I could have used tricks like b:j1.fi
to get the class into an annotation and then a.__dict__=__annotations__
to get it into a.b
, but I couldn't find any way to get the class statement and the annotation tricks to hook up. Anything that was compatible with the class statement was incompatible with the annotation tricks.
(You might wonder why I didn't abuse builtins.__build_class__
to call an existing function directly, like print
. I couldn't figure out a way to do that and have the output be deterministic, and I wanted deterministic output.)