For some reason the topic of 2 + 2 = 5 came up today while working with Travis. He pointed out a funny thread where he demonstrated with two methods and a compiler deoptimization that he could make 2+2 = 5 in a Smalltalk image without breaking the rest of the running code.
I thought this was pretty funny - I'm sure people had good chuckles about it back when it was posted too. But I was a bit surprised that it took so much code. I wondered what would happen if you just changed the compiler... so if you're curious, add the following to your image:
AssemblerCodeStream>>sendNoCheck: selector numArgs: nargs | index | selector = #+ ifTrue: [code skip: -2. (code next: 2) = #[ 75 75 ] ifTrue: [code skip: -2. ^self pushConstant: 5]]. ... keep the rest of the method as is ...
This isn't quite as powerful as Travis's code - since you cannot put 2's in to variables and have them incidently add up to 5, but if you inspect '2+2' you will get 5.
Naturally, we could use this sort of technique for something more useful, like inlining the behaviour of ifNil: and ifNotNil: ... I'd actually rather we had two levels of bytecode - unmodified (exactly represents the code you wrote) and optimized (dynamically inlines, optimizes, unwinds loops, puts in jump statements etc).
May be we'll get there one day.