Permanently self-modifying code

Now, we all know most languages have very simple ways to "self-modify" code. However, what if you were to actually modify the code and edit parts of it...on disk?

Your goal is to make code that prints a number, then edits its own file to replace the number with the next one in the Fibonacci sequence like so:

$./program 1$ ./program
1
$./program 2$ ./program
3
echo $A sed -ri "s/\w+\+(\w+)/\1+$A/" $0  Test >for i in seq 10 > do > ./fibo > done 1 1 2 3 5 8 13 21 34 55  • I think you could save 1 byte by starting from [1+0] instead of [-1+1] (see 4th rule of the challenge) – Leo Jan 22 '17 at 11:57 • Actually, that would make you save even more bytes by removing the -? from the regex. And since you're there, you could also remove the first capturing group :) – Leo Jan 22 '17 at 12:01 • @Leo That's a nice advice, thank you ! – zeppelin Jan 22 '17 at 12:25 Batch, 81 bytes @call:c @set/az=x+y @echo %x% @echo>>%0 @set/ax=%z%,y=%x% :c @set/ax=0,y=1  Note: the trailing newline is significant. Requires the script to be invoked using its full name including extension. Output starts at 0. Since Batch can't realistically edit a file, I just add extra lines to the end of the file, so eventually it will know which the next number to print is. The >>%0 placement saves a byte because I can't precede it with a digit. • -14 bytes, without forcing filename – HackingAddict1337 Apr 18 at 10:20 • @HackingAddict1337 Ah, I don't remember that bonus. – Neil Apr 18 at 10:34 • Also, my batch file now measures 79 bytes for some reason? – Neil Apr 18 at 10:37 • I don't want to put my name to your weird @goto& behaviour, or even your use of an uninitialised variable, so feel free to post your solution as an answer. – Neil Apr 18 at 10:43 • all right then (goto& == cmd/c) – HackingAddict1337 Apr 18 at 10:45 Python 2, 118 111 bytes ( 113 - 2 ) a,b=0,1;print a f=open(__file__,'r+') s=f.read() s=s.replace(s[4:s.find(';')],b+','+a+b) f.seek(0) f.write(s)  It works with any valid filename. There is not much to explain here, the code itself is very verbose. Thanks to FlipTack for reminding me, close() is not mandatory. • Can't you just use f=open(...) instead of the with statement? – FlipTack Jan 22 '17 at 9:52 Python 3.6, 96 91 (93-2) bytes a,b=0,1 f=open(__file__,"r+");next(f);f.write(f"a,b={b,a+b}\n{next(f)}{f.seek(0)}");print(b)  hardcoding the filename would save 5 bytes (88 bytes): a,b=0,1 f=open("f","r+");next(f);f.write(f"a,b={b,a+b}\n{next(f)}{f.seek(0)}");print(b)  Saved some bytes thanks to @Artyer • How about this (88 bytes) a,b=0,1 f=open('f','r+');next(f);f.write(f'a,b={b,a+b}\n{next(f)}{f.seek(0)}');print(b)# – Artyer Jan 23 '17 at 15:42 C, 142 bytes (144 - 2) void main(int x,char**a){FILE*f=fopen(*a,"r+");fseek(f,27,0);char n=fgetc(f),m=fgetc(f);fseek(f,27,0);printf("%d\n",fputc(fputc(m,f)?n+m:1,f));}  It's pretty straight forward. First it reads then saves the two chars at position 0x1A in the header. I probably could've looked deeper to find a safer spot to save the data but it works for me on my machine running OSX, compiled with GCC 4.2ish and I doubt it's very portable. Also, since it's based off chars it overflows after the 13th iteration. It gives the output: 1 1 2 3 5 8 13 21 34 55  Node.js, 152 137 bytes (139 - 2) Separated with newlines for clarity, not part of byte count. f=_=>require('fs').writeFileSync(__filename, f=${f};f().replace(/(\d[^,]*),(\d[^\)]*)/,
(m,a,b)=>${b=+b},${+a+b}),console.log((0,1)));
f()


Explanation:

