«Забытые» парадигмы программирования

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

Ладно. Введение это очень весело, но вы его все равно не читаете, так что кому интересно — добро пожаловать под кат!

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

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

В более высокоуровневых (таких как Си) состояние — это только память, инструкции могут быть сложнее и вызывать выделение и освобождение памяти в процессе своей работы.

В совсем высокоуровневых (таких как Python, если на нем программировать императивно) состояние ограничивается лишь переменными, а команды могут представлять собой комплексные операции, которые на ассемблере занимали бы сотни строк.

Основные понятия:  — Инструкция— СостояниеПорожденные понятия:  — Присваивание— Переход— Память— УказательЯзыки поддерживающие данную парадигму: Как основную:  — Языки ассемблера— Fortran— Algol— Cobol— Pascal— C— C++— AdaКак вспомогательную:  — Python— Ruby— Java— C#— PHP— Haskell (через монады)Стоит заметить, что большая часть современных языков в той или иной степени поддерживает императивное программирование. Даже на чистом функциональном языке Haskell можно писать императивно.

Структурное программирование a13680700ca4fb8822c8ebceee7b04d4.pngСтруктурное программирование — парадигма программирования (также часто встречающееся определение — методология разработки), которая была первым большим шагом в развитии программирования.Основоположниками структурного программирования были такие знаменитые люди как Э. Дейкстра и Н. Вирт.

Языками-первопроходцами в этой парадигме были Fortran, Algol и B, позже их приемниками стали Pascal и C.

Ключевые моменты: Эта парадигма вводит новые понятия, объединяющие часто используемые шаблоны написания императивного кода.В структурном программировании мы по прежнему оперируем состоянием и инструкциями, однако вводится понятие составной инструкции (блока), инструкций ветвления и цикла.

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

Иногда goto все-же делает код читабельнее, благодаря чему он до сих пор широко используется, несмотря на все заявления его противников.

Основные понятия:  — Блок— Цикл— ВетвлениеЯзыки поддерживающие данную парадигму: Как основную:  — C— Pascal— BasicКак вспомогательную:  — C#— Java— Python— Ruby— JavaScriptПоддерживают частично: — Некоторые макроассемблеры (через макросы)

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

Процедурное программирование a5b512bce13e607007178266699e6ef4.pngОпять-же возрастающая сложность программного обеспечения заставила программистов искать другие способы описывать вычисления.Собственно еще раз были введены дополнительные понятия, которые позволили по-новому взглянуть на программирование.

Этим понятием на этот раз была процедура.

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

Ключевые моменты: Процедура — самостоятельный участок кода, который можно выполнить как одну инструкцию.В современном программировании процедура может иметь несколько точек выхода (return в C-подобных языках), несколько точек входа (с помощью yield в Python или статических локальных переменных в C++), иметь аргументы, возвращать значение как результат своего выполнения, быть перегруженной по количеству или типу параметров и много чего еще.

Основные понятия:  — ПроцедураПорожденные понятия:  — Вызов— Аргументы— Возврат— Рекурсия— ПерегрузкаЯзыки поддерживающие данную парадигму: Как основную:  — C— C++— Pascal— Object PascalКак вспомогательную:  — C#— Java— Ruby— Python— JavaScriptПоддерживают частично: — Ранний Basic

Стоит отметить, что несколько точек выхода из всех этих языков поддерживаются только в Python.

Модульное программирование 6907b1894c0f9fa16592c05add5f3358.pngКоторый раз увеличивающаяся сложность программ заставила разработчиков разделять свой код. На этот раз процедур было недостаточно и в этот раз было введено новое понятие — модуль.Забегая вперед скажу, что модули тоже оказались неспособны сдержать с невероятной скоростью растущую сложность ПО и в последствии появились пакеты (это тоже модульное программирование), классы (это уже ООП), шаблоны (обобщенное программирование).

Программа описанная в стиле модульного программирования — это набор модулей. Что внутри, классы, императивный код или чистые функции — не важно.

Благодаря модулям впервые в программировании появилась серьезная инкапсуляция — возможно использовать какие-либо сущности внутри модуля, но не показывать их внешнему миру.

Ключевые моменты: Модуль — это отдельная именованная сущность программы, которая объединяет в себе другие программные единицы, близкие по функциональности.Например файл List.mod включающий в себя класс Listи функции для работы с ним — модуль.

Папка Geometry, содержащая модули Shape, Rectangle и Triangle — тоже модуль, хоть и некоторые языки разделяют понятие модуля и пакета (в таких языках пакет — набор модулей и/или набор других пакетов).

Модули можно импортировать (подключать), для того, чтобы использовать объявленные в них сущности.

Основные понятия:  — Модуль— ИмпортированиеПорожденные понятия:  — Пакет— ИнкапсуляцияЯзыки поддерживающие данную парадигму: Как основную:  — Haskell— Pascal— PythonКак вспомогательную:  — Java— C#— ActionScript 3Поддерживают частично: — C/C++

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

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

© Habrahabr.ru