Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Code Will Eat Itself

Code Will Eat Itself

To prove the undecidability of the halting problem you have to feed a program its own source code as input. Sometimes this can be done by reading data from the filesystem, but Kleene’s recursion theorem guarantees that a program can always calculate its own source code without relying on external storage.

This talk shows how to extend any Ruby program with a local variable containing its own source.

A lightning talk given at Scottish Ruby Conference 2013 (http://lanyrd.com/2013/scotruby/). There’s a video of this talk at https://tomstu.art/impossible-programs. This talk is adapted from chapter 8 of Understanding Computation (http://computationbook.com/).

Tom Stuart

May 13, 2013
Tweet

More Decks by Tom Stuart

Other Decks in Programming

Transcript

  1. A Ruby program run from a filesystem happens to be

    able to read its own source code: program = File.read(__FILE__) But what about Ruby programs that you type straight into IRB? What about compiled languages (Java, C)? What about JavaScript in a browser?
  2. Kleene’s recursion theorem roughly : Any computer program can calculate

    its own source code. This means we can modify any Ruby program to read its own source, without touching the filesystem.
  3. >> puts 'Single quotes look like \'this\'.' Single quotes look

    like 'this'. => nil >> puts %q{Curly brackets look like {this}.} Curly brackets look like {this}. => nil >> puts %q{An unbalanced curly bracket like this} is a problem.} SyntaxError: syntax error, unexpected tIDENTIFIER, expecting end-of-input
  4. program = %q{program = %q{program = %q{program = %q{program =

    %q{program = %q{program = %q{program = %q{...}}}}}}}}}} x = 1 y = 2 puts x + y
  5. program = %q{program = %q{program = %q{program = %q{program =

    %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{...}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} x = 1 y = 2 puts x + y
  6. program = %q{program = %q{program = %q{program = %q{program =

    %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{...}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} x = 1 y = 2 puts x + y
  7. program = %q{program = %q{program = %q{program = %q{program =

    %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{program = %q{...}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} x = 1 y = 2 puts x + y
  8. Our mistake is to try to put the program literally

    inside itself. A. Assign the current program’s source to program B. Do whatever other work the program is supposed to do i.e. the code we originally started with We're trying to write the program in two parts:
  9. We can avoid the problem by computing the source dynamically

    from data we provide. Write a three-part program: A. Assign a string literal to a variable call it data) B. Use that string to compute the whole program’s source and assign it to program C. Do whatever other work the program is supposed to do i.e. the code we originally started with
  10. A. Store the literal source code of parts B and

    C in data B. Compute part A's source from data, then concatenate the sources of A, B and C to get program C. Do whatever other work the program is supposed to do i.e. the code we originally started with Here's how to actually do it:
  11. data = %q{...} program = ... x = 1 y

    = 2 puts x + y We know most of the source of parts B and C already, so we can partially complete the value of data.
  12. data = %q{ program = ... x = 1 y

    = 2 puts x + y } program = ... x = 1 y = 2 puts x + y We also know that the source of part A is just the string 'data = %q{...}' with the value of data filling the gap between the curly braces, so we can partially complete the value of program too.
  13. data = %q{ program = ... x = 1 y

    = 2 puts x + y } program = "data = %q{#{data}}" + ... x = 1 y = 2 puts x + y Now all that’s missing from program is the source code of parts B and C, which is exactly what data contains, so we can append the value of data to program to finish it off.
  14. data = %q{ program = ... x = 1 y

    = 2 puts x + y } program = "data = %q{#{data}}" + data x = 1 y = 2 puts x + y Finally, we can go back and fix up the value of data to reflect what part B actually looks like.
  15. data = %q{ program = "data = %q{#{data}}" + data

    x = 1 y = 2 puts x + y } program = "data = %q{#{data}}" + data x = 1 y = 2 puts x + y That's it!
  16. data = %q{ program = "data = %q{#{data}}" + ...

    puts program } program = "data = %q{#{data}}" + ... puts program
  17. data = %q{ program = "data = %q{#{data}}" + data

    puts program } program = "data = %q{#{data}}" + data puts program
  18. >> data = %q{ program = "data = %q{#{data}}" +

    data puts program } => "\nprogram = \"data = %q{\#{data}}\" + data\nputs program\n" >> program = "data = %q{#{data}}" + data => "data = %q{\nprogram = \"data = %q{\#{data}}\" + data\nputs program\n} \nprogram = \"data = %q{\#{data}}\" + data\nputs program\n" >> puts program data = %q{ program = "data = %q{#{data}}" + data puts program } program = "data = %q{#{data}}" + data puts program => nil
  19. data = %q{ program = "data = %q{#{data}}" + data

    puts program } program = "data = %q{#{data}}" + data puts program ..is a quine. The program...