Теория языков программирования
Расширяемость языков
Kotlin extension functions и Swift protocols - это не просто syntactic sugar. Это фундаментально новый способ расширять чужой код без наследования. LSP изменил как создаются языки - IDE поддержка больше не требует команды IDE-разработчиков.
- **rust-analyzer**: LSP сервер для Rust. Один сервер -> поддержка в VS Code, IntelliJ, Neovim, Emacs, Helix. 5M+ пользователей
- **Arrow (Kotlin FP library)**: использует extension functions для добавления функциональных операторов к стандартным типам. monoid(), traverse() прямо на List<T>
- **TypeScript language server**: используется в VS Code, но также в Vim, Emacs, Sublime. Microsoft открыл LSP - теперь конкурирующие редакторы используют их сервер
Перегрузка операторов
Перегрузка операторов позволяет определить поведение стандартных операторов (+, -, *, ==, <) для пользовательских типов. Делает код математически интуитивным для числовых типов, векторов, матриц. Python использует dunder методы (__add__, __mul__).
Злоупотребление перегрузкой создаёт непонятный код. Python datetime + timedelta - интуитивно. C++ Matrix << Vector - непонятно. Правило: перегружай только если оператор семантически очевиден для типа.
Когда перегрузка операторов оправдана, а когда нет?
Протоколы и Type Classes
Протоколы (Swift/Elixir) и Type Classes (Haskell) - способ определить интерфейс без наследования. Любой тип может реализовать протокол ретроактивно - даже встроенные типы. Это мощнее ООП интерфейсов.
Что такое ретроактивная conformance и почему это мощнее ООП наследования?
Extension Methods
Extension methods (C#, Swift, Kotlin) позволяют добавлять методы к существующим типам без наследования и без изменения оригинального кода. Это форма ретроактивного расширения без полного protocol системы.
Чем Kotlin extension functions отличаются от реального добавления метода в класс?
Language Server Protocol
LSP (Language Server Protocol) - стандарт для коммуникации между IDE и language-specific серверами. Microsoft разработал для VS Code в 2016. Теперь любой язык с LSP реализацией получает IDE поддержку в 100+ редакторах.
IDE поддержка нового языка - огромная работа на годы
С LSP: реализовать language server достаточно для поддержки в VS Code, Neovim, Emacs, IntelliJ, Sublime. Это несколько месяцев, не лет
Gleam (новый функциональный язык) имел LSP поддержку с первого стабильного релиза. Раньше это было немыслимо для молодого языка
Какую проблему решает LSP?
Итоги
- **Перегрузка операторов**: для математических типов - интуитивно. Избегать семантически неясных операторов
- **Протоколы и type classes**: ретроактивная conformance без наследования. Любой тип можно сделать Describable/Show
- **Extension methods**: статические методы с синтаксическим сахаром. Нет доступа к private - это статический dispatch
- **LSP**: устраняет n*m проблему IDE интеграции. Один language server -> поддержка в 100+ редакторах
Связанные темы
Расширяемость связана с типами и метапрограммированием:
- ООП теория — Протоколы vs наследование - два разных подхода к полиморфизму
- Type-safe API — Phantom types и branded types - расширение через систему типов
Вопросы для размышления
- Rust traits = Haskell type classes = Swift protocols. Все три решают одну проблему по-разному. Как они отличаются по expressiveness и когда это важно?
- LSP изменил экономику создания языков. Раньше успех нового языка зависел от качества IDE плагина. Сейчас - от качества language server. Как это повлияло на появление новых языков?
- Extension methods в Kotlin - синтаксический сахар над статическими функциями. Haskell type classes - генерируют dict-passing в runtime. Какой подход лучше и почему?