Jump to content

Сравнение парадигм программирования

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

подходы парадигмы Основные

Существует два основных подхода к программированию: [1]

Следующие широко считаются основными парадигмами программирования, как видно при измерении популярности языков программирования:

Ниже приведены распространенные типы программирования, которые можно реализовать с использованием различных парадигм:

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

Парадигма Описание Поглаживания рук Связанные парадигмы Критика Примеры
Императив Программы как операторы , которые напрямую изменяют вычисленное состояние ( поля данных ). Прямые присваивания , общие структуры данных , глобальные переменные. Эдсгер В. Дейкстра , Майкл А. Джексон C , C++ , Java , Котлин , PHP , Python , Ruby
Структурированный Стиль императивного программирования с более логичной структурой программы. Структограммы , отступы , отсутствие или ограниченное использование перехода операторов . Императив C , C++ , Java , Котлин , Паскаль , PHP , Python
процедурный Получен из структурного программирования, основанного на концепции модульного программирования или вызова процедур. Локальные переменные , последовательность, выбор, итерация и модуляризация Структурированный, императивный C , С++ , Лисп , PHP , Питон
Функциональный Рассматривает вычисления как оценку математических функций, избегая состояния и изменяемых данных. Лямбда-исчисление , композиционность , формулы , рекурсия , ссылочная прозрачность , отсутствие побочных эффектов Декларативный С++ , [2] С# , [3] [ циклическая ссылка ] Кложур , Кофескрипт , [4] Elixir , Erlang , F# , Haskell , Java (начиная с версии 8), Kotlin , Lisp , Python , R , [5] Ruby , Scala , SequenceL , Standard ML , JavaScript , Elm
Управляемый событиями, в том числе управляемый временем Поток управления определяется в основном событиями , такими как щелчки мыши или прерывания, включая таймер. Основной цикл , обработчики событий, асинхронные процессы Процедурный, поток данных JavaScript , ActionScript , Visual Basic , Элм
Объектно-ориентированный Рассматривает поля данных как объекты, манипулируемые предопределенными методами. только Объекты , методы, передача сообщений , сокрытие информации , абстракция данных , инкапсуляция , полиморфизм , наследование , сериализация -маршалинг. процедурный См. подборку критики и другие материалы. [6] [7] [8] Common Lisp , C++ , C# , Eiffel , Java , Kotlin , PHP , Python , Ruby , Scala , JavaScript [9] [10]
Декларативный Определяет логику программы, но не подробный поток управления. Языки четвертого поколения , электронные таблицы , генераторы программ отчетов SQL , регулярные выражения , Пролог , OWL , SPARQL , журнал данных , XSLT
Программирование на основе автоматов Рассматривает программы как модель конечного автомата или любого другого формального автомата. состояний Перечисление , управляющая переменная , изменения состояний , изоморфизм , таблица переходов состояний Императивный, управляемый событиями Язык абстрактного государственного автомата

Различия в терминологии [ править ]

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

Языковая поддержка [ править ]

Синтаксический сахар — это улучшение функциональности программы за счет введения языковых функций, облегчающих конкретное использование, даже если результат можно было бы достичь и без них. Одним из примеров синтаксического сахара могут быть классы, используемые в объектно-ориентированных языках программирования. Императивный язык C может поддерживать объектно-ориентированное программирование посредством указателей на функции , приведения типов и структур. Однако такие языки, как C++, стремятся сделать объектно-ориентированное программирование более удобным, вводя синтаксис, специфичный для этого стиля кодирования. Более того, специализированный синтаксис подчеркивает объектно-ориентированный подход. Точно так же функции и синтаксис циклов в C (и других процедурных и структурированных языках программирования) можно считать синтаксическим сахаром. Язык ассемблера может поддерживать процедурное или структурированное программирование благодаря своим возможностям изменения значений регистров и выполнения ветвления в зависимости от состояния программы. Однако в таких языках, как C, был введен синтаксис, специфичный для этих стилей кодирования, чтобы сделать процедурное и структурированное программирование более удобным. Особенности языка C# (C Sharp), такие как свойства и интерфейсы, также не содержат новых функций, но предназначены для того, чтобы сделать хорошие практики программирования более заметными и естественными.

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

Расширением этого является синтаксический сахарин или необоснованный синтаксис, который не облегчает программирование. [11]

Сравнение производительности [ править ]

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

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

Управляемый код [ править ]

Для программ, выполняющихся в среде управляемого кода , такой как платформа .NET , многие проблемы влияют на производительность, на которую существенно влияют парадигма языка программирования и различные используемые языковые функции. [12]

Примеры псевдокода, сравнивающие различные парадигмы [ править ]

