Я программирую с восьми лет, и основную часть жизни был разработчиком в том или ином качестве. На протяжении своей жизни кодера, как любителя, так и профессионала, я изучил множество языков программирования, которые казались клонами друг друга. Но было и несколько языков, изменивших мой взгляд на программирование, а то и мышление в целом.

Я перечислю их в том порядке, в котором узнавал о них. В большинстве случаев я буду ассоциировать функциональность с языками, в которых они появились не впервые. Это не ошибка, я просто хочу показать, когда узнал об этих возможностях.

Basic


Язык, разработанный для того, чтобы сделать программирование простым.

  • Взрыв мозга: программирование собственных игр!
  • Взрыв мозга: массивы (или DIM, как они в нём назывались)!
  • Взрыв мозга: GOTO!
  • Взрыв мозга: GOSUB!

Первый Basic с нумерацией строк давно мёртв, но его наследие живёт в VB.Net, VBA, а также в современных динамических языках (Python, JavaScript и так далее).

(Turbo) Pascal


Наверно, этот язык сильнее всего повлиял на моё формирование как программиста. Подростком я выпустил несколько приложений на Turbo Pascal, в том числе и одно коммерческое (хотя, если откровенно, основную часть работы выполнил Алан Фриш).

  • Взрыв мозга: туториал по программированию!
  • Взрыв мозга: IDE!
  • Взрыв мозга: компилятор действительно помогает находить твои ошибки!
  • Взрыв мозга: по-настоящему полезный отладчик!
  • Взрыв мозга: структурированное программирование!
  • Взрыв мозга: юниты («модули»)!
  • Взрыв мозга: объектно-ориентированное программирование (хоть и не особо полезное в библиотеках)!
  • Взрыв мозга: тулкит для создания UI!
  • Взрыв мозга: динамическое распределение памяти!
  • Взрыв мозга: сообщество разработчиков (а также SWAGS)!
  • Взрыв мозга: оверлеи памяти!

Несколько лет спустя, всё ещё подростком, я попробовал перейти на C, и был немного разочарован, обнаружив, что, по сути, это такой же язык, только читать его сложнее (что за странный цикл for с тремя компонентами?), он больше подвержен ошибкам (дальние указатели? серьёзно?) и с зияющей нехваткой некоторых возможностей (как это так — нет модулей?), поэтому я не буду включать C в этот список.

Язык Pascal по-прежнему существует как Turbo Pascal, Lazarus Pascal и Delphi, но ещё и продолжил своё развитие в Ada (из-за его синтаксиса) и во всей существующей документации (JavaDoc, rustdoc, Sphinx, Doxygen и так далее), ведь первый инструмент для разработки документации (WEB) был спроектирован для и на Turbo Pascal.

x86 ASM


Одно из основных ограничений Turbo Pascal заключалось в том, что его BGI (API для общения с графическим адаптером) был ограничен 16 цветами и относительно низкими разрешениями. Когда появились более современные графические карты, все разработчики внезапно начали учить язык ассемблера, чтобы иметь возможность общаться с устройствами. Я не стал исключением.

  • Взрыв мозга: адресация памяти!
  • Взрыв мозга: стек — это иллюзия!
  • Взрыв мозга: прямое взаимодействие с графическим адаптером!
  • Взрыв мозга: прерывания!
  • Взрыв мозга: регистры!

Сегодня очень немногие люди пишут на языке ассемблера вручную, потому что это не особо полезно и не портируемо на 100%, но, разумеется, он всё равно присутствует внутри вашего компилятора или JIT. Я очень часто вижу, как разработчик на Rust или C++ демонстрирует дизассемблированную версию своего двоичного файла, и это напоминает мне о старых (не таких уж) добрых временах.

HyperCard


На другой части спектра находился HyperCard — язык программирования, придуманный для тех, кто не хочет изучать языки программирования. Он выглядел как приложение для рисования, но можно было использовать встроенный язык, чтобы превратить его в полнофункциональную IDE, а также писать новые программы.

  • Взрыв мозга: настройка своей среды.
  • Взрыв мозга: мой первый скриптовый язык, хотя в то время я этого и не понимал.
  • Взрыв мозга: программирование на почти естественном языке.
  • Взрыв мозга: стек и шаблоны, мои первые абстракции UX.
  • Взрыв мозга: программирование как форма беседы между программистом и компьютером.
  • Взрыв мозга: сборка мусора (хотя тогда я этого ещё не осознавал).
  • Взрыв мозга (в плохую сторону): невозможность портирования кода на платформы, не связанные с Apple; вероятно, это одна из причин того, что сегодня я в основном придерживаюсь опенсорса.

