Теория языков программирования
Теория объектно-ориентированного программирования
ООП - самая популярная парадигма, но и самая неправильно понятая. 90% кода на Java/Python/C++ - это ООП по синтаксису, но не по смыслу. Алан Кей, создатель термина ООП, говорил, что имел в виду messaging, а не классы и наследование.
- **Smalltalk**: исходное ООП по Кею - объекты обмениваются сообщениями, нет разницы между методом и сообщением. Всё в Smalltalk - объект, включая классы
- **Swift Protocol-Oriented Programming**: Apple отказалась от deep inheritance в пользу protocol composition, что сделало UIKit заменимым на SwiftUI без переписывания логики
- **Entity Component System (ECS)**: игровые движки (Unity DOTS, Bevy) отказались от ООП иерархий в пользу composition - 10-100x прирост производительности за счёт cache locality
Инкапсуляция
Инкапсуляция - это не просто сокрытие полей за private. Это разделение интерфейса (что объект умеет) и реализации (как он это делает). Клиентский код зависит только от интерфейса - реализация может меняться без его изменения. Это называется принцип сокрытия информации (information hiding) Парнаса, 1972.
Анемичная доменная модель (Fowler) - антипаттерн, где объекты - это просто DTO с геттерами/сеттерами, а вся логика в сервисах. Это ООП по форме, но не по существу.
В чём разница между инкапсуляцией и просто объявлением поля private?
Наследование против композиции
Наследование создаёт жёсткую связь IS-A: Dog IS-A Animal. При глубоких иерархиях малейшее изменение в базовом классе ломает всех наследников. Банан-проблема Джо Армстронга: хотел банан, получил гориллу с бананом и весь джунгль.
Почему Stack, унаследованный от ArrayList, считается примером плохого наследования?
Виртуальная таблица (vtable)
Vtable (virtual method table) - механизм реализации полиморфизма в C++/Java. Каждый класс с виртуальными методами имеет vtable - массив указателей на методы. Каждый объект хранит указатель на vtable своего класса (vptr). Вызов виртуального метода: dereference vptr, jump по индексу.
Цена vtable dispatch: ~5 наносекунд на современном CPU, но главная проблема - branch misprediction при polymorphic calls. V8 и JVM решают это inline caching: запоминают последний тип и генерируют быстрый путь для него.
Что хранится в vtable и зачем?
Multiple Dispatch
Single dispatch (классический ООП полиморфизм) выбирает метод по типу одного объекта (receiver). Multiple dispatch выбирает по типам всех аргументов. Классическая проблема: `collide(Shape a, Shape b)` - нужен разный код для Circle-Circle, Circle-Rectangle, Rectangle-Rectangle.
Visitor паттерн - удачное решение проблемы double dispatch в Java
Visitor - это workaround для отсутствия multiple dispatch, а не полноценное решение
В языках с native multiple dispatch (Julia, CLOS, Dylan) Visitor не нужен вообще. Visitor добавляет сложность ради симуляции того, что могло быть встроено в язык
Чем multiple dispatch отличается от single dispatch?
Ключевые идеи
- **Инкапсуляция** - защита инвариантов через осмысленный интерфейс, не просто private поля с геттерами
- **Композиция лучше наследования** - наследование уместно только при истинном IS-A отношении. Vtable dispatch ~5ns, но главная цена - branch misprediction
- **Multiple dispatch** - выбор метода по типам всех аргументов. В ООП языках обходится через Visitor (паттерн-костыль)
- **Vtable** - каждый объект хранит vptr на таблицу виртуальных методов своего класса
Связанные темы
ООП взаимодействует с типами и компилятором:
- Мультипарадигменные языки — Scala, Kotlin, Swift совмещают ООП с ФП - когда и что использовать
- Генерация кода и vtable — Компилятор генерирует vtable layout и call sequences
Вопросы для размышления
- Алан Кей говорил, что наибольшая ошибка в ООП - это то, что оно стало про классы, а не про сообщения. Как бы выглядело ООП, если бы фокус был на messaging?
- Entity Component System в игровых движках - это антипаттерн с точки зрения ООП, но выигрыш в производительности 100x. Как вы выбираете между архитектурной чистотой и производительностью?
- Почему в большинстве языков single dispatch, если multiple dispatch выразительнее?