Ответ 1
Повторяйте за мной: "Это разные парадигмы"
Скажи это вслух 20 раз или около того - это наша мантра на данный момент.
Если мы действительно должны сравнить яблоки и апельсины, давайте хотя бы рассмотрим, где пересекаются общие аспекты "быть фруктами".
Java-объекты являются базовой единицей вычислений для программиста Java. То есть объект (в основном структура с руками и ногами, инкапсуляция которой более строго соблюдается, чем в C++) является основным инструментом, с помощью которого вы моделируете мир. Вы думаете: "Этот объект знает/имеет Data {X,Y,Z}
и выполняет над ним Functions {A(),B(),C()}
, переносит Data
куда угодно и может связываться с другими объектами, вызывая функции/методы, определенные как часть их открытого интерфейса. Это существительное, и это существительное делает вещи. " То есть вы ориентируете свой мыслительный процесс на эти вычислительные единицы. Случай по умолчанию состоит в том, что вещи, которые происходят среди объектов, происходят последовательно, и сбой прерывает эту последовательность. Они называются "объектами" и, следовательно, (если мы не примем во внимание изначальное значение Алана Кея), мы получим "объектную ориентацию".
Erlang-процессы - это базовая единица вычислений для программиста Erlang. Процесс (в основном автономная последовательная программа, работающая в своем собственном времени и пространстве) является основным инструментом, с помощью которого Эрлангер моделирует мир (1). Подобно тому, как объекты Java определяют уровень инкапсуляции, процессы Erlang также определяют уровень инкапсуляции, но в случае Erlang единицы вычислений полностью отрезаны друг от друга. Вы не можете вызывать метод или функцию в другом процессе, а также не можете получить доступ к каким-либо данным, которые в нем находятся, и ни один процесс не выполняется даже в том же контексте синхронизации, что и любые другие процессы, и нет никакой гарантии относительно порядка относительного приема сообщений. другим процессам, которые могут отправлять сообщения. С таким же успехом они могут быть на разных планетах (и, если подумать, это действительно правдоподобно). Они могут аварийно завершить работу независимо друг от друга, и другие процессы будут затронуты только в том случае, если они преднамеренно решили быть затронутыми (и даже это включает обмен сообщениями: по сути, регистрация для получения сообщения о самоубийстве от мертвого процесса, который сам по себе не гарантированно поступит в каком-либо виде). порядка относительно системы в целом, на которую вы можете или не можете реагировать).
Java имеет дело со сложностью непосредственно в составных алгоритмах: как объекты работают вместе, чтобы решить проблему. Он предназначен для этого в пределах одного контекста выполнения, и по умолчанию в Java используется последовательное выполнение. Множество потоков в Java указывает на несколько работающих контекстов и является очень сложной темой из-за воздействия действий в различных контекстах синхронизации друг на друга (и системы в целом: отсюда и защитное программирование, схемы исключений и т.д.). Выражение "многопоточный" в Java означает нечто иное, чем в Erlang, фактически, в Erlang об этом даже не говорят, потому что это всегда базовый вариант. Обратите внимание, что потоки Java подразумевают сегрегацию в отношении времени, а не памяти или видимых ссылок - видимость в Java контролируется вручную путем выбора того, что является частным, а что - открытым; общедоступные элементы системы должны быть либо спроектированы так, чтобы быть "ориентированными на многопотоковое исполнение" и повторно входящими, секвенироваться через механизмы очередей, либо использовать механизмы блокировки. Вкратце: планирование - это проблема, управляемая вручную в многопоточных/параллельных программах Java.
Erlang разделяет контекст выполнения каждого процесса с точки зрения времени выполнения (планирование), доступа к памяти и видимости ссылок, и при этом упрощает каждый компонент алгоритма, полностью изолируя его. Это не просто случай по умолчанию, это единственный случай, доступный в рамках этой модели вычислений. Это происходит за счет отсутствия точного знания последовательности какой-либо операции после того, как часть ваших последовательностей обработки пересекает барьер сообщений - потому что все сообщения по существу являются сетевыми протоколами, и нет вызовов методов, которые могут быть гарантированно выполнены в пределах заданного контекст. Это было бы аналогично созданию экземпляра JVM для каждого объекта и разрешению им обмениваться данными только через сокеты - это было бы смехотворно громоздко в Java, но способ, которым Erlang предназначен для работы (между прочим, это также основа концепции написания "Java microservices", если кто-то бросает веб-ориентированный багаж, к которому часто прибегают модные слова - программы Erlang по умолчанию являются роями микросервисов). Это все о компромиссах.
Это разные парадигмы. Самая близкая общность, которую мы можем найти, состоит в том, чтобы сказать, что с точки зрения программиста процессы Erlang аналогичны объектам Java. Если мы должны найти что-то для сравнения потоков Java с... ну, мы просто не собираемся найти что-то подобное в Erlang, потому что в Erlang нет такого сопоставимого понятия. Бить мертвого коня: это разные парадигмы. Если вы напишете несколько нетривиальных программ на Erlang, это станет очевидным.
Обратите внимание, что я говорю "это разные парадигмы", но даже не затронул тему ООП против ФП. Разница между "мышлением в Java" и "мышлением в Erlang" более фундаментальна, чем ООП против FP.
Хотя верно то, что Эрланг, "ориентированный на параллелизм" или "ориентированный на процесс", ближе к тому, что имел в виду Алан Кей, когда он придумал термин "объектно-ориентированный" (2), на самом деле это не имеет значения. Кей получал то, что можно уменьшить когнитивную сложность системы, разрезая ваши компьютеры на отдельные куски, и для этого необходима изоляция. Java выполняет это способом, который делает его по-прежнему принципиально процедурным по своей природе, но структурирует код вокруг специального синтаксиса над диспетчерскими замыканиями более высокого порядка, называемыми "определениями классов". Эрланг делает это, разделяя текущий контекст на объект. Это означает, что штуковины Эрланга не могут вызывать методы друг у друга, но штуковины Java могут. Это означает, что вещи Erlang могут аварийно завершиться, но вещи Java не могут. Из этого основного различия вытекает огромное количество последствий - отсюда и "разные парадигмы". Компромисс.
Примечания:
- Кстати, Erlang реализует версию " модели актера ", но мы не используем эту терминологию, так как Erlang предшествует популяризации этой модели. Джо не знал об этом, когда он разработал Erlang и написал свою диссертацию.
- Алан Кей довольно много рассказал о том, что он имел в виду, когда придумал термин "объектно-ориентированный", наиболее интересным было его восприятие обмена сообщениями (одностороннее уведомление от одного независимого процесса с его собственным временем и памятью другому), VS вызывает ( вызовы функций или методов в контексте последовательного выполнения с совместно используемой памятью) и то, как немного размываются линии между интерфейсом программирования, представленным языком программирования и реализацией ниже.