Наверно, этот язык стал первоосновой для всего «визуального», от Visual Basic
и Visual Studio до любого инструмента для рисования UX. Кроме того, в какой-то степени, HyperCard стал одним из предков веба. Время от времени я наблюдаю возрождение какого-нибудь потомка HyperCard, но надолго их обычно не хватает.

Разумеется, многие из этих идей используются и в SmallTalk; вероятно, он более революционен, но я изучил SmallTalk гораздо позже, поэтому взорвать мой мозг по этим пунктам ему уже не удалось!

(O)Caml


Caml (позже OCaml) стал для меня неожиданностью. Я был пресыщенным студентом-первокурсником, уверенным, что после выпуска коммерческого ПО знаю уже всё; обычно я лучше владел программированием, чем учителя программирования в старшей школе, и это, разумеется, означало, что я лучший во всём. Я прочитал документацию OCaml ещё до первой лекции и ошибочно понял «полиморфизм» (сегодня мы называем это «дженериками») как «слабую типизацию». Как же я ошибался. На первой лекции преподаватель показал нам, как обходить дерево на OCaml. Это был крайне лаконичный, надёжный и читаемый код. Кроме того, преподаватель оказался сильным разработчиком и автором одного из текстовых процессоров, так что это, разумеется, стало столь необходимым мне уроком смирения.

Я влюбился в OCaml. Он быстро стал моим основным языком программирования до выгорания, вызванного разработкой Opalang.

  • Взрыв мозга: параметрический полиморфизм (aka «дженерики»)!
  • Взрыв мозга: выведение типов!
  • Взрыв мозга: сборка мусора!
  • Взрыв мозга: сопоставление с образцом!
  • Взрыв мозга: REPL!
  • Взрыв мозга: программирование высшего порядка!
  • Взрыв мозга: монады!
  • Взрыв мозга: Continuation-Passing Style!
  • Взрыв мозга: конкурентность передачи сообщений с произвольными сообщениями (включая каналы)!
  • Взрыв мозга: полиморфические варианты и рядный полиморфизм (aka «статическая утиная типизация»)!
  • Взрыв мозга: изменяемый синтаксис!
  • Взрыв мозга: написание DSL!
  • Взрыв мозга: Multistage programming!
  • Взрыв мозга: программирование на уровне типов между модулями!

Сообщество OCaml по-прежнему очень активно. Он использовался в разработке языков программирования (в том числе и первых прототипов Rust), инструментов статического анализа для ядерных электростанций, операционных систем для космических спутников и других ситуаций, требующих чрезвычайно высокой степени безопасности. Кроме того, это один из непосредственных предков Rust, F#, Elm, ReasonML и, если память мне не изменяет, первой версии React. А, и ещё Opalang. По какой-то причине конкурентность передачи сообщений позиционируется сегодня как «gochannels», но, насколько я знаю, она берёт начало ещё в Concurrent ML, одном из предков OCaml.

Java


Я начал изучать Java, когда пытался модернизировать код, написанный на Turbo Pascal, чтобы он мог работать в Linux, Windows и System 7 (предшественнице macOS). Этот язык показался мне многословным, я не мог понять, почему разработчики не поставляют установщик, учитывая сложность выпуска и/или запуска классов, и мне очень не хватало дженериков, алгебраических типов данных и сопоставления с образцом. Однако на долгое время Java стал моим базовым языком — не таким, на мой взгляд, хорошим, как OCaml, но с доступом к более качественным библиотекам.

  • Взрыв мозга: стандартная библиотека, в которой, похоже, есть всё необходимое мне!
  • Взрыв мозга: документация, которую писали так, чтобы она была понятна пользователям!
  • Взрыв мозга: JVML!
  • Взрыв мозга: очень простой в использовании тулкит UX (даже если результаты разочаровывали)!
  • Взрыв мозга: синхронизация как примитив языка (хоть это и не особо великолепная идея)!
  • Взрыв мозга: finally!
  • Взрыв мозга: компиляция Just in Time!
  • Взрыв мозга (в плохом смысле): понимание того, как finally реализовано в JVM.

