brainfuckで関数スタイルとクラススタイルの比較

@silver801 さんが投稿された「[Pythonでbrainfuckインタプリタ(楔形文字も出る)](https://qiita.com/silver801/items/418a4f13b559d91bbb4a)」を拝見しました。

> Pythonにはswitch-caseみたいなやつがないのでif-else祭りになりました。if-else節が長くなるときは一般にはdictを使えと言われてるけど、こういうとき（パターンマッチの後にいろいろ処理を書きたいとき）はどうするのがいいんだろうか？

とのことなので、処理を関数化してdictにしてみました。

### 関数スタイル

```py
import sys

class Brain:
    pass

def inc(brain):
    brain.mem[brain.ptr] += 1

def dec(brain):
    brain.mem[brain.ptr] -= 1

def fore(brain):
    brain.ptr += 1
    if brain.ptr > len(brain.mem):
        print("overflow!")
        sys.exit(1)

def back(brain):
    if brain.ptr == 0:
        print("Can't decrement anymore")
    brain.ptr -= 1

def putc(brain):
    # chr: char -> code point
    print(chr(brain.mem[brain.ptr]), end="")  # no line break

def getc(brain):
    # ord: code point -> char
    brain.mem[brain.ptr] = ord(sys.stdin.buffer.read(1))

def begin(brain):
    if brain.mem[brain.ptr] == 0:
        nest = 1
        while nest != 0:
            brain.head += 1
            if brain.head == len(brain.code):
                print("']' is missing")
                sys.exit(1)
            if brain.code[brain.head] == '[':
                nest += 1
            elif brain.code[brain.head] == ']':
                nest -= 1

def end(brain):
    if brain.mem[brain.ptr] != 0:
        nest = 1
        while nest != 0:
            brain.head -= 1
            if brain.head < 0:
                print("'[' is missing")
            if brain.code[brain.head] == ']':
                nest += 1
            elif brain.code[brain.head] == '[':
                nest -= 1

def nop(brain):
    pass  # ignore other symbol

def brainfuck(code, mem_size=30000):
    operations = {
        "+": inc,    # increment the value at the pointer.
        "-": dec,    # decrement the value at the pointer.
        ">": fore,   # increment the pointer.
        "<": back,   # decrement the pointer.
        ".": putc,   # output the value at the  pointer as utf-8 character.
        ",": getc,   # accept one byte of input, storing its value in the mem at the  pointer.
        "[": begin,  # if the byte at the pointer is zero, then jump it to the matching ']'
        "]": end,    # if the byte at the pointer is nonzero, then jump it buck to the matching '['
    }
    brain = Brain()
    brain.code = code
    brain.mem = [0] * mem_size
    brain.ptr = 0
    brain.head = 0  # (tape reading) head
    while brain.head < len(code):
        operations.get(code[brain.head], nop)(brain)
        brain.head += 1


def main():
    args = sys.argv
    if len(args) < 2:
        code = sys.stdin.read()
    else:
        path = args[1]
        with open(path) as f:
            code = f.read()
    brainfuck(code)

if __name__ == "__main__":
    main()
```

データと関数がバラバラに定義されています。
データと関数をまとめてクラスにしてみます。

### クラススタイル

```py
import sys

class Brain:


    def inc(self):
        self.mem[self.ptr] += 1

    def dec(self):
        self.mem[self.ptr] -= 1

    def fore(self):
        self.ptr += 1
        if self.ptr > len(self.mem):
            print("overflow!")
            sys.exit(1)

    def back(self):
        if self.ptr == 0:
            print("Can't decrement anymore")
        self.ptr -= 1

    def putc(self):
        # chr: char -> code point
        print(chr(self.mem[self.ptr]), end="")  # no line break

    def getc(self):
        # ord: code point -> char
        self.mem[self.ptr] = ord(sys.stdin.buffer.read(1))

    def begin(self):
        if self.mem[self.ptr] == 0:
            nest = 1
            while nest != 0:
                self.head += 1
                if self.head == len(self.code):
                    print("']' is missing")
                    sys.exit(1)
                if self.code[self.head] == '[':
                    nest += 1
                elif self.code[self.head] == ']':
                    nest -= 1

    def end(self):
        if self.mem[self.ptr] != 0:
            nest = 1
            while nest != 0:
                self.head -= 1
                if self.head < 0:
                    print("'[' is missing")
                if self.code[self.head] == ']':
                    nest += 1
                elif self.code[self.head] == '[':
                    nest -= 1

    def nop(self):
        pass  # ignore other symbol

    def fuck(self, code, mem_size=30000):
        operations = {
            "+": self.inc,    # increment the value at the pointer.
            "-": self.dec,    # decrement the value at the pointer.
            ">": self.fore,   # increment the pointer.
            "<": self.back,   # decrement the pointer.
            "[": self.begin,  # if the byte at the pointer is zero, then jump it to the matching ']'
            "]": self.end,    # if the byte at the pointer is nonzero, then jump it buck to the matching '['
            ".": self.putc,   # output the value at the  pointer as utf-8 character.
            ",": self.getc,   # accept one byte of input, storing its value in the mem at the  pointer.
        }
        self.code = code
        self.mem = [0] * mem_size
        self.ptr = 0
        self.head = 0
        while self.head < len(code):
            operations.get(code[self.head], self.nop)()
            self.head += 1


def main():
    args = sys.argv
    if len(args) < 2:
        code = sys.stdin.read()
    else:
        path = args[1]
        with open(path) as f:
            code = f.read()
    Brain().fuck(code)

if __name__ == "__main__":
    main()
```

### 比較

横並びにして比較してみましょう。

```py
import sys                                                  import sys
                                                            
class Brain:                                                class Brain:
    pass                                                    
                                                            
def inc(brain):                                                 def inc(self):
    brain.mem[brain.ptr] += 1                                       self.mem[self.ptr] += 1
                                                            
def dec(brain):                                                 def dec(self):
    brain.mem[brain.ptr] -= 1                                       self.mem[self.ptr] -= 1
                                                            
def fore(brain):                                                def fore(self):
    brain.ptr += 1                                                  self.ptr += 1
    if brain.ptr > len(brain.mem):                                  if self.ptr > len(self.mem):
        print("overflow!")                                              print("overflow!")
        sys.exit(1)                                                     sys.exit(1)
                                                            
def back(brain):                                                def back(self):
    if brain.ptr == 0:                                              if self.ptr == 0:
        print("Can't decrement anymore")                                print("Can't decrement anymore")
    brain.ptr -= 1                                                  self.ptr -= 1
                                                            
def putc(brain):                                                def putc(self):
    # chr: char -> code point                                       # chr: char -> code point
    print(chr(brain.mem[brain.ptr]), end="")                        print(chr(self.mem[self.ptr]), end="")
                                                            
def getc(brain):                                                def getc(self):
    # ord: code point -> char                                       # ord: code point -> char
    brain.mem[brain.ptr] = ord(sys.stdin.buffer.read(1))            self.mem[self.ptr] = ord(sys.stdin.buffer.read(1))
                                                            
def begin(brain):                                               def begin(self):
    if brain.mem[brain.ptr] == 0:                                   if self.mem[self.ptr] == 0:
        nest = 1                                                        nest = 1
        while nest != 0:                                                while nest != 0:
            brain.head += 1                                                 self.head += 1
            if brain.head == len(brain.code):                               if self.head == len(self.code):
                print("']' is missing")                                         print("']' is missing")
                sys.exit(1)                                                     sys.exit(1)
            if brain.code[brain.head] == '[':                               if self.code[self.head] == '[':
                nest += 1                                                       nest += 1
            elif brain.code[brain.head] == ']':                             elif self.code[self.head] == ']':
                nest -= 1                                                       nest -= 1
                                                            
def end(brain):                                                 def end(self):
    if brain.mem[brain.ptr] != 0:                                   if self.mem[self.ptr] != 0:
        nest = 1                                                        nest = 1
        while nest != 0:                                                while nest != 0:
            brain.head -= 1                                                 self.head -= 1
            if brain.head < 0:                                              if self.head < 0:
                print("'[' is missing")                                         print("'[' is missing")
            if brain.code[brain.head] == ']':                               if self.code[self.head] == ']':
                nest += 1                                                       nest += 1
            elif brain.code[brain.head] == '[':                             elif self.code[self.head] == '[':
                nest -= 1                                                       nest -= 1
                                                            
def nop(brain):                                                 def nop(self):
    pass                                                            pass
                                                            
def brainfuck(code, mem_size=30000):                            def fuck(self, code, mem_size=30000):
    operations = {                                                  operations = {
        "+": inc,                                                       "+": self.inc,    
        "-": dec,                                                       "-": self.dec,    
        ">": fore,                                                      ">": self.fore,   
        "<": back,                                                      "<": self.back,   
        ".": putc,                                                      "[": self.begin,  
        ",": getc,                                                      "]": self.end,    
        "[": begin,                                                     ".": self.putc,   
        "]": end,                                                       ",": self.getc,   
    }                                                               }
    brain = Brain()                                         
    brain.code = code                                               self.code = code
    brain.mem = [0] * mem_size                                      self.mem = [0] * mem_size
    brain.ptr = 0                                                   self.ptr = 0
    brain.head = 0                                                  self.head = 0
    while brain.head < len(code):                                   while self.head < len(code):
        operations.get(code[brain.head], nop)(brain)                    operations.get(code[self.head], self.nop)()
        brain.head += 1                                                 self.head += 1
                                                            
def main():                                                 def main():
    args = sys.argv                                             args = sys.argv
    if len(args) < 2:                                           if len(args) < 2:
        code = sys.stdin.read()                                     code = sys.stdin.read()
    else:                                                       else:
        path = args[1]                                              path = args[1]
        with open(path) as f:                                       with open(path) as f:
            code = f.read()                                             code = f.read()
    brainfuck(code)                                             Brain().fuck(code)
                                                            
if __name__ == "__main__":                                  if __name__ == "__main__":
    main()                                                      main()
```

Brainの中のbrainは自分自身なのでselfという名称にするのが一般的ですが、
brain のままにすれば、ほとんど一緒ですね。