- Императивное и декларативное программирование простым языком — объясняют эксперты
- Роман Меньшиков, ведущий системный программист компании «Аэродиск»
- Михаил Козин, руководитель отдела разработки ECM «Т1 Консалтинг»
- Павел Романченко, технический директор центра инновационных технологий и решений «Инфосистемы Джет»
- Что из себя представляют императивное и декларативное программирование?
- Декларативный и императивный подход написания кода
- Положительные стороны функционального программирования
- Отрицательные стороны функционального программирования
- Подведем итог:
Императивное и декларативное программирование простым языком — объясняют эксперты
Начинающему программисту несложно запутаться в различных терминах — взять только объектно-ориентированное, динамическое, императивное и декларативное программирование. Спросили у экспертов, что из себя представляют два последних подхода.
Роман Меньшиков, ведущий системный программист компании «Аэродиск»
Декларативное программирование — это парадигма программирования, в которой задаётся спецификация решения задачи: описывается, что представляет собой проблема и ожидаемый результат, но без описания способа достижения этого результата. Зачастую декларативные программы не используют понятия состояния и, в частности, не содержат переменных и операторов присваивания, обеспечивая ссылочную прозрачность. К подвидам декларативного программирования часто относят и функциональное программирование. Декларативные компьютерные языки часто не полны по Тьюрингу, так как теоретически не всегда возможно порождение исполняемого кода по декларативному описанию.
Императивное программирование — это парадигма программирования, в которой задаётся последовательность действий, необходимых для получения результата. В нём используются переменные, операторы присваивания и составные выражения.
Несмотря на то, что исторически первым был применен декларативный подход в программировании, первые языки программирования компьютеров (машинный, ассемблер, фортран, алгол, кобол) были императивными в силу простоты подхода.
Сейчас широко распространены как узкоспециализированные декларативные языки программирования (HTML + CSS, SVG, VRML, SQL, lex/VACC), в том числе функциональные (Haskell, Erlang, Scala), так и императивные языки (C/C++/C#, Java, Go, Rust, Python). Однако практически все современные языки программирования общего назначения высокого уровня, за исключением некоторых функциональных, относятся к императивным языкам.
Выбор той или иной парадигмы программирования — императивной или функциональной — определяется, главным образом, требованиями к программе и набором достоинств и недостатков каждой из парадигм. Так, например, независимость функций по данным в функциональных языках и отсутствие побочных эффектов чрезвычайно сокращает количество ошибок и позволяет эффективно распараллеливать код. Поэтому для создания высоконагруженных систем с высоким уровнем параллельных вычислений более оправданно выбирать один из функциональных языков.
С другой стороны, неизменность входных данных в функциональных языках программирования затрудняет создание систем, активно выполняющих ввод-вывод и модификацию уже имеющихся данных. Для реализации таких систем предпочтительнее выбирать императивные языки.
Михаил Козин, руководитель отдела разработки ECM «Т1 Консалтинг»
Императивное программирование — это парадигма, основанная на составлении алгоритма действий (инструкций/команд), которые изменяют состояние (информацию/данные/память) программы. Первыми языками программирования, основанными на таком подходе, были машинные коды и ассемблеры. Фактически, программа на этих языках — это код, который выполняется компьютером сразу, без предварительной компиляции. Из языков высокого уровня, требующих компиляции исходного кода программы в машинный код (или интерпретации), к императивным можно отнести C, C++, Java.
Декларативное программирование — это парадигма, при которой описывается желаемый результат, без составления детального алгоритма его получения. В пример можно привести HTML и SQL. При создании HTML мы с помощью тегов описываем, какую хотим получить страничку в браузере, а не то, как нарисовать на экране заголовок статьи, оглавление и текст. В SQL, если нам нужно посчитать количество сотрудников с фамилией «Сидоров», мы напишем SELECT count(*) FROM employee WHERE last_name = ‘Сидоров’; . Тут ничего не сказано про то, в каком файле или области памяти находятся данные по сотрудникам, как именно выбрать из них всех Сидоровых и нужно ли вообще это делать для подсчёта их количества.
Рассмотрим ещё один пример. Допустим, мы хотим приготовить обед.
В императивной парадигме это выглядит как-то так:
- купить мясо, огурцы, помидоры, соль;
- порезать мясо, посолить;
- поставить сковородку на плиту;
- …
В декларативной: хочу на обед жареное мясо с овощами (неплохо звучит, правда? :)).
Вроде бы различия очевидны. Однако, императивный язык не мешает обобщить и автоматизировать отдельные задачи. Можно реализовать некий «слой» кода, библиотеки, которые будут «уметь» выполнять отдельные этапы алгоритма: определять по рецепту, есть ли в наличии необходимые продукты, заказывать их доставку, пользоваться плитой и т.д. Получится, что программный код императивного языка программирования, использующий такие библиотеки, уже не будет по своей структуре так уж сильно отличаться от декларативного.
На практике, при написании кода и выбора подхода, разработчик отталкивается не только от возможностей и ограничений языка программирования, но и удобства использования той или иной парадигмы в данном конкретном случае.
Павел Романченко, технический директор центра инновационных технологий и решений «Инфосистемы Джет»
Императивные языки, такие, как Java, Python, JavaScript, C, C++ занимают доминирующее положение в индустрии ПО, соответственно императивное программирование — самое распространённое. Смысл его в том, что императивная программа содержит прямые указания, что должен сделать компьютер и в каком порядке должны выполняться инструкции. Этот подход легко понять программисту, а компилятору — легко породить достаточно эффективный код.
Декларативное программирование распространено не так обширно, как императивное, хотя оказывает большое влияние на мейнстрим. Смысл декларативного программирования в том, что программы пишут в виде некоторых ограничений и правил. Логические языки, такие, как Пролог, предлагают описывать ограничения в виде фактов и правил.
В функциональных языках (другой вариант декларативного программирование) описывают программу в виде функций. Отличие от функций в императивном программировании заключается в том, что функции в функциональном языке являются математическими в том смысле, что они устанавливают отношение между аргументом и результатом, и не могут изменять никаких переменных во время вычислений.
Вообще в декларативных языках обычно отсутствует изменение переменных или обычно спрятано за каким-либо специальным механизмом.
Самый популярный язык РСУБД SQL так же является декларативным. На нём описывается конечный результат, а способ его получения генерируется сервером СУБД исходя из множества факторов.
Декларативное программирование может являться более сложным в понимании, но позволяет писать более безопасный и поддерживаемый код, который легко параллелится. А компиляторы декларативных языков имеют больше возможностей при оптимизации программ.
Конечно, практически все основные языки сочетают в себе элементы и декларативного и императивного программирования. Огромное влияние оказывает функциональное программирование на JavaScript, Java, C++, C# и т.д.
Что из себя представляют императивное и декларативное программирование?
Если кратко, то императивная программа содержит прямые указания, что должен сделать компьютер и в каком порядке должны выполняться инструкции. Примерами императивных языков являются Java, Python, JavaScript, C, C++.
Декларативная же программа состоит из ограничений и правил, из которых компьютер генерирует способ получения результата. Пример декларативного языка: SQL.
Напоминаем, что вы можете задать свой вопрос экспертам, а мы соберём на него ответы, если он окажется интересным. Вопросы, которые уже задавались, можно найти в списке выпусков рубрики. Если вы хотите присоединиться к числу экспертов и прислать ответ от вашей компании или лично от вас, то пишите на experts@tproger.ru, мы расскажем, как это сделать
Декларативный и императивный подход написания кода
Сегодня мы коснемся темы функционального программирования, а именно различия между декларативным и императивным программированием.
Сначала давай быстро пробежимся по терминам, а потом сравним эти стили программирования и посмотрим, как они отражаются в Java и могут ли сосуществовать в данном языке.
Функциональное программирование — это парадигма, в которой процесс вычисления определяется вычислением значений функций в математическом их понимании, а не в понимании подпрограмм, как в процедурном программировании . То есть в этих двух парадигмах значение слова “функция” трактуется по-разному. Это нужно запомнить и не путать. В Java ты с этим не запутаешься: функции в значении подпрограмм — это “методы”, а функции как математические функции — это просто “функции” (также: лямбда-функции или method reference).
На практике в процедурном программировании функции зависят не только от входных переменных, но и от внешних факторов (например, других переменных вне функции или состояния системы). Таким образом при вызове одной и той же функции с одинаковыми аргументами в различном контексте могут получаться разные результаты. В функциональном же программировании при вызове функции с одинаковыми аргументами мы всегда получаем одинаковый результат, так как функции зависят только от входных данных.
Положительные стороны функционального программирования
- Повышение надежности кода
- Удобство организации модульного тестирования
- Возможности оптимизации кода при компиляции
- Возможности параллелизма
Отрицательные стороны функционального программирования
Недостатки функционального программирования вытекают из все тех же его особенностей:
- Отсутствие присваиваний и замена их на порождение новых данных приводят к необходимости постоянного выделения и автоматического освобождения памяти. Поэтому в системе исполнения функциональной программы обязательным компонентом становится высокоэффективный сборщик мусора.
- Нестрогая модель вычислений приводит к непредсказуемому порядку вызова функций, что создает проблемы при вводе-выводе, где порядок выполнения операций важен.
Краткая справка по функциональному программированию завершена, теперь перейдем непосредственно к стилям программирования.
Императивное программирование — это парадигма программирования, для которой характерны следующие черты:
- В исходном коде программы записываются инструкции (команды).
- Инструкции должны выполняться последовательно.
- Данные, получаемые при выполнении предыдущих инструкций, могут читаться из памяти последующими инструкциями.
- Данные, полученные при выполнении инструкции, могут записываться в память.
Основные черты императивных языков:
- Использование именованных переменных.
- Использование оператора присваивания.
- Использование составных выражений.
- Использование подпрограмм.
Императивная программа похожа на приказы, выражаемые повелительным наклонении в естественных языках, то есть представляют собой последовательность команд.
К императивным языкам программирования относятся C, C++.
Декларативное программирование — парадигма программирования, в которой задается спецификация решения задачи, то есть описывается конечный результат, а не способ его достижения. В качестве примеров декларативных языков можно привести язык разметки HTML. При написании тегов в этом языке мы не задумываемся о том, как элементы будут отрисовываться на странице, мы просто описываем, как эта страница должна выглядеть.
Другой язык декларативного программирования — SQL.
Чтобы сравнить два стиля программирования , рассмотрим пример из реальной жизни: как объяснить человек, как добраться до какого-то места?
Представим ситуацию: к нам подошел человек на улице и спросил: “Как пройти к музею N?”
При императивном подходе мы бы объясняли ему алгоритм того, как добраться туда пешком:
При декларативном же подходе мы просто называем адрес, а дальше человек сам, своими силами (инструментами) добирается до нужного места.
Java же на данный момент является мультипарадигмальным языком программирования . Мультипарадигменность заключается в том, что язык поддерживает несколько парадигм.
Во время своего долгого развития язык расширял свою объектно-ориентированную модель для того, чтобы его пользователи получали различные инструменты и могли выбрать лучший для решения каждой конкретной задачи.
Поэтому на данный момент Java поддерживает как и императивный (например, написание кода вызовов методов), так и декларативный подход (например, аннотации, доступные в Runtime).
Подведем итог:
- Существуют различные парадигмы программирования.
- Есть декларативный и императивный подходы.
- Выбирать стоит тот, который лучше будет справляться с решением поставленных задач.
- Java — мультипарадигменный язык, поддерживающий оба подхода.