Сравнение псевдокода , регистровую императивного, процедурного и объектно-ориентированного подходов, используемых для вычисления площади круга (πr²), предполагая отсутствие встраивания подпрограмм , отсутствие макросов препроцессоров арифметику и взвешивание каждого «шага» инструкции как всего лишь 1 инструкции – как Грубая мера длины пути инструкции – представлена ​​ниже. Шаг инструкции, который концептуально выполняет изменение состояния, в каждом случае выделен жирным шрифтом. Арифметические операции, используемые для вычисления площади круга, одинаковы во всех трех парадигмах, с той разницей, что процедурная и объектно-ориентированная парадигмы заключают эти операции в вызов подпрограммы, что делает вычисление общим и пригодным для повторного использования. Тот же эффект может быть достигнут в чисто императивной программе, использующей препроцессор макросов, только за счет увеличения размера программы (только на каждом месте вызова макроса) без соответствующих пропорциональных затрат времени выполнения (пропорциональных n вызовов - которые могут быть расположены в пределах внутренний цикл , например). И наоборот, встраивание подпрограмм компилятором может уменьшить размер процедурных программ до размера, близкого к чисто императивному коду. Однако для объектно-ориентированных программ, даже со встраиванием, сообщения все равно необходимо создавать (из копий аргументов) для обработки объектно-ориентированными методами. Накладные расходы на вызовы, виртуальные или иные, зависят не от изменения потока управления , а от затрат на сопутствующие соглашения о вызовах , таких как код пролога и эпилога , настройка стека и аргументов . передача [13] (см. здесь [14] для более реалистичной длины пути инструкций, стека и других затрат, связанных с вызовами на платформе x86 ). См. также здесь [15] для слайд-презентации Эрика С. Робертса («Выделение памяти переменным», глава 7) [16] – иллюстрация использования стека и кучи памяти при суммировании трех рациональных чисел в объектно-ориентированном языке Java .

Императив процедурный Объектно-ориентированный
 load r;                      1
 r2 = r * r;                  2
 result = r2 * "3.142";       3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.... storage .............
result variable
constant "3.142"
area proc(r2,res):
   push stack                                 5
   load r2;                                   6
   r3 = r2 * r2;                              7
   res = r3 * "3.142";                        8
   pop stack                                  9
   return;                                   10
...............................................
main proc:
   load r;                                    1
   call area(r,result);
    +load p = address of parameter list;      2
    +load v = address of subroutine 'area';   3
    +goto v with return;                      4
.
.
.
.
.... storage .............
result variable
constant "3.142"
parameter list variable
function pointer (==>area)
stack storage
circle.area method(r2):
   push stack                                 7
   load r2;                                   8
   r3 = r2 * r2;                              9
   res = r3 * "3.142";                       10
   pop stack                                 11
   return(res);                           12,13
...............................................
main proc:
   load r;                                    1
   result = circle.area(r);
      +allocate heap storage;                 2[See 1]
      +copy r to message;                     3
      +load p = address of message;           4
      +load v = addr. of method 'circle.area' 5
      +goto v with return;                    6
.
.
.... storage .............
result variable (assumed pre-allocated)
immutable variable "3.142" (final)
(heap) message variable for circle method call
vtable(==>area)
stack storage

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

Подпрограмма, накладные расходы на вызов метода [ править ]

Наличие (называемой) подпрограммы в программе не вносит ничего дополнительного в функциональность программы независимо от парадигмы, но может в значительной степени способствовать структурированию и универсальности программы, значительно упрощая ее написание, изменение и расширение. [17] Степень, в которой различные парадигмы используют подпрограммы (и соответствующие требования к памяти), влияет на общую производительность всего алгоритма, хотя, как отметил Гай Стил в статье 1977 года, хорошо спроектированная реализация языка программирования может иметь очень низкие накладные расходы на процедурную абстракцию. (но в большинстве реализаций сетует, что на практике этого редко достигают - будучи «довольно необдуманными или небрежными в этом отношении»). В той же статье Стил также приводит аргументы в пользу автоматного программирования (с использованием вызовов процедур с хвостовой рекурсией ) и приходит к выводу, что «мы должны относиться к вызовам процедур со здоровым уважением» (потому что они мощные), но предлагает «использовать их экономно». " [17]