В наши дни Java, разумеется — один из столпов отрасли. Также это один из предков C#, Scala и Go.

Prolog


Если вы никогда не писали код на Prolog, то лишь рекомендую попробовать. Это полностью изменит ваше мышление о программах. В Prolog вы не пишете алгоритмы, а учите программу, как думать. Написать простой алгоритм поиска пути можно, задействовав примерно 2-4 тривиальных правила. Написание простой системы типов будет чуть длиннее.

  • Взрыв мозга: учим программу думать!

Сегодня Prolog практически не существует. Однако его наследие огромно. Если память меня не подводит, SQL в большой мере основан на подмножестве Prolog с большим упором на оптимизацию в ущерб простоте. Система шаблонов C++ — это, по сути, более усложнённая реализация Prolog. Части системы типов Rust переписываются на Chalk — потомке Prolog.

Я подозреваю, что рано или поздно кто-нибудь начнёт комбинировать LLM с Prolog (или с Coq), чтобы создать поверх ChatGPT нечто надёжное. Кроме того, недавно я обнаружил TypeDB, очень похожий на новое поколение Prolog с API, напоминающим реляционные базы данных.

Coq


Coq (и его родственники Twelf, Isabel и так далее) — это нечто совершенно иное. Вы кодируете спецификации целиком, как типы. Эти типы и есть ваша цель.

Вы программируете не с помощью функций и библиотек, а используя инструменты для преобразования ваших типов, чтобы постепенно упрощать их в независимые подцели. Можно описать это так: вместо кодинга вы решаете головоломку. Разумеется, подцели в результате превратятся в ваши функции, в ваши структуры данных и модули. Но произойдёт это почти случайно.

И, разумеется… модуль контроля типов настолько мощен, что ваша программа — это, на самом деле, формальное, математически проверенное доказательство её соответствия спецификациям. Множество математических теорем было доказано благодаря превращению их в код на Coq.

  • Взрыв мозга: типы как спецификации.
  • Взрыв мозга: программы как доказательства.
  • Взрыв мозга: когда лемма проста, достаточно попросить Coq написать функцию за вас!
  • Взрыв мозга: типы высших родов.
  • Взрыв мозга: ожесточённые споры о том, какой же математик надёжнее, мозг или компьютер.

Я уже довольно давно не следил за разработкой Coq и других языков того же семейства. Насколько я понимаю, они довольно активно используются в научных кругах, где служат для формального доказательства соответствия спецификациям компиляторов и ядер операционных систем. Подозреваю, что если Prolog не вернётся, чтобы создать надёжные LLM, то кто-нибудь использует для этого Coq или Idris.

Erlang


Erlang (а теперь и Elixir) был и остаётся лучшим языком для распределённых систем. Ядро гораздо проще, чем у Python, но легко масштабируется на миллионы узлов.

  • Взрыв мозга: тривиальная реализация распределённых систем.
  • Взрыв мозга: развёртывание нового кода из языка отправкой замыканий.
  • Взрыв мозга: архитектура Let it fail.

Хотя многие всё ещё не слышали о Erlang/Elixir, этот язык использовался в отрасли начиная с 90-х в высокораспределённых системах. Его экосистема вполне жива, сейчас тестируется система статических типов. Модель let it fail применяется в мобильных операционных системах. Конкурентность и модели распределения распространились на Scala, Go и практически на всё остальное, где есть слова «микросервисы» или «акторы». На самом деле, меня печалит, когда я вижу микросервисы или Kafka, ведь по большей мере это повторные реализации архитектуры Erlang/Elixir, а также их внутренней BEAM Virtual Machine, но основанные на технологиях, которыми гораздо сложнее пользоваться и разворачивать, а также на протоколах, которые на множество порядков медленнее.

О, да, и Opalang тоже позаимствовал кое-что у Erlang.

Пи-исчисление


