# OOP 何必是 COP (December 8, 2024)

tl;dr: 面向对象编程（Object-oriented programming）不必是面向类编程（Class-oriented programming）

像 JavaScript 这种，声明对象比声明类还方便的语言中，何必非要定义一个类，再定义实例呢？

从“和面向过程相对”的意义上说，“面向对象”指的是，封装的时候，去封装一个名词而不是封装一个动词。至于实现上，是去实现一个类，还是实现一个接口，其实都是 OOP

---

经常看到言论说 JavaScript 正在远离 OOP，事实上我觉得被远离的只是“OOP原教旨主义”，Java 之流那种

什么意思呢，我觉得 interface 就是定义了一个对象应该是什么 shape，比如，如果我是一个瞎子，只靠声音认狗狗🐕，只要你能汪汪叫就算你是狗 U•ェ•*U

那传统的继承式 OOP 就要求你老老实实界门纲目科属种，你得是继承了[动物界、脊椎动物门、哺乳动物纲、食肉目、犬科、犬属](https://zh.wikipedia.org/wiki/%E7%8A%AC)，但接口式的 OOP 只要求你能狗叫就行了，管你是 [京中有善口技者](https://baike.baidu.com/item/%E5%8F%A3%E6%8A%80/2193741)，还是音乐播放器，你都是狗。基于接口的 OOP 很显然就是更进步的、实用主义的 OOP

---

```typescript
interface DogLike {
  bark: () => "Woff"
};

function getDog(): DogLike {
  return {
    bark() {
      return "Woff"
    }
  }
}

const dog = getDog()

dog.bark()
```

这是面向过程吗？这也是面向对象。只要你在使用的时候不是在使用 `doBark(dog)` 而是 `dog.bark()` 你就是在 OOP 了。不需要用 `class` 只要你是在操作一个主体的方法，就是在 OOP

相对的，像这种

```typescript
class Dog {
  bark(): "Woff"
};

function doBark(dog: Dog) {
  return dog.bark()
}

dog = Dog()

doBark(dog)
```

这种才是披着面向对象外皮的面向过程编程。

---

是的，在我的定义中，Rust 也可以是 OOP。

---

说起来，前两天我一个[给 Gradio 的 PR](https://github.com/gradio-app/gradio/pull/10088) 被合了：

<img src="https://opengraph.githubassets.com/c790d44cd041450e184c1791a6a532657bd99d0044625f779cb15d9ad839405a/gradio-app/gradio/pull/10088" width="1200" title="null" crop="0,0,1,1" id="BZj2g" class="ne-image">

这个 PR 也挺好玩的，起因是我发现 Gradio 5 实现热重载了，我一直挺关心热重载的，包括我 py3.online 上也自己实现了一套热重载。我看它代码时发现它的方法差不多（都是在一个模块的 `__dict__` 中 exec 它的 sources），还支持一个 `NO_RELOAD` 的常量，`if gr.NO_RELOAD` 块中可以执行一些不想被热重载重新执行的代码。我觉得还蛮有意思的。然后我就在想：这个值是怎么做到动态的呢？是在热重载的时候直接改这个值，从 True 改成 False 吗？那如果人家不是用 `gr.NO_RELOAD` 而是直接用 `from gradio import NO_RELOAD` 这样的方式导入的呢？这样不就失去响应性了吗？

后来一读源码，发现更离谱，它甚至不是动态的 bool，而是通过 AST 搜索 `if gr.NO_RELOAD` 这样的出现，然后把整个 if 语句都删掉。我觉得这也太 hack 了，因为这导致这个 if 语句没法用 and / or 之类的结构，也没法用别名，甚至 else 子句也删了，也没法把这个 bool 当参数传给别处。而且这些，在文档里都没有描述。害人不浅啊（具体的坏处我 PR 里描述的更清楚）

于是，我的实现，简单来说就是把它编程一个伪 bool，让它的 `__bool__` 是动态的就行了。简单的话直接用 list 之类的东西就行，我是继承了 bool 类（简单来说是这样，但是 Python 里 bool 不让继承，所以其实我继承的是 int）（插播一条冷知识，Python 中 bool 也是 int 的子类哦），虽然我这样也 hack，但我至少不会造成奇奇怪怪的 bug

```python
class DynamicBoolean(int):
    def __init__(self, value: int):
        self.value = bool(value)

    def __bool__(self):
        return self.value

    def set(self, value: int):
        self.value = bool(value)
```

本来以为他们会不会对这个命名有异议的，但是居然没有。看来他们对贡献挺不 opinionated 的，毕竟也是[一个 utils.py 文件](https://github.com/gradio-app/gradio/blob/main/gradio/utils.py) 1500+ 行的项目。哈哈哈