По частоте вызовов подпрограмм:

  • Для процедурного программирования степень детализации кода во многом определяется количеством дискретных процедур или модулей .
  • Для функционального программирования обычным является частый вызов библиотечных подпрограмм. [ нужна ссылка ] но часто может быть встроен оптимизирующим компилятором
  • В объектно-ориентированном программировании количество вызываемых вызовов методов также частично определяется степенью детализации структур данных и, таким образом, может включать в себя множество доступов только для чтения к объектам низкого уровня, которые инкапсулированы и, следовательно, не доступны никаким другим, более прямым, способом. способ. Поскольку повышенная степень детализации является предпосылкой для большего повторного использования кода , наблюдается тенденция к более мелкозернистым структурам данных и соответствующему увеличению количества дискретных объектов (и их методов) и, следовательно, вызовов подпрограмм. Создание божественных объектов активно не поощряется. Конструкторы также увеличивают счет, поскольку они также являются вызовами подпрограмм (если они не встроены). Проблемы с производительностью, вызванные чрезмерной детализацией, могут не проявиться до тех пор, пока масштабируемость не станет проблемой.
  • Для других парадигм, где может использоваться сочетание вышеуказанных парадигм, использование подпрограмм менее предсказуемо.

Выделение динамической памяти для хранения сообщений и объектов [ править ]

Уникальность объектно-ориентированной парадигмы заключается в динамическом выделении памяти из динамической памяти как для создания объектов, так и для передачи сообщений. Тест 1994 года «Затраты на выделение памяти в больших программах на C и C++», проведенный Digital Equipment Corporation на различном программном обеспечении с использованием инструмента профилирования на уровне инструкций, измерял, сколько инструкций требуется для динамического выделения памяти. Результаты показали, что наименьшее абсолютное количество выполненных инструкций в среднем составляло около 50, но другие достигали 611. [18] См. также «Куча: удовольствия и боли» Мурали Р. Кришнана. [19] в котором говорится: «Реализации кучи, как правило, остаются общими для всех платформ и, следовательно, имеют большие накладные расходы». Статья IBM 1996 года «Масштабируемость алгоритмов динамического распределения памяти», написанная Аруном Айенгаром из IBM. [20] демонстрирует различные алгоритмы динамического хранения и соответствующее количество инструкций. Даже рекомендуемый алгоритм MFLF I (HS Stone, RC 9674) показывает количество инструкций в диапазоне от 200 до 400. Приведенный выше пример псевдокода не включает в себя реалистичную оценку длины этого пути выделения памяти или задействованных накладных расходов префикса памяти и последующего связанного с этим мусора. сбор накладных расходов. Настоятельно предполагая, что распределение кучи — нетривиальная задача, один с открытым исходным кодом программный микрораспределитель , созданный разработчиком игр Джоном Рэтклиффом , состоит почти из 1000 строк кода. [21]

Динамически отправляемые вызовы сообщений и накладные расходы на вызов процедур прямой

В своем реферате « Оптимизация объектно-ориентированных программ с использованием статического анализа иерархии классов » [22] Джеффри Дин, Дэвид Гроув и Крейг Чемберс с факультета компьютерных наук и инженерии Вашингтонского университета утверждают, что «интенсивное использование наследования и динамически связанных сообщений, вероятно, сделает код более расширяемым и пригодным для повторного использования, но это также налагает значительные издержки производительности по сравнению с эквивалентной, но нерасширяемой программой, написанной необъектно-ориентированным способом. В некоторых областях, таких как пакеты структурированной графики, цена дополнительной гибкости, обеспечиваемой использованием сильно объектно-ориентированного стиля. Однако в других областях, таких как библиотеки базовых структур данных, пакеты численных вычислений, библиотеки рендеринга и среды моделирования на основе трассировки, стоимость передачи сообщений может быть слишком велика, что вынуждает программиста избегать объектно-ориентированного программирования. «горячие точки» их применения».

Сериализация объектов [ править ]

Сериализация приводит к большим накладным расходам при передаче объектов из одной системы в другую, особенно когда передача осуществляется в удобочитаемых форматах, таких как расширяемый язык разметки ( XML ) и нотация объектов JavaScript ( JSON ). Это контрастирует с компактными двоичными форматами необъектно-ориентированных данных. В процессе сериализации участвуют как кодирование, так и декодирование значения данных объекта и его атрибутов, что также включает в себя понимание сложных проблем, таких как наследование, инкапсуляция и сокрытие данных.

Параллельные вычисления [ править ]

Университета Карнеги-Меллона Профессор Роберт Харпер в марте 2011 года писал: «В этом семестре мы с Дэном Ликатой совместно читаем новый курс по функциональному программированию для первокурсников, желающих получить специальность по информатике... Объектно-ориентированное программирование полностью исключено из вводной учебной программы. , поскольку он по своей природе одновременно антимодулен и антипараллелен и, следовательно, не подходит для современной учебной программы по информатике. Предлагаемый новый курс по методологии объектно-ориентированного проектирования будет предлагаться на втором курсе для тех студентов, которые хотят учиться. эту тему». [23]