Здесь я сжульничал. Пи-исчисление — это не язык программирования, а исчисление, то есть математическая модель, спроектированная для рассуждений о системах. Эту модель можно полностью определить всего в десятке строк спецификации и очень легко реализовать. Она использовалась для выполнения статического анализа моделей криптографических протоколов, протоколов банкинга… а также биологических процессов. Я использовал её для определения системы типов, которую разработчики теоретически могли бы применять, чтобы гарантировать правильную деградацию своих протоколов в условиях (D)DoS-атаки.

  • Взрыв мозга: совершенно другой взгляд на условия гонки.
  • Взрыв мозга: полнота по Тьюрингу любого вида последовательной операции не нужна.
  • Взрыв мозга: описание сложных конкурентных/распределённых систем при помощи простой математики.

Я уже давненько не видел новых публикаций о пи-исчислении, но, возможно, просто не там смотрю.

Opalang


Особый для меня случай, ведь я присоединился к команде и какое-то время был ведущим архитектором языка. Представьте, что вы пишете единую кодовую базу на простом функциональном языке + на основе акторов, сравнимом с OCaml/F#/ReasonML/Elm или с Erlang со статической типизацией, затем компилятор анализирует код на надёжность, безопасность и возможность распределённого использования, далее разделяет его на клиентский код (компилируемый в JavaScript + HTML + CSS), серверный код (компилируемый в нативное приложение) и код на стороне баз данных (компилируемый в схему базы данных и компилируемые запросы).

Я влюбился в этот язык. А затем выгорел, проектируя, разрабатывая и продвигая его в токсичном окружении. После этого мне понадобилось довольно много времени, чтобы вернуться в сферу проектирования языков программирования.

  • Взрыв мозга: автоматизированное разделение на клиент, сервер и базу данных.
  • Взрыв мозга: HTML со статической типизацией.
  • Взрыв мозга: автоматическое устранение большинства проблем безопасности из Top 10 OWASP.
  • Взрыв мозга: автоматическое распределение между веб-серверами (хоть мы и немного это переусложнили).
  • Взрыв мозга: системы типов для анализа безопасности.
  • Взрыв мозга: асинхронные волокна (fibers) в JavaScript (до Promise, async/await и воркеров DOM).
  • Взрыв мозга: база данных, ориентированная на структуры данных.
  • Взрыв мозга: распределённая масштабируемая база данных (к сожалению, мы совершили ошибки, и на практике она оказалась довольно медленной).

Я считаю, что Opalang (и его родственники ReSharper и Ur/Web) был слишком большим прорывом для своего времени. Вся идея многоуровневого программирования, похоже, оказалась полностью забыта. Возможно, когда-нибудь она вернётся. WASM должен сильно упростить эту задачу.

Rust


Потом я влюбился в Rust. Он сочетал в себе многие преимущества OCaml и Haskell, обещая дать разработчикам возможность писать высококонкурентный код и выполнять разработку на уровне систем. Кроме того, на тот момент революционными идеями были модульная сборка мусора и планирование M:N, хоть от этих идей и отказались до версии 1.0. В то время я начал экспериментировать с языком, по большей мере это был исследовательский проект. Помню обсуждения обработки ошибок, строк и итераторов. Один из важнейших пунктов в моём резюме: я один из тех, кто внедрил идею макроса try!, который затем преобразовали в оператор ?.

  • Взрыв мозга: использование аффинных типов данных для доказательства свойств typestate.
  • Взрыв мозга: писать код, по производительности сравнимый с C++, но с гарантиями уровня OCaml.
  • Взрыв мозга: эффективная модель компиляции для async/await.
  • Взрыв мозга: то, насколько успешно система типов приводит к безопасным конкурентным решениям.
  • Взрыв мозга: помогающие сообщения об ошибках.
  • Взрыв мозга: удобный процесс до RFC/RFC.
  • Взрыв мозга: экосистема cargo и крейтов.
  • Взрыв мозга: юнит-тестирование с принятием однозначной позиции (opinionated unit testing).
  • Взрыв мозга: тестирование документации.
  • Взрыв мозга: дружелюбное и приветствующее новичков сообщество.
  • Взрыв мозга: частичная поддержка в написании моей собственной постепенной системы типизации (gradual type system).

У меня уже довольно долго не хватает времени, чтобы заниматься контрибьютингом в компилятор или stdlib, но когда оно найдётся, я планирую к этому вернуться!