f=_=>                          // define f as function with a single unused argument _
require('fs').writeFileSync( // import the standard filesystem module and overwrite file
__filename,                // string var containing path of file for current module
f=${f};f().replace( // template string containing source of entire script /(\d[^,]*),(\d[^\)]*)/, // regexp to match and group the numbers in this script (m,a,b)=> // replace function with arguments match, group a, group b ${b=+b},${+a+b} // template string incrementing fibonacci numbers in place ), // end replace() console.log( // prints to stdout, undefined passed to argument (0,1) // comma separated group returns value of last expression ) // end console.log() ) // end fs.writeFileSync() ; // end statement defining f as arrow function f() // run function to modify script and print fibonacci number  Usage: // assuming above script is stored in program.js$ node program
1
$node program 1$ node program
2
$node program 3$ node program
5
...


bash + Unix utilities, 43 bytes (45-2)

dc -e9k5v1+2/z^5v/.5+0k1/p;sed -i s/z/z1+/ $0  The first time this is run, it uses dc to compute the 1st Fibonacci number via the Binet formula. Each call to sed modifies the program by changing the string passed to dc; this change tells dc to add an additional 1 to the exponent in the formula, which causes it to compute the next number in the Fibonacci sequence each time. Test > for k in {1..10} > do > ./fib > done 1 1 2 3 5 8 13 21 34 55  To illustrate how it works, at this point, after the 55 is printed, the program has been modified to read: dc -e9k5v1+2/z1+1+1+1+1+1+1+1+1+1+^5v/.5+0k1/p;sed -i s/z/z1+/$0


so running it again yields

> ./fib
89


dc -e9k5v1+2/z1+1+1+1+1+1+1+1+1+1+1+^5v/.5+0k1/p;sed -i s/z/z1+/ $0  • I like this ! Well done ! – zeppelin Jan 24 '17 at 19:49 • @zeppelin Thank you -- this avoids the issues with the previous version we had. – Mitchell Spector Jan 24 '17 at 19:50 SmileBASIC 3, 99 bytes (101 -2) -2 byte bonus because it works with any filename. A=0B=1F$="TXT:"+PRGNAME$()S$=LOAD(F$)SAVE F$,SUBST$(S$,0,INSTR(S$,"F"),FORMAT$("A=%DB=%D",B,A+B))?A+B


This one does work, and it somehow ended up being the same size as my broken one!

• It's much shorter if you don't do the bonus – 12Me21 Feb 11 '17 at 22:26
• forcing a specific filename makes me feel like a freak. I'm beating half these answers anyway – snail_ Feb 12 '17 at 3:06
• I think not turning off the LOAD dialog is much worse. – 12Me21 Feb 12 '17 at 3:15
• It's actually shorter if you load it into slot 1 and use PRGEDIT commands to replace the first line (and add a linebreak after A=0B=1) And you also don't need A=0 the first time. – 12Me21 Feb 12 '17 at 3:33
• Dang, I saw this one and immediately thought "SmileBASIC". I probably couldn't come close anyways. Nicely done! Btw I'm known as Mr_Mo on sbs – raddish0 Apr 18 at 19:50

Batch, 66 - 2 = 64 bytes

Uses \r line terminators (not traditional \r\n)

@call:a
@set/az=x+y
@(set/p=,x=%z%,y=%x%)<%0>>%0
:a
@goto&set/ax=1


Any filenames are allowed, except for 0-9 (which isn't a .bat anyways)

Credits to:
@dbenham mentioning the weird behavior of GOTO :invalid_or_empty label (originally discovered by some Russians):

In summary, (GOTO) 2>NUL behaves like EXIT /B, except it allows execution of concatenated commands in the context of the caller!

Warning: will overflow if the number exceeds 2^31-1 (47), because batch integers are 32-bits.

R, 145 bytes (147 - 2)

a=c(1,1)
cat(a[1])
cat(c(sprintf("a=c(%i,%i)",a[2],sum(a)),R[-1]),file=f,sep="\n")


(Has a trailing newline). It works with any valid filename.

Perl 6, 67 62 bytes (64 - 2)

say (1,1,*+*...*)[1];$*PROGRAM.&{.spurt: .slurp.&{S/\[<(\d+/{$/+1}/}}


say 0+1;$*PROGRAM.&{.spurt: .slurp.&{S/(\d+).(\d+)/$1+{$0+$1}/}}


Stacked, noncompeting, 65 (67 - 2) bytes

Some issues regarding file IO were fixed in the most recent series of commits. Thus, noncompeting.

2:>
:sum\tail...\stack:0#out repr LF+program LF split last+d0\write


Here's a link to the github.

Example execution

(I omitted the actual path for clarity.)

C:\
λ type permanently-self-modifying-code.stk
2:>
:sum\last\stack:0#out repr LF+program LF split last+d0\write
C:\
λ stacked permanently-self-modifying-code.stk
1

C:\
λ stacked permanently-self-modifying-code.stk
1

C:\
λ stacked permanently-self-modifying-code.stk
2

C:\
λ stacked permanently-self-modifying-code.stk
3

C:\
λ stacked permanently-self-modifying-code.stk
5

C:\
λ stacked permanently-self-modifying-code.stk
8


Explanation

How this works is by taking a pair of numbers to begin the sequence (2:> in this case is the integer range [0, 2), which is (0 1)), then performing the Fibonacci transformation on them, like so:

:sum\last\                     top of stack: (x y)
:              duplicate.             stack: ((x y) (x y))
sum           sum of TOs.            stack: ((x y) x+y)
\          swap order.            stack: (x+y (x y))
last      obtain last element.   stack: (x+y y)
\     swap order.            stack: (y x+y)


On each run, this transformation is executed on the top of stack. Then, the stack is pushed to the stack, duplicated, and its first member obtained (stack:0#). This item is then outputted, and is the desired Fibonacci number. repr then takes the representation of the stack and appends a newline. Then, the program is pushed to the stack, and split on newlines. Then, we take the last member (the last line), and append this to the aforementioned string. Finally, we push d0 (the file itself; think dollar sign 0 == $0.) and write to it. Ruby, 68 bytes (70-2) p$a=1+0
f=open$0,'r+' s=f.read.sub /\d+.(\d+)/,"\\1+#$a"
f.seek 0
f<<s


Clojure, 209204 195 bytes

0 1(let[u #(apply str %)a"./src/s.clj"p #(Long/parseLong(u %))l(fn[v](split-with #(Character/isDigit %)v))c(slurp a)[n[_ & r]](l c)[m r](l r)b(+(p n)(p m))](println b)(spit a(str(p m)" "b(u r))))


-5 bytes by switching to parse the numbers as a long instead of an integer, and removing a couple missed spaces.

-9 bytes by removing the space between the second number and (let...) (most expensive space ever!).

See the pregolfed code comments for a description.

Tested again, and it no longer throws unmatched bracket errors. It works up to 7540113804746346429, at which point it throws an integer overflow exception.

Also note, this assumes the source code is located at "./src/s.clj".

0 1 ; Starting numbers
(let [; The first 4 entires are shortcuts to functions and data that are used more than once
u #(apply str %) ; Turns a list into a string
a "./src/s.clj" ; Current location
p #(Integer/parseInt (u %)) ; Integer parsing shortcut
; Used to split a string on digits to parse them out
l (fn [v] (split-with #(Character/isDigit %) v))
src (slurp a) ; Get the source
[n [_ & r]] (l src) ; Use deconstructuring to grab the first number
[m r] (l r) ; Same as above, grabbing the second number
n' (+ (p n) (p m)) ; Parse the 2 numbers, and add them
; Put everything back together, only this time with the new numbers
k (str (p m) " " n' (u r))]
(println n') ; Print the new number
(spit a k)) ; Overwrite the old source


Python 3.8 (pre-release), 73 bytes

b=c=1;exec(a:="print(b);open(*'aw').write(f'b,c={c,b+c};exec(a:=%r)'%a)")


filename should be a

Explanation

b=c=1;exec(a:="print(b);open(*'aw').write(f'b,c={c,b+c};exec(a:=%r)'%a)")
b=c=1                                                                      # Set b and c to 1
a:="print(b);open(*'aw').write(f'b,c={c,b+c};exec(a:=%r)'%a)"   # Set a to the string and return it
exec(                                                             )  # Execute a as python code
print(b)                                                    # Prints b
open(*'aw')                                        # Opens a files named a in write mode
f'b,c={c,b+c};exec(a:=%r)'%a     # String Formatting: 'b,c=(<c>,<b+c>);exec(a:="<a>")'
.write(                            )    # Write the string to the file


Try it online!