Розділ 12. Вавилон мов
Сім сотень
За підрахунками сайту HOPL (History of Programming Languages, який веде Шотландський університет Глазго), у світі за всю історію існувало близько 8945 мов програмування. З них сьогодні активно використовується — близько 700. У продакшні великих компаній — близько 50. На щоденній основі більшість програмістів пише на 5-10.
Але цих п’яти-десяти теж занадто багато. JavaScript, Python, Java, C, C++, C#, Go, Rust, Swift, TypeScript, PHP, Ruby — кожна заявляє про себе як про “правильну”. Кожна з мільйонами користувачів. Кожна з власною екосистемою бібліотек, конференцій, книг, культурних кодів.
Чому? Якщо мови — це інструменти для опису обчислень, чому ми не зробили одну добру мову, як зробили один добрий протокол інтернету (TCP/IP) чи один добрий формат JSON?
Це питання — серце цього розділу. Відповідь, на жаль, складніша, ніж нам би хотілося.
Коротка історія мовного зоопарку
Перш ніж зрозуміти, чому їх так багато, треба побачити, звідки вони з’являлися.
1950-ті: початок. - Fortran (1957,
IBM, Джон Бекус). Перша високорівнева мова. Ідея: писати математику
замість асемблера. Жива досі — у науковому обчисленні. -
COBOL (1959, Грейс Гоппер). Для бізнесу. Англомовний
синтаксис:
MULTIPLY HOURS-WORKED BY HOURLY-WAGE GIVING GROSS-PAY. Жива
у банках і державних системах. Уряд США досі (2024) перекладає
COBOL-системи на Java. - LISP (1958, Джон Маккарті).
Для штучного інтелекту, рекурсії, символьних обчислень. Принципово інша
парадигма: вся програма — це список. Вплинула на майже всі сучасні
функціональні мови.
1960-ті: розбудова. - ALGOL 60 (1960). Структуроване програмування, блоки, рекурсія. Не виграла комерційно, але вплинула на всі наступні мови (C, Pascal, Java — нащадки). - BASIC (1964, Дартмут). Для початківців. Стане мовою, на якій навчилися перші мільйони людей з домашніми комп’ютерами 1980-х. - Simula (1967). Перша об’єктно-орієнтована мова. Тоді мало хто помітив. Через 15 років концепцію об’єктів запозичить C++.
1970-ті: вибух. - Pascal (1970, Ніклаус Вірт). Для викладання структурованого програмування. Стандарт у школах і університетах 1980-х. - C (1972, Деніс Рітчі). Уже знаємо. - Smalltalk (1972, Алан Кей у Xerox PARC). Чисто об’єктно-орієнтована. Жодного успіху комерційно, але вплинула на все — Java, Python, Ruby, JavaScript узяли свою OOP-парадигму звідси. - Prolog (1972). Логічне програмування. Замість “як обчислити” — “що ми знаємо і що шукаємо”. Жива у нішах (експертні системи, NLP). - SQL (1974, IBM). Не мова загального призначення, але важлива. Перша спроба декларативного програмування — кажеш що ти хочеш отримати, не як.
1980-ті: професіоналізація. - C++ (1985, Бьярн Страуструп у Bell Labs). C з об’єктами. Швидко став мовою системного програмування з ООП. - Objective-C (1984). C з повідомленнями в стилі Smalltalk. Apple використає її для NeXT, потім macOS, потім iOS. - Perl (1987, Ларрі Волл). “Швейцарський ножик” для текстових скриптів. Стане “клейкою стрічкою інтернету” в 1990-х. - Erlang (1986, Ericsson). Для телекомунікаційних систем — паралельність, надійність, hot reloading. Жива у Discord, WhatsApp, Goldman Sachs. - HyperTalk (1987, Apple). Скриптова мова HyperCard. Тут вперше з’явилася ідея, що з програмуванням можна “грати”, не вивчаючи синтаксису.
1990-ті: інтернет. - Python (1991, Гвідо ван Россум). Простий синтаксис, читабельність як цінність. Через 30 років стане мовою #1 у світі. - Java (1995, Sun Microsystems, Джеймс Гослінг). “Write once, run anywhere”. Корпоративний стандарт. - JavaScript (1995, Брендан Айк у Netscape, за 10 днів). Для оживлення веб-сторінок. Ніхто не думав, що це стане найпоширенішою мовою світу. - PHP (1995, Расмус Лердорф). Спочатку для особистого сайту. Стане основою половини інтернету (WordPress, Facebook у молодості, Wikipedia, Slack — все писалось на PHP). - Ruby (1995, Юкіхіро Мацумото в Японії). Створена для радості програміста. Вибухне в 2005-му з фреймворком Ruby on Rails. - OCaml (1996), Haskell (1990). Чисто функціональні. Любимі академіками. Майже не використовуються в індустрії.
2000-ні: прагматизм. - C# (2000, Microsoft, Андерс Хейлсберг — той самий, що Turbo Pascal колись робив). “Java для Microsoft”. Виросла, переросла Java у багатьох аспектах. - Scala (2003). Функціональна на JVM. Любима у фінансах і Twitter колись. - Groovy (2003). Скриптова на JVM. - F# (2005). OCaml для .NET. - Clojure (2007). Lisp на JVM.
2010-ті: пост-моноліт. - Go (2009, Google, Роб Пайк, Кен Томпсон, Роберт Грізмер). “C для хмари”. Простий, швидкий, з горутинами. Docker, Kubernetes, Terraform — все на Go. - Rust (2010, Mozilla). “C++ без помилок”. Через 10 років стане мовою-улюбленцем системних програмістів. - Kotlin (2011, JetBrains). “Java без болю”. У 2017 Google зробив Kotlin офіційною мовою Android. - TypeScript (2012, Microsoft, той самий Андерс Хейлсберг!). “JavaScript з типами”. Захопила фронтенд за 5 років. - Swift (2014, Apple, Кріс Латтнер). Заміна Objective-C для iOS і macOS. - Elixir (2011). Erlang з красивим синтаксисом. - Crystal (2014). Ruby з типами і компіляцією. - Nim, Zig, D, V — всі намагаються бути “C/C++, але краще”.
2020-ті: AI-епоха. - Mojo (2023, Modular, Кріс Латтнер знову). “Python зі швидкістю C для AI”. - Roc (2022, Річард Фельдман). Чисто функціональна, дружній синтаксис. - Gleam (2019). Функціональна на BEAM (Erlang VM). - Carbon (2022, Google). “C++ наступного покоління”.
Це далеко не вичерпний список. Але вже — десятки активних мов. Чому?
Чотири осі вибору
Якщо подивитися на мову з висоти, кожна — це відповідь на чотири головні питання. Різні відповіді = різні мови.
Вісь 1. Як керувати пам’яттю?
- Ручне керування. Програміст сам виділяє і звільняє. Швидко, але небезпечно. Приклади: C, C++.
- Автоматичний garbage collector (GC). Спеціальний механізм періодично знаходить і звільняє непотрібну пам’ять. Зручно, але повільно (паузи). Приклади: Java, C#, Go, Python, Ruby, JavaScript.
- Reference counting. Кожен об’єкт лічить, скільки на нього посилань. Коли посилань нема — звільняється. Приклади: Swift, Objective-C, Python (часткова).
- Ownership system. Компілятор статично перевіряє, хто володіє пам’яттю. Звільнення вставляється автоматично. Приклади: Rust.
Вісь 2. Який тип системи?
- Динамічна. Типи перевіряються під час виконання.
Зручно писати, можна сказати
x = 5; x = "hello";— мова не заперечує. Помилки знаходяться у продакшні. Приклади: Python, JavaScript, Ruby. - Статична. Типи перевіряються компілятором. Більше коду писати, менше помилок у продакшні. Приклади: Java, C#, Go, Rust, Swift, TypeScript.
- Сильна / слабка. Якщо
1 + "2"= “12”, це слабка типізація. Якщо це помилка — сильна. JavaScript — слаба. Python — сильна, але динамічна. - З виведенням типів. Компілятор сам угадує типи з
контексту.
let x = 5;— ясно, що це int. Приклади: Rust, Swift, Haskell, OCaml, Kotlin.
Вісь 3. Яка модель паралелізму?
- Потоки + мютекси. Класика. Складно, помилково. Приклади: C, C++, Java.
- Async/await. Кооперативний паралелізм. Зручно для I/O. Приклади: JavaScript, Python (новіші), C# (історично перші), Rust.
- Горутини / Channels. “Не діліться пам’яттю — діліться через канали”. Приклад: Go.
- Актори. Кожен потік — це актор з власною пам’яттю, спілкуються через повідомлення. Приклади: Erlang, Elixir, Akka (на Scala).
- Нічого. Однопотокова мова. Приклади: JavaScript у браузері, Python (з GIL), PHP.
Вісь 4. Яка парадигма мислення?
- Імперативна. Кажеш машині крок за кроком, що робити. Найприродніше для людини.
- Об’єктно-орієнтована. Все — це об’єкти, які обмінюються повідомленнями. Smalltalk, Java, Ruby.
- Функціональна. Все — це функції без побічних ефектів. Lisp, Haskell, Clojure.
- Логічна. Кажеш факти і запити. Машина шукає відповідь. Prolog.
- Декларативна. Кажеш що хочеш, не як. SQL, HTML, CSS.
- Гібридна. Більшість сучасних мов — суміш кількох. Python — імперативна + ООП + трохи функціональної. JavaScript — те саме.
Чотири осі × приблизно 4-5 варіантів кожної = десятки можливих комбінацій. Кожна має свій оптимальний варіант. Кожна має свою мову.
Чому ми не маємо “одну мову”
Подивимось на суто прагматичну сторону. Чому б не зробити одну мову, яка б замінила всі інші?
Кілька серйозних причин.
Причина 1: Різні задачі вимагають різних абстракцій.
Веб-фронтенд: треба JavaScript / TypeScript (бо тільки він працює у браузері). Системне програмування: треба C, C++, або Rust (бо треба контроль над пам’яттю). Веб-бекенд: можна Python, Node.js, Java, Go — будь-що, що може обслуговувати HTTP. Машинне навчання: Python (бо там бібліотеки). Embedded: C (бо там залізо). Бази даних: SQL (бо нічого кращого). Скриптинг: Bash, Python. Мобільний iOS: Swift. Мобільний Android: Kotlin.
Кожна задача має свої вимоги — оптимізована мова під неї виграє.
Причина 2: Шлях залежності.
Раз ти написав код на одній мові — ти в неї інвестував. Бібліотеки, інструменти, знання команди. Перейти на іншу мову — означає переписати все. Це вартує мільйонів. Тому компанії тримаються своєї мови, навіть якщо вона “не найкраща”.
Приклад: COBOL. Жахлива мова з 1959 року. Ніхто молодий не хоче нею писати. Але банки тримають мільярди рядків COBOL-коду, який обслуговує трильйони доларів транзакцій щодня. Переписати — неможливо. Ризик занадто великий.
Причина 3: Вендор-лок.
Microsoft створила C# і F#. Apple — Swift і Objective-C. Google — Go і Dart. Кожна велика компанія робить свою мову, щоб прив’язати розробників до своєї платформи. Це бізнес-стратегія, не технічне рішення.
Причина 4: “Not Invented Here” синдром.
Великі компанії і університети мають велике его. “Якщо це не наша мова — нам не цікаво”. Тому Microsoft не використовує Java. Apple не використовує C#. Google створив Go замість використати Rust. І так далі.
Причина 5: Розробники мають уподобання.
Програмісти емоційно прив’язані до своїх мов. У них є ідентичність (“я Python-програміст”, “я Rust-розробник”). Війни мов у соцмережах, мемах, конференціях. Це майже релігія. І нова мова, яка хоче перемогти всіх — не зможе, бо всі вже у своїх таборах.
Причина 6: Експерименти потрібні.
Ми не знаємо, як виглядатиме ідеальна мова майбутнього. Тому потрібні різні експерименти. Lisp у 1958-му був експериментом — і його ідеї досі живуть у сучасних мовах. Erlang був експериментом — і це джерело акторської моделі. Кожна нова мова — це гіпотеза про те, як треба думати про програмування. Деякі не приживуться. Деякі стануть стандартом.
Чи є з цього вихід
Чесна відповідь: ні. В осяжному майбутньому мов буде так само багато або й більше.
Але є тенденції, які можна побачити.
Тенденція 1: Консолідація навколо кількох “переможців”.
Кожна ніша поступово знаходить свого лідера: - Веб-фронтенд: TypeScript. - Бекенд: Java + Python + Go (трійка лідерів). - Системне: Rust зростає, C/C++ ще тримають. - Мобільний iOS: Swift. - Мобільний Android: Kotlin. - ML: Python (і ще довго). - Скриптинг: Python, Bash. - Бази даних: SQL.
Тобто є ~10 мейнстрім-мов. Решта — нішеві.
Тенденція 2: Мультимовні системи стають нормальними.
Сучасний продукт — це не “мова X”, а поєднання мов. Наприклад, типовий веб-додаток: - Frontend на TypeScript. - Backend на Python (для AI), Go (для високих навантажень), Rust (для критичних компонентів). - Інфраструктура на YAML, HCL (Terraform). - База даних на SQL. - Скрипти на Bash і Python.
Це нормально. Не “виберіть мову”, а спроектуйте мовну композицію під задачу.
Тенденція 3: AI як абстракція над мовами.
Це найцікавіше. Зараз AI вже може писати код на будь-якій мові з опису задачі. Через 5-10 років, можливо, конкретна мова стане деталлю реалізації. Ти кажеш: “напиши мені веб-сервер з аутентифікацією”. AI вибирає мову, пише код, запускає. Тобі — байдуже, чи це Go, чи Rust.
Якщо це станеться — кількість мов перестане бути проблемою. Користувачі — це AI, а не люди. AI добре читає всі мови.
Тенденція 4: Domain-specific languages (DSL).
Замість великих мов загального призначення — маленькі спеціальні мови для конкретних задач: - CSS — для стилів. - SQL — для запитів. - GLSL/HLSL — для шейдерів. - Solidity — для смарт-контрактів. - Terraform HCL — для інфраструктури.
Цих DSL стає більше і більше. Багато з них вбудовуються в основну мову (DSL-ом може бути функція в Python).
Що в цьому всьому добре і що погано
Добре: - Різноманіття дозволяє експериментувати, шукати кращих рішень. - Кожна задача знаходить оптимальну мову. - Інновації не зупиняються. - Ринок праці гнучкий — програміст може вибирати свою спеціалізацію.
Погано: - Фрагментація екосистем. Бібліотека, написана на Rust, недоступна напряму з Python. Треба обгортки. - Дублювання. Одна й та сама бібліотека для роботи з JSON існує у 50 мовах. Кожна реалізація має свої баги. - Криза кадрів. Знайти експерта одночасно з Python, Go, Rust і Kotlin — майже неможливо. - Війни. Програмісти витрачають енергію на захист своєї мови, а не на створення корисного. - Мобільність коду. Якщо команда вирішила переписати з Python на Rust — це місяці-роки роботи.
А що з PDP-11?
Згадаймо попередній розділ. Майже всі сучасні мови — нащадки C, тобто PDP-11. Тобто за всім цим різноманіттям ховається одна спільна модель: процесор + лінійна пам’ять + послідовні інструкції.
Жодна з мейнстрім-мов не визнає сучасне залізо чесно. Усі вдають, що під ними — той самий PDP-11.
Винятки: - CUDA і OpenCL — для GPU. Визнають паралелізм як основу. - Шейдерні мови (GLSL, HLSL) — теж паралельні. - Erlang/Elixir — визнають розподіленість (актори). - Halide (мова для обробки зображень) — визнає кеш-ієрархію.
Усе це — DSL для конкретних задач. Загальної мови, яка б природно описувала сучасне залізо, досі немає.
Це і є відкрита проблема всієї індустрії. Можливо, наступні великі мови (Mojo? щось ще?) спробують її розв’язати. Можливо, AI стане шаром, який бере наш PDP-11-код і трансформує його під реальне залізо. Можливо, нічого не зміниться, і ми житимемо у цій вежі ще 50 років.
Що з цього винести
- У світі близько 700 активних мов програмування, з яких реально використовується 5-10.
- Кожна мова — це відповідь на чотири головні питання про пам’ять, типи, паралелізм і парадигму.
- Мов багато, бо різні задачі вимагають різних абстракцій + шлях залежності + вендор-лок + людська природа.
- Однієї універсальної мови не буде. Замість цього — мультимовні системи і доменно-специфічні мови.
- AI може стати абстракцією над мовами через 5-10 років — ти описуєш задачу, AI вибирає мову.
- Усі сучасні мови — нащадки C / PDP-11. Ніхто не описує сучасне залізо чесно. Це відкрита проблема індустрії.
Цим розділом закінчується Частина III. Ми пройшли програмний шар: від народження Unix у 1969-му через мовну Вавилонську вежу до боротьби моноліту з мікроядром.
У Частині IV — найважливіша. Що далі? Як зробити системи, яким можна довіряти? Що таке формальна верифікація? Як seL4 виглядає всередині? Що таке capability-based безпека? І як штучний інтелект, який щодня стає розумнішим, зустрічається з голим залізом — і що з цього виходить?
Це фінал книги. І це — найоптимістичніша її частина. Бо до цього ми описували проблеми. Тепер опишемо, як їх можливо вирішити.