We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.
Talk:Immutable Brainfuck
Input EOF
What should , do in case of EOF? --Blashyrkh (talk) 09:30, 25 August 2026 (UTC)
- Thanks for pointing that out. The tape should remain unchanged. I added it to the spec. --Rainwave (talk) 09:41, 25 August 2026 (UTC)
- Actually, nevermind. That'd break reversibility. I changed it to EOF = 0 instead. --Rainwave (talk) 09:44, 25 August 2026 (UTC)
- If reversibility is mandatory, you may insert 9 bits ('0', ascii-code) or single '1' bit in case of EOF.--Blashyrkh (talk) 09:51, 25 August 2026 (UTC)
- Possible, but I personally think EOF = 0 is cleaner for the language spec. It's also the way Reversible Brainfuck handles EOF. --Rainwave (talk) 10:00, 25 August 2026 (UTC)
- If reversibility is mandatory, you may insert 9 bits ('0', ascii-code) or single '1' bit in case of EOF.--Blashyrkh (talk) 09:51, 25 August 2026 (UTC)
- Actually, nevermind. That'd break reversibility. I changed it to EOF = 0 instead. --Rainwave (talk) 09:44, 25 August 2026 (UTC)
Shorter "Hello, world!"
It prints "Hello, world!" string with newline (U+000A) at the end:
0010100011000010100100111001101110100111111110111111011110000010100110101111101110011011100110111101001110001001[0>.>>>>>>>>]
Thinking about quine... --Blashyrkh (talk) 22:40, 26 August 2026 (UTC)
"Tape"?
Should it be called "tape" due to insertion principle? It's rather far from how real (physical) tape works. Probably, it's two stacks: left stack and right stack. < pops value from the left stack and pushes to the right stack. > does the opposite. 0 and 1 pushes the corresponding value to the right stack. [ and ] examine the top value of the left stack. . combines 8-bit value from the top of the left stack and 7 top values from the right stack, and outputs it. , pushes 8 bits to the right stack. --Blashyrkh (talk) 08:13, 27 August 2026 (UTC)
- And looking from this perspective, one can notice how weird and asymmetric
.operation is. --Blashyrkh (talk) 08:59, 27 August 2026 (UTC) - Usually, tape (self-extending)=queue=two stacks. --None1 (Nope.) 11:58, 27 August 2026 (UTC)
- Shouldn't it be linked-list? I originally intended it to be some sort of growing array, so I used the standard BF terminology which is tape. --Rainwave (talk) 12:12, 27 August 2026 (UTC)
- Originally, the word "tape" comes from Turing Machine. Urban Muller didn't use the word, he called it "array" (https://gist.github.com/rdebath/0ca09ec0fdcf3f82478f, not sure whether it's the original code and not fake). So, it may be called neutrally "memory" or less-neutrally "linked list". --Blashyrkh (talk) 12:19, 27 August 2026 (UTC)
Shorter Truth-machine
,>.>>>>>>>[1]>[<<<<<<<<.>>>>>>>1>]
--Blashyrkh (talk) 20:37, 27 August 2026 (UTC)
Behavior of the . command
Read eight contiguous cells starting from the current cell, interpret them as a byte, and output them as a single ASCII character. Note that the pointer's position remains unchanged.
What if there are less than 8 cells starting from the current cell?
- They are considered as 0.
- Errors.
- UB
- Or...?
--None1 (Nope.) 08:09, 28 August 2026 (UTC)
--Blashyrkh (talk) 08:18, 28 August 2026 (UTC)the language operates on a right-unbounded tape, where the initial cells are all 0.
Interpreter
#! /usr/bin/env python3
import sys
if __name__=="__main__":
tape = [0]
pos = 0
prog = open(sys.argv[1], "rt").read()
ip = 0
while ip<len(prog):
match prog[ip]:
case ">":
pos += 1
if pos>=len(tape):
tape.append(0)
case "<":
pos -= 1
if pos<0:
tape.insert(0, 0)
pos += 1
case "[":
if tape[pos]==1:
d = 1
new_ip = ip+1
while d>0 and new_ip<len(prog):
if prog[new_ip]=="[":
d += 1
elif prog[new_ip]=="]":
d -= 1
new_ip += 1
if d>0:
sys.exit("Unmatched [")
ip = new_ip-1
case "]":
if tape[pos]==1:
d = 1
new_ip = ip-1
while d>0 and new_ip>=0:
if prog[new_ip]=="]":
d += 1
elif prog[new_ip]=="[":
d -= 1
new_ip -= 1
if d>0:
sys.exit("Unmatched ]")
ip = new_ip+1
case "1":
tape.insert(pos+1, 1)
case "0":
tape.insert(pos+1, 0)
case ".":
value = 0
for i in range(8):
if pos+i>=len(tape):
break
value |= (tape[pos+i]<<(7-i))
sys.stdout.buffer.write(bytes((value,)))
case ",":
inp = sys.stdin.buffer.read(1)
value = inp[0] if inp else 0
for _ in range(8):
tape.insert(pos+1, value&1)
value >>= 1
# case "#":
# print()
# print(" ".join("{0}{1}{2}".format("[" if i==pos else " ", tape[i], "]" if i==pos else " ") for i in range(len(tape))))
case _:
pass
ip += 1
The only difference with the specification (or clarification of UB if you like) is that my tape is unbounded in both directions. --Blashyrkh (talk) 08:23, 28 August 2026 (UTC)
- I wrote one in C++, too. --None1 (Nope.) 09:25, 28 August 2026 (UTC)
- Using ordinary std::list would be faster (O(1) vs O(logn)), but would introduce huge memory overhead (single std::list element with two 64-bit pointers, 1 byte payload and padding to hold 1 bit). --Blashyrkh (talk) 10:17, 28 August 2026 (UTC)
- Oh, I forgot that this esolang doesn't require random access memory. --None1 (Nope.) 10:20, 28 August 2026 (UTC)
- I'll add a version with std::list for the sake of portability. --None1 (Nope.) 10:40, 28 August 2026 (UTC)
- Done. --None1 (Nope.) 11:04, 28 August 2026 (UTC)