К сожалению, мне кажется, Rust испортил для меня многие другие языки. Теперь когда я пишу на Python или Go (и тем, и другим я занимаюсь, чтобы зарабатывать на жизнь), или даже на TypeScript, мне всегда неприятна перспектива того, что мой код поломается, как только я его запущу. В Rust я кодирую в системе типов столько свойств, сколько могу, из-за чего перед написанием кода приходится немного дольше подумать, зато тесты обычно проходят с первого раза.

▍ А почему не $(ВАШ ЛЮБИМЫЙ ЯЗЫК)?


За свою карьеру я писал код на десятках языков программирования. В том числе на Haskell, Scheme, SmallTalk, (Tw)elf, Idris, Python, Go, PHP, Perl, Bash, C, C++, JoCaml,
JavaScript, TypeScript, Scala, C#, F#, Visual Basic, Ruby, (D)TAL, Squeak, Logo,
Scratch, UnrealScript, GDScript, Lua, SQL…

Если я не включил их в статью, значит, они не взорвали мой мозг. Это не значит, что эти языки не хорошие и не новаторские. Просто их концепция не вызвала во мне особого отклика или, что бывает чаще, я уже обнаружил те же концепции в каких-то других языках потому, что изучал их в таком порядке.

▍ Что дальше?


Я уже долгое время не видел ничего революционного, но это ничего не значит. Возможно, новая идея уже на подходе, где-то в небольшом исследовательском проекте, о котором я не слышал.

Когда я пришёл в PASQAL, то надеялся, что буду поражён языками для квантовых вычислений. Пока этого не случилось, но я не теряю надежды!

Мне кажется, что, несмотря на чрезмерный ажиотаж и безумный урон для окружающей среды, что-то полезное получится из ChatGPT и LLM, но пока не вижу этого. Я видел только интересные эксперименты, и многие игрушки уже кажутся поломанными. Любопытно, каким окажется будущее.

