Введение
Высокоуровневая концептуализация компьютерного программирования и классификация языков программирования.
classification of programming languages
Парадигма программирования – это относительно высокоуровневый способ структурирования и концептуализации реализации компьютерной программы. Язык программирования может быть классифицирован как поддерживающий одну или несколько парадигм. Парадигмы разделяются и описываются различными аспектами программирования. Некоторые парадигмы связаны с особенностями модели исполнения, например, разрешением побочных эффектов или определением последовательности операций моделью исполнения. Другие парадигмы касаются организации кода, например, группировки в единицы, включающие как состояние, так и поведение. Ещё одни парадигмы относятся к синтаксису и грамматике. Некоторые распространенные парадигмы программирования включают (представлены в иерархических взаимосвязях):
Императивное программирование – код напрямую управляет потоком выполнения и изменением состояния.
Процедурное программирование – организовано в виде процедур, вызывающих друг друга.
Объектно-ориентированное программирование – организовано в виде объектов, содержащих как структуру данных, так и связанное с ней поведение.
Декларативное программирование – код описывает свойства желаемого результата, но не способ его вычисления.
Функциональное программирование – желаемый результат представляется как значение серии вычислений функций.
Логическое программирование – желаемый результат представляется как ответ на вопрос о системе фактов и правил.
Реактивное программирование – желаемый результат представляется с использованием потоков данных и распространения изменений.
Imperative code directly controls execution flow and state change
procedural organized as procedures that call each other
object oriented organized as objects that contain both data structure and associated behavior
Declarative code declares properties of the desired result, but not how to compute it
functional a desired result is declared as the value of a series of function evaluations
logic a desired result is declared as the answer to a question about a system of facts and rules
reactive a desired result is declared with data streams and the propagation of change
Обзор
Парадигмы программирования берут начало в исследованиях компьютерных наук, посвященных существующим практикам разработки программного обеспечения. Полученные результаты позволяют описывать и сравнивать практики программирования и языки, используемые для написания программ. Для лучшего понимания, другие исследования изучают процессы разработки программного обеспечения и описывают различные методологии для их описания и сравнения. Язык программирования можно описать с точки зрения парадигм. Некоторые языки поддерживают только одну парадигму. Например, Smalltalk поддерживает объектно-ориентированную, а Haskell – функциональную. Большинство языков поддерживают несколько парадигм. Например, программа, написанная на C++, Object Pascal или PHP, может быть чисто процедурной, чисто объектно-ориентированной или содержать элементы обеих или других парадигм. При использовании языка, поддерживающего несколько парадигм, разработчик выбирает, какие элементы парадигмы использовать. Однако этот выбор не всегда предполагает осознанное рассмотрение самих парадигм. Разработчик часто использует возможности языка по мере их доступности и в той мере, в которой он с ними знаком. Категоризация получившегося кода по парадигме часто является академическим упражнением, выполняемым задним числом. Языки, классифицируемые как императивные парадигмы, имеют две основные характеристики: они определяют порядок выполнения операций, используя конструкции, явно контролирующие этот порядок, и допускают побочные эффекты, когда состояние может быть изменено в один момент времени внутри одного блока кода, а затем прочитано в другой момент времени внутри другого блока кода. Взаимодействие между блоками кода не является явным. В отличие от этого, языки декларативной парадигмы не указывают порядок выполнения операций. Вместо этого они предоставляют набор доступных операций в системе вместе с условиями, при которых каждая из них может быть выполнена. Механизм исполнения языка отслеживает, какие операции могут быть выполнены, и самостоятельно выбирает порядок их выполнения. Подробнее – в статье «Сравнение многопарадигматических языков программирования». В объектно-ориентированном программировании код организован в объекты, содержащие состояние, которое принадлежит и (обычно) контролируется кодом объекта. Большинство объектно-ориентированных языков также являются императивными. В объектно-ориентированном программировании программы рассматриваются как набор взаимодействующих объектов. В функциональном программировании программы рассматриваются как последовательность вычислений функций без состояния. При программировании компьютеров или систем с множеством процессоров, в процессеориентированном программировании программы рассматриваются как наборы параллельных процессов, действующих на логические структуры данных. Многие парадигмы программирования известны не только поддерживаемыми ими методами, но и теми, которые они запрещают. Например, чисто функциональное программирование запрещает побочные эффекты, а структурированное программирование – конструкцию goto. Отчасти поэтому новые парадигмы часто воспринимаются как догматичные или излишне жесткие теми, кто привык к старым. Однако, избегая определенных методов, можно упростить понимание поведения программы и доказать теоремы о ее корректности. Парадигмы программирования также можно сравнивать с моделями программирования, которые позволяют вызывать модель исполнения, используя только API. Модели программирования также могут быть классифицированы по парадигмам на основе характеристик модели исполнения. Для параллельных вычислений часто используется модель программирования вместо языка. Это связано с тем, что детали параллельного оборудования проникают в абстракции, используемые для программирования этого оборудования. Это вынуждает программиста сопоставлять шаблоны в алгоритме с шаблонами в модели исполнения (которые были внедрены из-за проникновения аппаратных деталей в абстракцию). В результате ни один язык параллельного программирования не подходит для решения всех вычислительных задач. Поэтому удобнее использовать базовый последовательный язык и вставлять вызовы API в параллельные модели исполнения через модель программирования. Такие модели параллельного программирования можно классифицировать в соответствии с абстракциями, отражающими аппаратное обеспечение, такими как общая память, распределенная память с передачей сообщений, представления о месте, видимые в коде, и так далее. Эти можно рассматривать как разновидности парадигм программирования, применимые только к параллельным языкам и моделям программирования.
software engineering processes and describes various methodologies to describe and compare them. A programming language can be described in terms of paradigms. Some languages support only one paradigm. For example, Smalltalk supports object oriented and Haskell supports functional. Most languages support multiple paradigms. For example, a program written in C++, Object Pascal or PHP can be purely procedural, purely object oriented, or can contain aspects of both or other paradigms. When using a language that supports multiple paradigms, the developer chooses which paradigm elements to use. But, this choice may not involve considering paradigms per se. The developer often uses the features of a language as the language provides them and to the extent that the developer knows them. Categorizing the resulting code by paradigm is often an academic activity done in retrospect. Languages categorized as imperative paradigm have two main features: they state the order in which operations occur, with constructs that explicitly control that order, and they allow side effects, in which state can be modified at one point in time, within one unit of code, and then later read at a different point in time inside a different unit of code. The communication between the units of code is not explicit. In contrast, languages in the declarative paradigm do not state the order in which to execute operations. Instead, they supply a number of available operations in the system, along with the conditions under which each is allowed to execute. The implementation of the language's execution model tracks which operations are free to execute and chooses the order independently. More at Comparison of multi paradigm programming languages. In object oriented programming, code is organized into objects that contain state that is owned by and (usually) controlled by the code of the object. Most object oriented languages are also imperative languages. In object oriented programming, programs are treated as a set of interacting objects. In functional programming, programs are treated as a sequence of stateless function evaluations. When programming computers or systems with many processors, in process oriented programming, programs are treated as sets of concurrent processes that act on a logical shared data structures. Many programming paradigms are as well known for the techniques they forbid as for those they support. For instance, pure functional programming disallows side effects, while structured programming disallows the goto construct. Partly for this reason, new paradigms are often regarded as doctrinaire or overly rigid by those accustomed to older ones. Yet, avoiding certain techniques can make it easier to understand program behavior, and to prove theorems about program correctness. Programming paradigms can also be compared with programming models, which allows invoking an execution model by using only an API. Programming models can also be classified into paradigms based on features of the execution model. For parallel computing, using a programming model instead of a language is common. The reason is that details of the parallel hardware leak into the abstractions used to program the hardware. This causes the programmer to have to map patterns in the algorithm onto patterns in the execution model (which have been inserted due to leakage of hardware into the abstraction). As a consequence, no one parallel programming language maps well to all computation problems. Thus, it is more convenient to use a base sequential language and insert API calls to parallel execution models via a programming model. Such parallel programming models can be classified according to abstractions that reflect the hardware, such as shared memory, distributed memory with message passing, notions of place visible in the code, and so forth. These can be considered flavors of programming paradigm that apply to only parallel languages and programming models.
Критика
Некоторые исследователи в области языков программирования критикуют представление о парадигмах как о классификации языков программирования, например, Харпер и Кришнамурти. Они утверждают, что многие языки программирования нельзя однозначно отнести к одной парадигме, поскольку они включают в себя элементы нескольких парадигм. См. статью «Сравнение языков программирования с мультипарадигменным подходом».
История
Со временем развивались различные подходы к программированию. Классификация каждого подхода либо описывалась одновременно с его разработкой, либо, чаще, ретроспективно, спустя некоторое время. Одним из первых подходов, сознательно обозначенных как таковой, является структурированное программирование, которое продвигалось начиная с середины 1960-х годов. Концепция парадигмы программирования в том виде, в каком мы её знаем, возникла, по крайней мере, в 1978 году, в лекции Роберта Флойда при вручении премии Тьюринга под названием «Парадигмы программирования», где он ссылается на понятие парадигмы, использованное Томасом Куном в его работе «Структура научных революций» (1962). Ранние языки программирования не имели чётко определённых парадигм, и программы часто интенсивно использовали операторы `goto`. Чрезмерное использование этих операторов приводило к так называемому "спагетти-коду", который сложно понимать и поддерживать. Это послужило стимулом для разработки парадигм структурированного программирования, которые запрещали использование операторов `goto`, разрешая лишь более структурированные управляющие конструкции.
Код машины
Машинный код — это самый низкий уровень компьютерного программирования, поскольку он состоит из машинных инструкций, определяющих поведение компьютера на минимально возможном уровне абстракции. Будучи наиболее директивным способом кодирования, он классифицируется как императивный. Его иногда называют языком программирования первого поколения.
Сборка
Язык ассемблера ввел мнемонические обозначения для машинных инструкций и адресов памяти. Ассемблер классифицируется как императивный язык и иногда называется языком программирования второго поколения. В 1960-х годах языки ассемблера были разработаны для поддержки библиотечной функции COPY и достаточно сложных возможностей условной генерации макросов и предварительной обработки, вызова подпрограмм (CALL), использования внешних переменных и общих областей (глобальных переменных), что обеспечивало значительное повторное использование кода и изоляцию от аппаратных особенностей посредством логических операторов, таких как READ/WRITE/GET/PUT. Ассемблер использовался и продолжает использоваться для систем, критичных ко времени отклика, и часто во встраиваемых системах, поскольку он обеспечивает максимальный контроль над действиями машины.
Языки процедур
Процедурные языки, также называемые языками программирования третьего поколения, первыми были описаны как языки высокого уровня. Они используют лексику, соответствующую решаемой задаче. Например, в языке COmmon Business Oriented Language (COBOL) используются такие термины, как файл, переместить и копировать. FORmula TRANslation (FORTRAN), использующий терминологию математического языка, был разработан главным образом для научных и инженерных задач. ALGOrithmic Language (ALGOL) был ориентирован на то, чтобы стать подходящим языком для определения алгоритмов, при этом используя математическую терминологию и предназначенный для научных и инженерных задач, как и FORTRAN. Programming Language One (PL/I) – гибридный язык общего назначения для коммерческих и научных вычислений, поддерживающий указатели. Beginners All-purpose Symbolic Instruction Code (BASIC) был разработан, чтобы сделать программирование доступным для большего числа людей. C – язык программирования общего назначения, первоначально разработанный Деннисом Ричи в период с 1969 по 1973 год в AT&T Bell Labs. Эти языки классифицируются как процедурная парадигма. Они напрямую управляют пошаговым процессом выполнения компьютерной программы. Таким образом, эффективность и результативность такой программы во многом зависят от квалификации программиста.
COmmon Business Oriented Language (COBOL) uses terms like file, move and copy. FORmula TRANslation (FORTRAN) using mathematical language terminology, it was developed mainly for scientific and engineering problems. ALGOrithmic Language (ALGOL) focused on being an appropriate language to define algorithms, while using mathematical language terminology, targeting scientific and engineering problems, just like FORTRAN. Programming Language One (PL/I) a hybrid commercial scientific general purpose language supporting pointers. Beginners All purpose Symbolic Instruction Code (BASIC) it was developed to enable more people to write programs. C a general purpose programming language, initially developed by Dennis Ritchie between 1969 and 1973 at AT&T Bell Labs. These languages are classified as procedural paradigm. They directly control the step by step process that a computer program follows. The efficacy and efficiency of such a program is therefore highly dependent on the programmer's skill.
Объектно-ориентированное программирование
В попытке улучшить процедурные языки были созданы языки объектно-ориентированного программирования (ООП), такие как Simula, Smalltalk, C++, Eiffel, Python, PHP, Java и C#. В этих языках данные и методы для работы с этими данными находятся в едином кодовом блоке, называемом объектом. Эта инкапсуляция обеспечивает единственный способ доступа объекта к данным – через методы самого объекта, содержащего эти данные. Таким образом, внутреннее устройство объекта может быть изменено без воздействия на код, использующий этот объект. Александр Степанов, Ричард Столлман и другие программисты подняли вопрос о целесообразности парадигмы ООП по сравнению с процедурной парадигмой. Необходимость наличия у каждого объекта связанных методов заставляет некоторых скептиков связывать ООП с разрастанием программного кода; попыткой разрешить эту дилемму стал полиморфизм. Хотя большинство языков ООП относятся к третьему поколению, возможно создание объектно-ориентированного ассемблера. High Level Assembly (HLA) является примером такого языка, полностью поддерживающего продвинутые типы данных и объектно-ориентированное программирование на ассемблере, несмотря на свои ранние истоки. Таким образом, различные парадигмы программирования можно рассматривать скорее как вдохновляющие мемы, отражающие убеждения их сторонников, чем как непременный прогресс от одного уровня к другому. Точные сравнения эффективности конкурирующих парадигм часто затруднены из-за новой и различной терминологии, применяемой к схожим сущностям и процессам, а также многочисленных различий в реализации на разных языках.
Декларативные языки
Декларативная программа описывает, в чём заключается проблема, а не то, как её решить. Программа структурирована как набор свойств, которые должны быть найдены в ожидаемом результате, а не как последовательность действий. Получив базу данных или набор правил, компьютер пытается найти решение, удовлетворяющее всем заданным свойствам. Ярким примером декларативного языка является язык четвёртого поколения SQL, а также семейство функциональных языков и языков логического программирования. Функциональное программирование является подмножеством декларативного программирования. Программы, написанные в этом стиле, используют функции – блоки кода, предназначенные для работы подобно математическим функциям. Функциональные языки не поощряют изменение значений переменных посредством присваивания, активно используя вместо этого рекурсию. Парадигма логического программирования рассматривает вычисления как автоматизированное логическое заключение на основе базы знаний. Факты о предметной области выражаются в виде логических формул, а программы выполняются путём применения правил вывода к этим формулам до тех пор, пока не будет найден ответ на задачу или набор формул не будет признан противоречивым.
Другие парадигмы
Символическое программирование — это парадигма, описывающая программы, способные манипулировать формулами и компонентами программ как данными. Дифференцируемое программирование структурирует программы таким образом, чтобы их можно было дифференцировать целиком, как правило, с помощью автоматического дифференцирования. Литературное программирование, как форма императивного программирования, структурирует программы как ориентированную на человека сеть, подобно гипертекстовому эссе: документация является неотъемлемой частью программы, а программа структурирована в соответствии с логикой изложения, а не удобством компилятора. Символические методы, такие как рефлексия, позволяющие программе ссылаться на саму себя, также можно рассматривать как парадигму программирования. Однако это совместимо с основными парадигмами и, следовательно, не является самостоятельной парадигмой.