См. также [ править ]

Ссылки [ править ]

  1. ^ «Парадигмы программирования: каковы принципы программирования?» . ИОНОС . Проверено 30 мая 2022 г.
  2. ^ «Архивная копия» (PDF) . Архивировано из оригинала (PDF) 02 февраля 2017 г. Проверено 18 декабря 2015 г. {{cite web}}: CS1 maint: архивная копия в заголовке ( ссылка )
  3. ^ «Функциональное программирование C#» . август 2020 года . Проверено 14 августа 2015 г.
  4. ^ Руис, Седрик (май 2014 г.). «Функциональный CoffeeScript для нетерпеливых» . Блог Седрика Руиса . Седрик Руис . Проверено 9 августа 2015 г.
  5. ^ «Функциональное программирование · Advanced R» .
  6. ^ Шелли, Асаф (22 августа 2008 г.). «Ошибки объектно-ориентированного моделирования» . Сеть программного обеспечения Intel . Проверено 4 июля 2010 г.
  7. ^ Йегге, Стив (30 марта 2006 г.). «Казнь в царстве существительных» . steve-yegge.blogspot.com . Проверено 3 июля 2010 г.
  8. ^ «Data-Oriented Design (или почему вы можете выстрелить себе в ногу с помощью ООП) – игры изнутри» .
  9. ^ Крокфорд, Дуглас. «JavaScript: самый непонятый язык программирования в мире» . crockford.com.
  10. ^ Крокфорд, Дуглас. «Частные члены в JavaScript» . crockford.com.
  11. ^ «Файл жаргона v4.4.7: «синтаксический сахар» » .
  12. ^ Грей, Ян (июнь 2003 г.). «Написание более быстрого управляемого кода: знайте, чего это стоит» . MSDN . Майкрософт.
  13. ^ «Реальная стоимость звонков» . WordPress.com. 30 декабря 2008 г.
  14. ^ «Диассемблирование/функции X86 и фреймы стека — Wikibooks, открытые книги для открытого мира» .
  15. ^ Робертс, Эрик С. (2008). «Искусство и наука Java; Глава 7: Объекты и память» . Стэнфордский университет. Архивировано из оригинала 6 июня 2011 г. Проверено 17 мая 2010 г.
  16. ^ Робертс, Эрик С. (2008). Искусство и наука Явы . Аддисон-Уэсли. ISBN  978-0-321-48612-7 . Архивировано из оригинала 6 июня 2011 г. Проверено 17 мая 2010 г.
  17. Перейти обратно: Перейти обратно: а б Гай Льюис Стил-младший «Разоблачение мифа о« дорогом вызове процедур », или Реализации вызовов процедур, считающиеся вредными, или Лямбда: окончательный вариант GOTO». Лаборатория искусственного интеллекта Массачусетского технологического института. Памятка лаборатории искусственного интеллекта AIM-443. Октябрь 1977 г. [1] Архивировано 29 декабря 2009 г. в Wayback Machine [2] [3]
  18. ^ Детлефс, Дэвид; Доссер, Эл; Зорн, Бенджамин (июнь 1994 г.). «Стоимость выделения памяти в больших программах на C и C++; страница 532». Программное обеспечение: практика и опыт . 24 (6): 527–542. CiteSeerX   10.1.1.30.3073 . дои : 10.1002/спе.4380240602 . S2CID   14214110 .
  19. ^ Кришнан, Мурали Р. (февраль 1999 г.). «Куча: Удовольствия и боли» . microsoft.com.
  20. ^ «Масштабируемость алгоритмов динамического распределения памяти». 1996. CiteSeerX   10.1.1.3.3759 .
  21. ^ "Микроаллокатор.h" . Гугл-код . Проверено 29 января 2012 г.
  22. ^ Дин, Джеффри; Гроув, Дэвид; Чемберс, Крейг (1995). «Оптимизация объектно-ориентированных программ с использованием статического анализа иерархии классов». Объектно-ориентированное программирование . Конспекты лекций по информатике. Том. 952. Вашингтонский университет. стр. 77–101. CiteSeerX   10.1.1.117.2420 . дои : 10.1007/3-540-49538-X_5 . ISBN  978-3-540-60160-9 .
  23. ^ Преподавание FP первокурсникам , из блога Харпера о преподавании вводных информатики. [4]

Дальнейшее чтение [ править ]

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: ec8e37cf12f64e33afcbabe33bf6adcd__1706817900
URL1:https://arc.ask3.ru/arc/aa/ec/cd/ec8e37cf12f64e33afcbabe33bf6adcd.html
Заголовок, (Title) документа по адресу, URL1:
Comparison of programming paradigms - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)