А какие языки повлияли на ваше мышление, связанное с программами?

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (15)


  1. Zenitchik
    06.11.2024 13:11

    У автора, я смотрю, от каждой мелочи мозг взрывается...


  1. gsaw
    06.11.2024 13:11

    Я программирую с восьми лет, и основную часть жизни был разработчиком


  1. smt_one
    06.11.2024 13:11

    Эх, нет упоминания ATS. Надо действительно запланировать статью про него, а то про такую жемчужину на Хабре ничего и не видно.


  1. ednersky
    06.11.2024 13:11

    Взрыв мозга: GOTO!

    Очень хороший оператор. Мания удалять его из языков программирования - это победа сил зла над силами разума.


    1. diakin
      06.11.2024 13:11

      Догматизм и начетничество.


    1. Moog_Prodigy
      06.11.2024 13:11

      Меня всегда это удивляло. Ну давайте тогда и в асме отменим jmp, rjmp и прочие безусловные переходы. Как легко станет писать то сразу! Никаких переходов, никакой путаницы, исключительно условные операторы, условные переходы - красота.


      1. nagayev
        06.11.2024 13:11

        В асме пусть живет)

        Все же если человек пишет в 2024 на асме он по идее точно знает что делает.

        А вот на каком-нибудь JS не всегда.


        1. ednersky
          06.11.2024 13:11

          goto - идеальный оператор для написания, например, парсеров и вообще стейтмашин. при этом пофиг какой язык, если оператор goto есть, то читабельность кода в этом случае значительно выше, чем если этого оператора нет


    1. nagayev
      06.11.2024 13:11

      Понятно, что в каких-то случаях использовать GOTO нормальная практика. В ядре линукса например он используется в том числе чтобы реализовать что-то вроде деструктора - позакрывать там файлы при выходе из функции например. Но в целом для современных языков GOTO не очень нужен. GOTO прямо провоцирует нарушать правило одного выхода из функции (см. misra), которое не лишено смысла. Используя что-то современное вроде Python или C++ в отличие от Си у вас есть инструменты для этого вроде менеджера контекста with или идиома RAII, которую удобно реализовывать через деструкторы.


      1. diakin
        06.11.2024 13:11

        GOTO прямо провоцирует нарушать правило одного выхода из функции

        Это как это?


        1. nagayev
          06.11.2024 13:11

          Ну потому что у вас есть возможность прыгать почти в любое место в коде (в С++ например нельзя обходить инициализацию переменной).

          А имея просто return шанс что выход будет один все же выше.

          А еще у goto есть другие недостатки: усложнение статического анализа например.


          1. diakin
            06.11.2024 13:11

            В смысле вплоть до из одной функции в другую? В этом случае программиста уже никакие парадигмы не спасут.


    1. adeshere
      06.11.2024 13:11

      Очень хороший оператор. Мания удалять GOTO из языков программирования - это победа сил зла над силами разума.

      Кстати, а в каких современных языках, кроме фортрана, он реально используется (а не формально присутствует для обратной совместимости), и в каком обычно контексте?

      Я застал древний фортран, где GOTO использовался на каждом углу, и читать этот код было невозможно. Даже когда прыжки GOTO строго вложены друг в друга, это уже нечитаемо, имхо. А если траектории прыжков пересекаются (например, со строчки N1 прыжок на N4, а со строчки N2 прыжок на N5), то это та самая катастрофа, попав в которую хочется вырезать все GOTO каленым железом, включая и их использование

      в быту ;-)

      Как известно, в русском языке такой оператор появился очень задолго до первых языков программирования и вообще вычислительной техники ;-)

      P.S. Вдогонку сообразил еще один аргумент супротив неправильного употребления GOTO: совсем небольшая модификация этого простонародного оператора запросто может приводить (и во многих алгоритмах из позапрошлого века реально приводит)

      к UB

      ... иди туда, не знаю куда ....

      ;-)

      Сейчас я по-прежнему пишу на фортране, но немного в другом стиле: а именно, почти без GOTO. Однако, есть пара контекстов, где я не просто не избегаю GOTO, а наоборот, использую его, как стандарт. Наиболее типичный случай - это переход из тела функции в самый ее конец (обычно на стандартную метку 900) при обнаружении каких-то проблем в любом месте функции. Код после метки 900 анализирует локальный номер ошибки и ее контекст, формирует диагностические сообщения для юзера и для протокола, восстанавливает среду (например, функция могла открыть какой-то файл или аллоцировать память - файл надо закрыть, а память освободить) и устанавливает возвращаемое значение с учетом вида ошибки. Такая схема позволяет:

      1) приблизить проверочный код в теле функции к тому месту, где проверяемые условия непосредственно задействованы, не разрывая логику функции. Так, входные параметры проверяются сразу при входе в функцию, а условный знаменатель - непосредственно перед делением на него. Это упрощает модификацию кода: проверочные операторы легко менять одновременно с исполняемыми;
      2) При этом код, выявляющий нештатную ситуацию, занимает минимальное место и не мешает чтению общей логики (обычно он состоит из одного-двух IF-ов с последующим GOTO);
      3) Весь код восстановления собран в одном месте, что позволяет избежать его дублирования после каждой проверки. Причем, он знает, из какого именно места произошел переход на метку 900, и с учетом этого выполняет все нужные операции в нужном порядке.

      Еще изредка у меня GOTO заменяет простой и короткий цикл WHILE с постусловием в тех случаях, ЕСЛИ
      1) этот цикл практически всегда выполняется один раз (и лишь изредка надо его повторить два-три раза) И
      2) запись постусловия в формате IF(...) GOTO улучшит читаемость кода.

      Я таким способом подчеркиваю для себя линейность алгоритма. Но имхо этот случай гораздо более спорный, чем описанный выше. Даже несмотря на обязательное требование к таким GOTO, что они должны вести не более, чем на несколько операторов назад, и что во внутреннем блоке не должно быть никаких ветвлений или условий.


    1. vanxant
      06.11.2024 13:11

      Очень хороший оператор

      Соглашусь с комментатором выше. Вы просто не видели программ, построенных на базе пересекающихся goto. Какая-нибудь машина состояний. например. Я понимаю, что там это оправданно, и компилятор в итоге именно такую лапшу из goto (jmp, br, you name it) и выдаст. Но лучше пусть он этим и занимается.


  1. foal
    06.11.2024 13:11

    Мне голову сломал FORTH. До сих пор, как вспомню так вздрогну :)