Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Классификация языков программирования.Критерии выбора среды и языка разработки программ ( Основная терминология программирования)

Содержание:

ВВЕДЕНИЕ

Данная работа посвящена классификации языков и сред программирования, специфике и проблемам, возникающим с конкретными языками программирования в ходе разработки программных продуктов в конце XX – начале XXI века.

На сегодняшний день количество средств для разработки ПО, подходов к разработке ПО и разнообразных программных решений вкупе со стандартами и сопроводительной документацией – настолько велико, а концепции, существовавшие ещё во второй половине XX века вполне обособленно друг от друга – настолько переплетены и интегрированы друг с другом, что проблема относительно точной систематизации всех накопившихся решений и опыта полностью заслуживает обсуждения. Это стало одним из факторов написания работы по этой теме.

Объектом исследования данной работы являются языки программирования.

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

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

  • Проанализировать фундаментальные концепции и составить терминологический аппарат.
  • Рассмотреть реализацию данных концепций на примере конкретных языков, попутно рассмотрев их особенности и перспективы, и описав их в рамках терминологического аппарата.
  • Рассмотреть практику использования языков программирования и IDE для них, описав попутно потребности нескольких секторов IT-отрасли в тех или иных технологиях.
  • Выработать единую методику для оценки качества жизненного цикла ПО.
  • Проверить методику на практическом примере, в рамках одной из отраслей.

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

В Главе 2 рассматриваются примеры реализации концепций из Главы 1 теми или иными языками, описываются их возможности и ограничения. В качестве примеров для классификации выбраны языки, занимавшие в 2017-м году первые 5 позиций в рейтингах компании TIOBE и профильного журнала IEEE Spectrum одновременно (стоит отметить, что они совпадают). Они будут рассматриваться с точки зрения теоретических концепций, проанализированных в Главе 1, и в конце Главы 2 будет практически проверена методика поиска оптимального языка, выработанная в Главе 1, на примере конкретной задачи и выборки данных по результатам обзора языков.

В Главе 3 рассматривается статистика использования нескольких сред разработки. В работе будут рассмотрены среды разработки, удовлетворяющие максимальные потребности пользователей и одновременно имеющие широкую известность, исходя из данных таблицы Leaders отчёта крупного исследования компании G2 Crowd за 2017-й год; в качестве второго источника, для уже более подробного сравнения сред, была выбрана статья Лучанинова и Ленкина 2016-го года. Третьим источником служит актуальный на момент зимы 2018 года рейтинг статистического портала TrustRadius. Будут рассмотрены среды, упомянутые во всех источниках информации, а также имеющие в той или иной мере актуальную поддержку всех языков из Главы 2. Аналогично, будет проведено исследование их эффективности для решения одной из задач.

На основании информации, описанной в главах данной работы, делаются суждения о возможностях той или иной технологии программирования для той или иной задачи. В качестве источников информации для работы намеренно было отдано предпочтение работам высококвалифицированных практиков, статьям из технических журналов, посвящённых международной практике IT, а также национальным и международным техническим стандартам (ГОСТ, ECMA). В качестве источников информации по тем или иным конкретным технологиям используются официальные технические документы крупных компаний (Microsoft, Oracle) и отдельных проектов (Mono, NetBeans, Python, Android). Значительная часть этих источников в контексте работы дублирует друг друга, для объективности.

Основными теоретическими источниками послужили работы Карделли, Барендрегта, несколько учебно-методических русскоязычных изданий (такие как «Архитектура компьютера» Таненбаума, «Теория и практика языков программирования» Орлова), и несколько государственных стандартов РФ. Надёжность и достоверность данных источников трудно переоценить, потому что многие из них фактически заложили основы современной программной инженерии. Среди книг по языкам программирования, использованных в ходе подготовки материала, стоит выделить труды Кернигана и Ритчи, Гослинга, Рихтера, Страуструпа, так как. эти авторы принимали непосредственное участие в создании описываемых ими технологий. Также, были использованы книги справочного и учебного характера – труды Бизли по Python, Шилдта по Java, Подбельского по C#.

1. Теоретические концепции языков программирования и программных сред

1.1. Основная терминология программирования

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

Программирование - процесс проектирования определённых последовательностей инструкций, направленных на решение определённой задачи (т.н. алгоритмов)[1], для дальнейшей реализации этих алгоритмов, транслированных в технические данные, вычислительной техникой (в частности, компьютером)[2]. Запись алгоритма, предназначенная для реализации таким способом, называется программой, а работоспособная программа вместе с технической документацией по её эксплуатации – программным обеспечением (ПО)[3]. Создание программного обеспечения, как и разработка любых алгоритмов вообще, является тяжёлым и кропотливым процессом, требующим высоких созидательных и аналитических способностей, а потому на момент второй половины XX – первой половины XXI века, разработка ПО является уделом людей[4].

То, какие команды исполняет процессор, определяется архитектурой команд процессора[5]. В совокупности, язык, на котором исполняются команды процессора, называется машинным языком[6]. Команды на машинном языке, в соответствии с принципами программного управления Джона фон Неймана, помещаются перед выполнением в основную память, на оперативное запоминающее устройство (ОЗУ) [9, с. 43 – 45].

Язык программирования (ЯП) – это формальный язык, предназначенный для человекочитаемого (но при этом достаточно чёткого) описания логики программы. В современном мире программы в буквальном смысле пишутся на языках программирования. Получившийся текст называется исходным, и в дальнейшем, благодаря своей однозначности, может быть переведён в машинный код и исполнен[7].

Каждый язык программирования обладает своим уникальным синтаксисом. Синтаксис, в свою очередь, состоит из примитивных элементов - атомов. Атомы обычно не описываются в исходном тексте сами по себе, а комбинируются в т.н. лексемы, минимально допустимые синтаксические конструкции[8]. С точки зрения семантики, синтаксис языков программирования в обязательном порядке предоставляет программисту средства для описания данных, используемых в программе, и действий, производимых над данными. Данные, используемые программой, могут быть изменяемыми и неизменяемыми. Изменяемые элементы данных называются переменными, а неизменяемые - константами. Выражение – явное описание минимального законченного действия, которое может совершить программа с данными для получения одного результата. Данные, участвующие в выражении, называются операндами[9]. Данные классифицируются по типам. Объекты данных с похожими наборами значений, функционированием, и объёмом занимаемой памяти[10], можно рассматривать как объекты с одинаковым типом данных[11].

Технические инструменты, используемые программистами для создания программного обеспечения, часто собираются в одну программу, называемую средой разработки (IDE). Иногда среда разработки включает также системы контроля версий и браузеры компонентов программы. Такой подход повышает удобство разработки и сопровождения программного обеспечения. Также любая такая среда может быть адаптирована под нужды определённого разработчика. Использование IDE тесно связано с моделью разработки программного обеспечения – совокупностью объектов и операций, определяющих процессы, совершаемые программистом[12].

1.2. Классификация языков программирования по способу исполнения программ

Готовый исходный текст программы должен быть понят компьютером. На практике за любое понимание исходного текста машиной отвечает транслятор, или его подвид[13], интерпретатор. Строго говоря, транслятор отвечает не только за подготовку программы к запуску в машинном коде, но и вообще за любой её перевод с одного ЯП на другой (в т. ч. и в машинный код)[14]. Язык, на который должна быть транслирована исходная программа, называется целевым (выходным)[15]. И в этом аспекте языки программирования делятся на 2 большие группы: компилируемые (транслируемые) и интерпретируемые[16]. Также существуют комбинированные варианты реализации исходных текстов языков[17], в частности, при помощи технологии виртуальных машин. Виртуальная машина – это фактически программная (иногда и аппаратная [32]) надстройка над аппаратным компьютером, позволяющая смоделировать на нём абстрактный компьютер с компилируемым или интерпретируемым языком в роли машинного кода[18]. Реализацию исходного текста посредством виртуальной машины сложно описать с точки зрения чистой трансляции или чистой интерпретации[19].

В компилируемых языках исходный текст сразу переводится в машинный код или в промежуточный код виртуальной машины, на стороне программиста, в составе специального ПО для компиляции (компилятора либо ассемблера)[20]. Транслятор компилируемого в машинный код языка собирает из исходной программы программу в машинных кодах, пригодную для выполнения. Некоторые особенности трансляции в машинный код:

  • Быстродействие получившейся программы: компьютер конечного пользователя сразу приступает к выполнению программы, написанной понятным процессору машинным языком.
  • Конечному пользователю не требуется ничего, кроме самой программы и совместимого аппаратного обеспечения, для её запуска[21]
  • Сложность восстановления исходного текста при наличии только выходного исполняемого файла[22].
  • Результаты компиляции в машинный код представляют собой инструкции для строго определённого типа компьютеров[23].
  • Программа полностью загружает себя в память, засоряя её.

Программа на интерпретируемом языке распространяется, как правило, в виде упрощённого промежуточного представления исходного кода, либо в исходной форме. В ходе её обработки на компьютере конечного пользователя специальной программой-интерпретатором, каждая необходимая в данный момент команда в коде транслируется, и программа выполняется покомандно[24]. Некоторые особенности интерпретируемых языков:

  • Программа переводится в машинный код последовательно по ходу своего выполнения, т.е. некоторые части программы могут быть никогда не обработаны, если это не потребовалось по ходу выполнения программы[25]
  • Учитывая, что программа транслируется в машинный язык только на стороне пользователя, ответственность за аппаратную совместимость перекладывается с программиста на пользователя и его интерпретатор.
  • Интерпретация может отрицательно повлиять на производительность, т.к. в отличие от компиляции реальный процессор получает машинный код для выполнения дольше[26].
  • В случае если потребуется повторное использование элементов программы, они будут интерпретированы несколько раз, тратя лишнее время.

У интерпретируемых языков есть специфический подвид – скриптовые (сценарные) ЯП[27]. Файлы этих языков представляют собой сценарии (скрипты), и предназначаются для модульного, иногда опционального, использования в больших проектах. Скриптовые ЯП ориентируются на применение в этой отрасли, и успешно используются для Интернет-проектов, крупного модульного ПО и системного администрирования[28].

Компиляцию и интерпретацию во многих современных языках стараются совмещать, чтобы скомбинировать их достоинства[29]. Наиболее наглядная такая система исполнения программы упоминается в трудах Э. Таненбаума как «Just-In-Time (JIT) компиляция». Она тесно связана с концепцией виртуальной машины. Некоторые особенности JIT-компилируемых языков:

  • Код, написанный программистом, транслируется в компактный промежуточный код виртуальной машины.
  • При интерпретации промежуточного кода для исполнения, виртуальная машина перед первым использованием каждого отдельного участка кода фактически компилирует и временно сохраняет его в памяти.
  • Повторное использование уже скомпилированного фрагмента кода происходит также быстро, как и при классической компиляции: его не требуется транслировать в машинный язык заново.
  • Пока участок кода не используется, он может не компилироваться[30], что позволяет избежать затрат ресурсов, присущих обычной компиляции.

1.3. Классификация языков программирования по уровню детализации

Детализированность алгоритмов на ЯП определяет его уровень. Языки высокого уровня удобны для восприятия человеком[31]. Также, уровень языка тесно связан со степенью его зависимости от аппаратного обеспечения. Чем выше ориентация ЯП на конкретную архитектуру набора команд и чем больше в нём технических деталей[32], ухудшающих восприятие кода программистом, тем ниже уровень языка. Всего по этим критериям выделяют следующие категории языков[33] [34]: машинные языки, ЯП ассемблерного типа, и высокоуровневые ЯП. Также, частным случаем уровня детализации работы с аппаратным обеспечением может являться способ работы языка с памятью.

Начнём с машинных языков. Данная категория языков самая древняя, и, по сути, является не языком, а способом кодирования машинных инструкций, предложенным Джоном фон Нейманом в 1945 году. Любой современный компьютер является реализацией множества его идей, включая эту. Каждая команда машинного языка, построенная по принципам фон Неймана, целиком и полностью состоит из двоичных цифр, объединённых в минимальные блоки (байты и слова)[9]. Таким образом, текстовая запись родного для компьютера машинного кода будет представлять собой набор нечитабельных для неподготовленного человека чисел, независимо от того, в какой системе счисления эти числа визуализированы. Программировать таким способом крайне тяжело и затратно, а код полностью зависим от процессора[35].

В связи с очевидным неудобством программирования в машинных кодах, команды процессоров были сгруппированы в соответствии с их функциональностью с точки зрения человека, и им были присвоены читабельные формальные наименования[36]. Так появились ассемблеры – программы для трансляции формальной алгоритмической записи инструкций процессора (т.н. язык ассемблера) в их машинную форму[37]. Язык ассемблерного типа, в отличие от машинного кода, может использоваться для наглядного и относительно читабельного описания алгоритма программы: он позволяет не отвлекаться на фактическое вычисление машинных инструкций[38]. Ассемблеры зависимы от набора команд процессора, а ассемблерные инструкции - повторяют процессорные инструкции[39].

Также существует очень специфический независимый от процессора подвид ассемблеров, появившийся в эпоху виртуальных машин и JIT-компиляции. Он транслирует инструкции не в машинный код аппаратного процессора, а в промежуточный код виртуальной машины[40]. Ассемблеры этого типа, таким образом, зависят не от аппаратной платформы, а от виртуальной машины и программной платформы. Такие языки чрезмерно специфичны, использование ассемблеров виртуальных машин на практике – явление довольно нечастое[41].

На этом эволюция языков программирования в плане оптимизации работы программиста не закончилась. Программировать на машинных и ассемблерных языках сложно, из-за необходимости думать не над решением прикладной задачи, а над описанием действий аппаратного обеспечения. Если задача, которую решает программист, достаточно масштабна, - низкоуровневое программирование только переусложнит её. Именно для облегчения условий работы прикладных программистов, и повышения их сосредоточенности на текущей задаче, и были разработаны языки высокого уровня[42]. Высокоуровневые лексемы не связаны прямо с функционалом процессора, а ориентированы на использование в прикладных целях, они сделаны похожими на естественные языки[43] и/или символическую математику, чтобы быть понятными программисту[44].

Помощь в реализации фактических конструкций высокоуровневых языков возложена на программный интерфейс приложений (API) и двоичный интерфейс приложений (ABI). Первый интерфейс может применяться силами самого программиста. Он включает различные высокоуровневые средства, помогающие программисту в решении прикладных задач. Ответственность за внутреннюю реализацию API лежит на его разработчиках. Второй интерфейс программист в большинстве случаев не может использовать явно, но именно он отвечает за реализацию семантики языка операционной системой и аппаратным обеспечением, отвечая за двоичную совместимость программного обеспечения [21].

Кроме этого, у высокоуровневых языков иногда бывает автоматизирована работа с памятью. Такую систему называют сборкой мусора [18]. В противовес преимущественно высокоуровневой сборке мусора, в высокоуровневых и низкоуровневых ЯП может существовать и явное освобождение памяти. Для явного оперирования памятью в высокоуровневых языках программирования, созданы специальные правила и идеомы, например, «resource acquisition is initialization» (RAII) в языке C++[45].

1.4. Классификация парадигм, реализуемых языками программирования

В связи с требованиями по решению прикладных задач, а также в связи с необходимостью упростить правила программирования, сделав их исходные тексты схожими с человеческой логикой, появлялось множество парадигм программирования. Рассмотрим наиболее устоявшиеся, независимо от классификатора, парадигмы[46] [47] [48]:

  • императивная
  • функциональная
  • декларативная
  • объектно-ориентированная

Рассмотрим сначала императивную парадигму. Минимальный лексический элемент управления у языков данной группы – оператор[49]. Действия над данными выражаются в виде последовательностей инструкций [2], выполнение каждой из которых изменяет состояние компьютера. Процедурная схема идеально отражает особенности компьютерной архитектуры Джона фон Неймана [8, с. 16]. Императивная программа представляет собой последовательность инструкций, выполняемых по порядку. Также присутствуют циклы – последовательности инструкций, которые могут выполняться по нескольку раз до выполнения определённого условия [50]. Процедурами называются именованные блоки машинных инструкций, которые можно вызвать удалённо из разных участков кода [1]. Возможен рекурсивный вызов процедур, однако такие приёмы программирования следует использовать осторожно из-за ограничений стековой памяти на многих компьютерных архитектурах [7, с. 99 – 101]. Любой императивный язык должен показывать, как именно должен быть реализован тот или иной алгоритм; зато, у процедурных программ высокая скорость выполнения[51]. Согласно некоторым расширенным классификациям, благодаря этому фактору, только процедурные языки могут быть низкоуровневыми[52]. Известным примером языка, созданного для процедурного программирования, является C.

Функциональная парадигма (также называемая в некоторых источниках[53] аппликативной) была предвосхищена математиком А. Чёрчем, в 30-х годах XX века создавшим лямбда-исчисление, в некотором смысле предок любого функционального языка [29].

Основная идея функционального программирования (ФП) – оперирование функциями, подвидом процедур [1], умеющим возвращать значение[54], для работы с данными. Из простых функций составляются более и более сложные функции, пока из начальных данных не будет получен желаемый результат [8, 15]. Ещё одной особенностью функциональной парадигмы является сознательный отказ от использования переменных. Долгое время реализация лямбда-исчисления на фон-неймановских компьютерных архитектурах считалась крайне сложной[55]. На относительно современных компьютерах (конца XX века – начала XXI века) функциональное программирование наконец-то обрело достойную реализацию. Это связано в основном с развитием параллельных вычислений; в частности, параллелизм может быть описан функциональным языком более лаконично, чем императивным, также эти технологии хорошо комбинируются. Функциональные языки программирования используются в математическом ПО и для создания Искусственного Интеллекта. Как и процедурное программирование, ФП демонстрирует, как именно должно выполняться то или иное программное действие[56], однако функциональное программирование часто противопоставляется императивному[57]. Классическим примером языка, созданного для ФП, является LISP.

Декларативная группа языков, как и функциональная группа, оперирует действиями для достижения конечного результата. На практике иногда даже отождествляют эти два понятия[58]. Однако парадигма декларативного программирования строится вокруг утверждения, что каждый шаг действий не должен описываться явно. Способ решения задачи в декларативных ЯП не описывается; вместо этого, основным предметом описания является сама задача и условия, при которых она может быть выполнена.

В некоторых источниках эта группа языков называется языками с системой правил[59], согласно же другим – языки системы правил являются лишь наиболее показательным подвидом декларативных языков[60]. Языки системы правил, также известные как языки логического программирования, не имеют чёткого порядка выполнения алгоритмов. Вместо этого, единственным, что влияет на порядок выполнения логических программ, являются т.н. разрешающие высказывания (условия) [8, с.18]. В программе задаются факты, являющиеся по сути своей данными, и аксиомы, связывающие каждое потенциальное действие программы с проверкой разрешающего условия. Действие будет выполнено только при соответствии условию. Самым известным языком логического программирования является Prolog.

Объектно-ориентированная парадигма представлена множеством языков, таких как C++ или Java. По данным некоторых источников, она значительно повышает производительность труда программиста[61] [62], позволяя работать с данными, имеющими прямое отношение к предметной области программы. Для этого, программа разбивается на осмысленные модули, именуемые объектами, и на функции, которые можно выполнить с тем или иным объектом, называемые методами. Важнейшую роль тут играют типы данных. Каждый объект имеет свой тип, и может наследовать черты объектов другого типа. Типы описываются программистом посредством своеобразных чертежей - классов[63].

Разработка объектно-ориентированных программ начинается с построения иерархий из классов [8, с. 19]. Некоторые готовые классы программист может получить из средств API [21]. Основные особенности классов и их методов, ставшие стандартом парадигмы объектно-ориентированного программирования (ООП):

- Внутренняя информация классов должна быть инкапсулирована, доступ к ней извне должен быть скрыт либо жёстко регламентирован; это обеспечивает контроль над несанкционированным или случайным произвольным изменением данных[64].

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

- Полиморфизм ad-hoc: возможность создать в разных классах, объединённых в одну иерархию, разные реализации наследуемого метода, и ссылаться на них из классов и методов внешнего контекста, как на один и тот же, несмотря на различия в реализации[66].

1.5. Критерии выбора сред и языков программирования

IDE должна реализовывать нужную модель разработки максимально удобно для программиста[67]. Данные вопросы, на примере платформы Java, изучала во второй половине 2000-х исследовательская группа в Вестминстерском Университете. В ходе исследования было решено создать несколько групп критериев. Часть критериев, независимая от Java [20]:

  • Интерфейс. Для оценки интерфейса IDE требовалось ответить на следующие вопросы: 2 вопроса про автодополнение кода, насколько хорош редактор кода, понятен и дружественен ли интерфейс, особенности навигации в IDE.
  • Развёртывание, тестирование и поддержка. Несколько вопросов о проверке кода на ошибки, тестировании, системе справки и поддержки, предоставляемой программисту.
  • Возможности подключения баз данных, различных сетевых служб. Производительность IDE на пике работы.

Раньше IDE рассматривались в контексте одного конкретного языка программирования[68], однако современные IDE – мультиязычные. Есть и современные исследования этого вопроса. Одна из таблиц исследования Grid℠ компании G2 Crowd[69], «Satisfaction by Category», содержит результаты опросов пользователей относительно использования в бизнесе, простоты установки, использования и администрирования, а также качество поддержки разных IDE. В разных российских источниках, озвучивались, суммируя, следующие критерии[70] [71]:

  • доступность и простота установки[72]
  • возможность реализовать поставленные задачи
  • отказоустойчивость и критерии времени отклика
  • требования к ОС и переносимости
  • контроль версий
  • удобство использования (наличие справки и поддержки, изменение кода, понятность и расширяемость)
  • системные требования

Выбор же самого языка программирования – задача также сложная. Наиболее часто встречающиеся критерии[73] [74]:

  • Стоимость написания программы и её поддержки. Сюда включаются также затраты на обучение, затраты на исполнение программы, затраты на IDE, память вычислительных устройств. Поэтому, для рассмотрения ЯП, предлагается использовать стоимость трансляции программы, выполнения и сопровождения. Эти критерии тождественны качеству оптимизации кода при трансляции, нагромождению семантики (например, при сборке мусора или проверках типов), степени сложности прочтения исходного текста.
  • Системные требования к программе, её портабельность, возможность развёртывания на разных системах.
  • Гибкость и универсальность языка, возможность применения его для широкого круга задач без подключения сторонних технологий.
  • Концептуальная целостность языка. Обоснованность ограничений[75], единый подход ко всем конструкциям языка. Несколько менее важной частью этой характеристики является скромность синтаксиса.
  • Естественность языка. Значение этого параметра субъективно: оно меняется в зависимости от того, насколько ЯП подходит для реализации того или иного прикладного алгоритма.
  • Читабельность и надёжность. Надёжность зависит от наличия обработки некритических ошибок (исключений), системы типов, и степени читабельности языка. Читабельность – от спецификации данных (что опять связано с типизацией), и от степени абстракции (модульности, понятных человеку алгоритмов). Эти характеристики могут быть особо важны в проектах, с большим количеством разработчиков. Из-за их взаимной зависимости они объединены.

Выбор средств создания ПО происходит в ходе решения многокритериальной задачи. В рамках данной работы будет рассмотрено, в частности, решение методом последовательных уступок. Он позволяет ранжировать критерии согласно их значимости в какой-либо конкретной сфере приложения и рассмотреть их все поэтапно, с возможностью предварительной инверсии (изменения знака) показателей[76] [77]. На сегодняшний день существует несколько популярных отраслей программной инженерии, требующих различных характеристик от среды или языка программирования.

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

В отличие от прочих областей «научного» профиля, при рарзарботке искусственного интеллекта требуются символьные, а не числовые, данные, а также возможность совершенствования кода непосредственно во время работы программы. Для разработки ИИ считаются приоритетными технологии функционального и декларативного программирования[79] [80], интерпретации и JIT-компиляции, самоидентификации кода во время исполнения.

От системного программирования, ещё одной предметной области, зависит программирование вообще: именно системные программисты создают средства для работы других программистов, виртуальные машины, компиляторы и интерпретаторы, операционные системы, программы для взаимодействия с аппаратным обеспечением[81]. Также, системное программирование тесно связано с управлением каким-либо оборудованием. Особое внимание здесь уделяется полному доступу к программному и аппаратному обеспечению компьютера, с которым ведётся работа; язык системного программирования должен предоставлять такой доступ.

Веб-программирование актуально с тех пор, как от специалистов потребовалось снизить нагрузку на серверы, создав адекватное информационное сообщение с клиентами и переложив обработку части информации на клиентов. Языки для веб-программирования, в результате, разделились на клиентские и серверные. Клиентские языки используются для запуска сценариев на стороне клиента. Они должны быть очень гибкими и унифицированными, чтобы допускать запуск на любой машине, в любой ОС, посредством любого интернет-браузера. Серверные же языки работают на стороне сервера. Они должны быть способны обрабатывать много данных[82]. В данной предметной области очень важны технологии передачи по сети и запуска программ на любой машине, а также надёжность и безопасность языка программирования[83].

Есть и ещё одна, сугубо прикладная, область применения программирования. Она тесно связана с бизнесом и обработкой деловых данных. В данной отрасли требуется анализ рисков, планирование, построение сложных иерархий и структур, точные описания данных. Языки для работы с деловой информацией должны легко работать с базами данных и графическими интерфейсами. Более того, существует тенденция нацеленности таких языков на результат вычислений, а не на их процесс. В наше время, помимо обработки деловых данных посредством ЯП, возможно и упрощение этого процесса с помощью электронных таблиц[84].

Выводы к Главе 1

Самыми применимыми подходами к программированию оказались 4 основные парадигмы. При этом 3 из них пытаются абстрагировать решение задачи от подробностей работы с машиной. Кроме обычной компиляции, необходимой для создания очень производительных приложений, существуют и другие способы запуска программы: интерпретация и JIT-компиляция на стороне пользователя.

Языки ассемблерного типа облегчают подробную работу с процессором. Для решения же задач, не связанных с аппаратным обеспечением, были созданы более абстрактные ЯП. Языки с абстракцией назвали высокоуровневыми; в противовес им, ассемблеры и машинный код можно выделить в единую низкоуровневую группу. Более того, об уровне языка можно косвенно судить по степени автоматизации работы с памятью и наличию API для высокоуровневых операций в системе. Эти 2 пункта влияют на сам процесс программирования и должны быть рассмотрены более подробно.

Существует много классификаций IDE и языков программирования. Разграничение сред – непростое занятие, но оно обязательно включает в себя анализ интерфейса, производительности, плагинов и инструментов. Языки же следует оценивать с оглядкой на сферу приложения, либо строить способы анализа частичных данных. Многие критерии могут не иметь объективно лучшего или худшего результата, т.к. завязаны на множестве полезных для программиста факторов. Вероятно, для объективной их оценки, их придётся инвертировать при анализе.

2. Некоторые современные языки программирования и их сравнение

2.1. Язык программирования C

Язык программирования C (далее по тексту – Си) был создан для нужд ядра UNIX-подобных операционных систем. Создателями этого ЯП являются Д. Ритчи и К. Томпсон[85]. Несмотря на изначальную ориентацию на системное и прикладное ПО для UNIX, Си - очень гибкий язык: он рассчитан на применение практически в любой области. Известны случаи системного программирования на Си, создания крайне высокопроизводительных и кроссплатформенных программ [7, с. 11]. Си – многократный «язык года» по версии TIOBE, и на момент 2017-2018 гг. является, судя по рейтингам IEEE Spectrum и TIOBE, одним из самых востребованных ЯП [37, 48].

Программы на Си легко портируются, и это считается очень сильной его стороной. Если чётко следовать особым стандартам написания кода, можно добиться даже полной переносимости [7, с. 11]. По критерию зависимости от аппаратного обеспечения данный ЯП является высокоуровневым. Однако стоит сделать ремарку: в нём достаточно много низкоуровневой семантики, чтобы даже сравнивать его с языками ассемблерного типа и использовать в схожих целях. В частности, об этом говорил Б. Страуструп[86]. В конце концов, этот ЯП может оперировать битами, регистрами процессора, оперативной памятью, в нём отсутствуют операции над сложными объектами, в пользу чисел и указателей (см. приложение 6), он оперирует небезопасными и непроверяемыми преобразованиями типов[87], а одной из целей его создания было системное программирование в UNIX (он даже в определённом смысле интегрирован с ней)[88].

Си является процедурным (императивным): в нём можно явно наблюдать и задавать, что именно будет делать компьютер, и как он будет выполнять ту или иную задачу. Это, вкупе с низкоуровневой семантикой, позволяет писать максимально экономичные программы, рационально расходующие системные ресурсы. В Си нет ни поддержки параллелизма, ни сложных составных объектов данных (хотя присутствуют примитивные структуры и контейнеры [7, с. 141 – 147]). Из управляющих конструкций, он предоставляет циклы, условия, группирование и подпрограммы, условный и безусловный переход [7]. Последний может сильно усложнить программу.

В Си присутствуют и функции, способные возвращать значение. Переменные, находящиеся в теле и среди аргументов функций, называются локальными. Обычно они являются т.н. автоматическими: они создаются заново при каждом новом обращении к функции [7, с. 44]. Возвращение значения происходит с помощью оператора return, после которого указывается возвращаемая переменная, константа, или выражение над ними. Можно создать и классическую процедуру (ничего не возвращающую), просто не указывая ничего после return, либо вообще опустив этот оператор. Язык позволяет и рекурсивный вызов функций [7, с. 81 – 84].

Основу синтаксиса данного ЯП составляют операторы присваивания, выхода из цикла или функции, побитового сдвига, равенства и т.д. Операторы могут использоваться блоками, что делает код более лаконичным [7, с. 69 – 80]. Программы на Си отражают возможности современных компьютеров. Так, присутствует возможность использовать регистровую память процессора для некоторых переменных [7, с. 97]. Количество регистров ограничено, но иногда это полезно для повышения производительности.

Си – чистокровный компилируемый язык, поэтому одну программу на нём нельзя написать для огромного количества устройств одновременно[89]; с другой стороны, программы на C элементарно могут быть скомпилированы в нескольких экземплярах из одного и того же исходника для любой программной и аппаратной платформы. Для обеспечения раздельной компиляции из разных исходных файлов, используются специальные заголовочные файлы [7, с. 95 – 96]. Там содержатся описания структур, функций, констант, используемых каждым файлом исходника и т.д. В Си есть препроцессор, обрабатывающий специальные директивы. Каждая директива должна занимать одну строку исходного текста и начинаться с символа #.Препроцессор имеет весьма опосредованное отношение к самому языку[90].

Создатели Си не ставили себе задачи реализовать одну из безопасных моделей менеджмента памяти. Вместо этого, они реализовали произвольный низкоуровневый доступ к ней. Память может быть выделена специальными функциями, как правило, с названием alloc. Для оперирования памятью используются низкоуровневые указатели. После того, как выделенный буфер памяти перестал быть нужным, он может быть освобождён с помощью процедуры, как правило, именуемой словом free. Обращения к free должны производиться в обратном вызовам alloc порядке[91].

Изначально в Си была предусмотрена библиотека ввода-вывода, отвечающая за взаимодействия с файловой системой, такие как файловый ввод и вывод, обработка ошибок, и т.д. У современных версий языка Си имеется более обширная библиотека классов. Внутри неё, помимо вышеописанных функций, находятся функции размещения объектов в памяти, средства для работы со строками, примитивные средства обработки ошибок и так далее [7, с. 260 – 280]. Библиотечные функции подключаются с помощью заголовочных файлов[92].

В целом (см. таблицу 2), Си представляет собой язык с простыми, но тесно связанными с системным программированием, синтаксическими конструкциями. Программы на Си легко портируются после перекомпиляции. Он небезопасен. Стоимость трансляции, выполнения и сопровождения низкая.

2.2. Язык программирования C++

На сегодняшний день, культура написания кода на языке C++ и его хорошее понимание очень высоко ценится программистами-практиками[93]. Он был разработан в 70-х Б. Страуструпом, с целью реализовать некоторые возможности объектно-ориентированного языка Simula на языке с синтаксисом C. В Simula создателя привлекала программная сама организация программы. Изначально рабочим названием было «C с классами». Из изначальных особенностей можно выделить классы и возможность создания их иерархии, контроль доступа с помощью ключевых слов private и public, конструкторы и деструкторы, дружественные классы.

Окончательную форму и название язык приобрёл к 1983 году[94]. В существенно доработанной версии ЯП, которая и получила название C++, также присутствовали глобальный[95] и ad-hoc полиморфизм, реализованный за счёт виртуальных методов, перегрузки методов и операторов, возможность создать ссылку на объект, улучшенная по сравнению с классическим Си концепция неизменяемых данных[96].

По критерию исполнения программы, C++ является компилируемым. Компилятор этого языка имеет очень мощную систему связывания файлов исходного текста перед компиляцией. Она позволяет, в частности, компилировать программу одновременно из нескольких исходников, не только на C++, но и на Си, Фортране или Ассемблере[97]. Чтобы незначительно влиять на этап компиляции из исходного текста, существуют (как и в классическом Си) директивы препроцессора. Каждая директива описывается в файлах исходных кодов и начинается со знака #. Препроцессор обрабатывает каждую строку, начинающуюся с этого символа, перед компиляцией[98].

Язык C++, в отличие от C, является уже полностью высокоуровневым. Реализация языка не зависит от платформы напрямую, а также допускает высокие уровни абстракции. Программист может работать с осмысленными и читабельными данными, не относящимися к работе компьютера. Даже работа с памятью может быть реализована на высоком уровне, с помощью потокового ввода-вывода[99]. К тому же, одна программа на C++ легко может быть скомпилирована в нескольких вариантах для разных платформ [21]. Однако в C++ сохранены и многие низкоуровневые возможности. В частности, можно ограниченно применять регистровую память, также можно использовать и низкоуровневую работу с оперативной памятью компьютера. Непосредственная работа с ОЗУ осуществляется с помощью низкоуровневых указателей[100].

Этот ЯП позволяет программисту писать код так, как ему удобней. В частности, для высокоуровневого программирования поддерживаются классы (при этом, современный C++ является одним из ООП-языков, поддерживающих множественное наследование[101]), а для низкоуровневого – возможность писать императивный код в стиле классического Си, поддерживая большинство приёмов программирования на нём[102]. Б. Страуструп отмечал, что намеренно не стал принуждать использовать исключительно одну парадигму, а дал возможность программировать так, как потенциальный программист посчитает нужным[103]. Таким образом, C++ можно назвать универсальным, мультипарадигмальным языком. Обратной стороной столь широких возможностей является постоянно усложняющийся синтаксис с огромным количеством лексем[104], затрудняющий обучение языку, и возможность испортить код неосторожными низкоуровневыми действиями.

Применение объектно-ориентированной модели на C++ гарантирует инкапсуляцию некоторой информации. В частности, данные каждого класса делятся на спецификаторы доступа public, protected и private. Данные, отмеченные как private и public, недоступны извне класса (но последнее доступно при наследовании). Таким образом, можно контролировать уровни доступа к членам класса и обезопасить код. Есть и довольно необычный способ обеспечить доступ к члену класса: это пометить функцию или класс как дружественный для другого класса (см. приложение 3). Это разрешает избирательный доступ к отмеченной информации дружественным типам[105]. Какой-либо объект данных можно объявить и вне контекста класса. Тогда он станет виден в пределах всей программы.

Полиморфизм методов реализован за счёт их переопределения. Метод, доступный для переопределения, называется виртуальным (virtual). В современных версиях C++ виртуальные функции могут и вовсе не иметь своего тела (см. приложение 3). Классы с такими методами, лишь представляют некий интерфейс для реализации потомками, и называются абстрактными[106].

Создатель языка C++ решил не делать реализации схемы со сборкой мусора. Эта идея обсуждалась, но так и не нашла реализации. Вместо неё было решено оставить классическую схему из Си, с явным выделением и освобождением памяти. В C++ пытались реализовать сборку мусора, но в основном эти идеи не увенчались успехом; хотя и существуют версии C++ со сборщиком мусора, он опционален [23].

Проблема инициализации и освобождения ресурсов была решена ещё в самом начале разработки языка, посредством системы с конструктором и деструктором. Конструктор в C++ представляет собой специальную функцию, присваивающую изначальные значения каждому члену экземпляра класса[107]. Деструктор же наоборот, освобождает ресурсы класса, когда он больше не нужен (см. приложение 3). По сути своей, это аналоги alloc и free из Си[108], но в рамках объектно-ориентированного программирования они более очевидны и лаконичны.

Основная библиотека с готовыми модулями на данном языке включает в себя (на примере Visual C++) обработчики ошибок, итераторы, средства ввода-вывода, средства управления памятью, зачаточные средства функционального программирования, средства синхронизации, высокоуровневую работу со строками[109]. Помимо этого, существует т.н. Стандартная Библиотека Шаблонов (STL). Её первоначальный вариант был разработан А. Степановым[110]. Она включает в себя достаточно много контейнеров данных и операции над ними. Это позволило реализовать на C++ некоторые возможности функционального программирования[111].

Суммируя (см. таблицу 2), универсальность C++ выше чем у Си. Надёжность кода незначительно повышается средствами обработки исключений и самим фактом наличия высокоуровневого программирования. Синтаксически переусложнён, поэтому целостность низкая. Стоимость трансляции и сопровождения высокая, выполнения – низкая.

2.3. Язык программирования Java

Этот язык был разработан инженерами компании Sun Microsystems (позднее – Oracle) в середине 1990-х годов. Задача, которую он решает, весьма сложна: необходимо было разработать ЯП, программы на котором можно бы было распространять по Интернету (в том числе в составе веб-страниц), запускать их на любом аппаратном обеспечении. Используемый в то время C++ не позволял решать такие вопросы безопасно[112]. В результате родилась концепция виртуальной машины Java (JVM), а также были разработаны и внедрены промышленные методы JIT-компиляции, и новый высокоуровневый язык. Создал концепцию этого ЯП Д. Гослинг. Java, согласно его работам [18], задумывался как простой и понятный язык, на котором можно быстро писать код без изнурительной подготовки. В числе потенциальных целей для языка значились клиент-серверные приложения, парадигмы передачи сообщений, многопоточные приложения с интерактивной графикой. ЯП был сделан понятным для программистов на таких языках как C++, Objective C, Eiffel и Ada [18, с. 19].

Как и Си, Java дважды становился языком года по версии TIOBE, и занимает стабильно высокие позиции в рейтингах ЯП [37, 48]. Это даёт повод считать, что влияние технологии JVM на IT-индустрию огромно.

Этот язык создавался изначально под нужды промышленного объектно-ориентированного программирования [18]. Присутствуют классы, из которых можно выстраивать иерархии. В классах наличествуют типизированные данные – поля, и типизированные функции – методы. Всё вышеперечисленное может быть инкапсулировано внутри класса (ключевым словом private), а может быть оставлено для публичного доступа (public). Существует и модель доступа только для потомков класса (protected). В каждом классе есть методы-конструкторы, инициализирующие его. Любая иерархия начинается от корневого класса Object[113]. Даже примитивные типы данных - символы и строки, массивы, числа и булевые значения, наследуют от него.

Присутствуют и абстрактные типы данных. Они делятся на 2 подвида. Первый подвид - абстрактные классы, отличающиеся от обычных только тем, что могут иметь методы без реализации и могут использоваться только для инициализации потомков. Второй абстрактный тип данных называется интерфейсом и целиком состоит из констант и сигнатур методов. Интерфейсы не наследуются классами, а реализуются (наследовать они могут только друг от друга), причём реализуются в обязательном порядке все методы, объявленные в интерфейсе. Можно реализовать или унаследовать сразу несколько интерфейсов (см. приложение 1). Никаких других реализаций множественного наследования в Java нет[114].

Полиморфизм реализован как переопределение методов. Методы абстрактных классов без реализации и интерфейсов тоже должны быть переопределены. Также возможна их перегрузка (см. приложение 1).

Java изначально проектировался специалистами Sun Microsystems как чистый объектно-ориентированный язык, и не планировалось какой-либо мультипарадигмальности. Однако, начиная с восьмой версии языка, реализованы некоторые средства функционального программирования. В частности, можно создавать функциональные интерфейсы. Такой интерфейс состоит из всего одной функции. Можно наследовать, реализовывать и использовать его, как любой интерфейс. Отличие от обычного интерфейса заключается в возможности инициализировать его метод по ходу выполнения программы ссылкой на метод или анонимную функцию, таким образом, реализовав интерфейс (см. приложение 1)[115].

Программы, написанные на Java, используют JIT-компиляцию либо классическую интерпретацию. На стороне программиста код преобразуется в промежуточную форму. Файлы с промежуточным кодом имеют расширение class и обычно собираются в распознаваемые JVM архивы с расширением .jar[116]. Промежуточный язык JVM может содержит 226 типов команд[117].

В изначальном описании 1995 года [18, с. 52 – 55], Java описывается как интерпретируемый язык. При классической интерпретации, JVM на стороне конечного пользователя преобразует байт-код в машинный код по мере выполнения. Этот способ довольно медленный, поэтому для него есть альтернатива: технология HotSpot. Компилятор HotSpot транслирует программу кусками и сохраняет в памяти. Иногда две технологии применяются совместно в целях оптимизации[118].

Большинство программных интерпретаторов виртуальной машины Java написаны на Си, что гарантирует им высокую портируемость на самые разные платформы. Существуют и аппаратные реализации JVM. Так, в частности, для аппаратной интерпретации байт-кода Java, существуют специальные микросхемы для его исполнения[119], или, например, технология Jazelle процессоров ARM [32]. Данный ЯП очень популярен в плане своей портируемости: на нём можно и писать приложения для браузеров, и создавать мобильные приложения, и писать прикладное ПО для ПК [37]. При этом программа на Java гарантирует свою работу везде, где есть JVM, без перекомпиляции. Платой за все эти плюсы стала низкая производительность программ, написанных на Java и невозможность низкоуровневого программирования. Первое связано со спецификой JIT-компиляции, а также частично вытекает из второго: синтаксис и семантика Java не предполагают работы ни с регистрами, ни с адресами в оперативной памяти, что вынуждает программиста отказаться от быстрых, но небезопасных, решений[120].

Для того чтобы не нагромождать программиста ненужной в практической деятельности работой, а также обеспечить стабильную работу JVM, процесс освобождения ресурсов в Java автоматизирован. За это отвечает сборщик мусора среды исполнения Java. Его работа невидима для программиста. Управление памятью Java базируется на подсчёте ссылок. Если ссылки на какой-либо объект программы есть, значит, он активен. Если же ссылки на объект в памяти отсутствуют, то рано или поздно он будет автоматически освобождён [18, с. 24 – 25]. Если надо подготовить объект к удалению, существуют методы-финализаторы. Их содержание может быть явно задано программистом. Финализаторы вызываются автоматически, перед освобождением неиспользуемого объекта во время процедуры сборки мусора. При отсутствии финализатора, сборщик мусора просто удаляет ненужный объект[121].

Библиотеки языка Java очень богаты на самые разнообразные классы. В частности, они обеспечивают примитивы синхронизации. Все модули библиотеки Java являются т.н. потокобезопасными: их одновременное использование из нескольких потоков не способно нарушить логику программы или вызвать неконтролируемое поведение. Также, библиотеки Java используются как API на Android. Вот только малая часть функционала (в список вошли только корневые, и не связанные со сторонними технологиями, библиотеки)[122] [123]:

  • java.lang, отвечающая за основные типы, поддерживаемые языком.
  • java.io обеспечивает высокоуровневый потоковый ввод и вывод различных данных.
  • java.net для работы в сети; она содержит сокеты, средства для работы со ссылками и telnet.
  • java.util, библиотека с контейнерами и коллекциями данных: в частности, там находятся реализации хэш-таблиц и стека, а также классы Date (дата) и Time (время) [18, с. 16].
  • java.awt – Abstract Windowing Toolkit, библиотека с инструментарием для создания графического пользовательского интерфейса.
  • java.text – представляет форматы чисел, дат, и прочих данных.
  • java.math – поддерживает математические операции с целыми числами или десятичными дробями.
  • java.applet, библиотека классов для создания легковесных веб-приложений[124].
  • java.security, инструменты для шифрования и безопасности.

Суммируя (см. таблицу 2), можно прийти к выводу, что Java – очень безопасный язык. Java легко портируется. Синтаксис усложнён запретами. Технологии Java нельзя применить в некоторых областях, требующих высокой производительности и универсальности. Стоимость трансляции, выполнения, и поддержки высокая.

2.4. Язык программирования Python

Python – это лёгкий в изучении ЯП, популярность и полезность которого в современном мире растёт. В частности, Python был удостоен первого места в The 2017 Top Programming Languages[125]. Индекс TIOBE этого ЯП тоже стабильно держится на относительно высоких позициях (см. таблицу 1).

Python применяется в основном для веб-приложений и серверного ПО[126]. Он позволяет строить наращиваемые и модульные программы. Кроме этого, по информации официального сайта, Python используется в ПО для инженерного анализа и компьютерной анимации[127]. Несмотря на простоту в изучении и работе, на нём можно писать самые разные по масштабу приложения. Крупные программы на этом языке поставляются в модульном виде [4, с. 46 – 47].

Данный язык является высокоуровневым. ПО на нём может быть исполнено множеством систем, а синтаксис позволяет оперировать очень абстрактными данными. Исходный код на Python обычно вообще никак не связан с ОС или аппаратным обеспечением, применяясь лишь в прикладных целях. Одной из целей создателей было сделать ЯП, программирование на котором проще чем на C, C++ или даже Java, и отнимает меньше времени. Также, упор сделан на более высокоуровневые типы данных, которые обеспечивали бы программисту возможность совершать много типовых операций единичными выражениями[128]. Этот ЯП, несмотря на его простоту освоения, может успешно применяться для сложных математических вычислений[129].

Данный язык поддерживает несколько парадигм программирования. В основном это ООП. Python позволяет создавать иерархии классов. Классы создаются по ходу исполнения программы. Внутри каждого класса могут быть объявлены именованные функции или переменные. Чтобы унаследовать один класс от другого, надо при описании наследника указать после его сигнатуры название прародителя в скобках. Прародителей может быть и несколько. В этом случае, наследование описанных в скобках классов происходит, как правило, слева-направо, методом поиска в глубину (от наследников к прародителям) [4, с. 160 – 163]. Это важно учитывать при построении сложных иерархий, когда у прародителей могут быть разные данные с одинаковой сигнатурой: наследуется самая первая, найденная в иерархии реализация (см. приложение 2). Однако, точный алгоритм построения иерархий сложнее. В некоторых редких случаях, реализация множественного наследования ведёт к ошибкам и не рекомендуется [4, с. 164]. С другой стороны, оно позволяет создавать в Python т.н. классы-примеси. Это наборы методов и данных, которые могут быть унаследованы другим классом. Все классы неявно наследуют от класса object [4, с. 75].

Любая именованная информация класса может быть инкапсулирована. За эту операцию отвечает добавление символов нижнего подчёркивания перед сигнатурой инкапсулируемого члена (см. приложение 2).

Методы в Python могут быть переопределены. Для этого достаточно, просто написать метод с такой же сигнатурой в классе-наследнике. Полиморфизм Python завязан не на принципы ООП, а на интерпретируемую структуру языка[130]. Обратной стороной этого является техническая возможность переопределить метод одноимённой переменной [4]. Поэтому с особой серьёзностью используются соглашения о наименовании тех или иных членов класса[131]; в частности, методы принято именовать глаголами, а данные – существительными, или, как вариант – писать названия методов заглавными, а данных – строчными буквами. В классе, отмеченном как абстрактный, можно создавать абстрактные методы. Экземпляры такого класса нельзя создавать [4, с. 182 – 188].

Кроме ООП, на Python возможно функциональное программирование. Наиболее часто ФП на этом языке употребляется для многозадачных приложений. Функциональная парадигма на Python поддерживается благодаря тому, что любую функцию можно применить в качестве аргумента или результата выражения. Также присутствуют специальные функции – генераторы, которые могут применяться для обработки контейнеров данных, использоваться как итераторы, и т.д. Генераторы также способствуют декларативному программированию на Python. Декларативный стиль часто применяется на этом языке для упрощения работы с большим количеством операций и/или данных [4, с. 130 – 155].

Python – интерпретируемый сценарный язык. Исходный текст на нём является по сути своей законченным скриптом, а файлы с этими скриптами обычно имеют расширение .py или .pyw[132]. Стандартная реализация интерпретатора может компилировать встроенные модули с кодом на Си, в целях оптимизации. Более того, существует интерактивный режим интерпретатора, в котором можно исполнять скрипты мгновенно, во время их написания. У языка есть множество реализаций [4, с. 23 – 25][133]:

  • CPython, обычная реализация. Написана на Си.
  • Jython, реализация Python с использованием JVM. Написана Джимом Хаганином на Java[134].
  • Реализации Python на технологиях .NET Framework. Одна из них, созданная Брайаном Ллойдом, использует технологии классического CPython, может взаимодействовать при этом с компонентами .NET Framework. Также существует и более самобытная реализация Python, генерирующая промежуточный код IL, написанная создателем Jython.
  • PyPy, экспериментальная попытка создать JIT-компилятор для Python. Поддерживает некоторые нововведения, не свойственные остальным реализациям.

В Python реализована сборка мусора. Для всех объектов в программе ведётся учёт. Как только на объект появляется новая ссылка – счётчик ссылок увеличивается, и наоборот [4, с. 59 – 60]. Сбор мусора срабатывает в зависимости от того, сколько объектов было создано и сколько объектов без ссылок засоряют память. Ненужный объект может быть и не удалён во время этой процедуры, а лишь перемещён в следующее поколение. Всего поколений три: от нулевого до второго. По умолчанию, в нулевом поколении может находиться 700 объектов, а в 1-м и 2-м до десяти. Пороговые значения можно произвольно изменить, либо вообще отключить сборщик мусора [4, с. 280 – 383].

Python может использовать самые разные API и библиотеки, в зависимости от интерпретатора. Так или иначе, стандартная библиотека Python, предоставляет следующие элементы[135] [136]:

  • Поддержку встроенных типов и выражений, работу со строками. Также, поддержку встроенных коллекций данных и исключений.
  • Модули для математических операций. В частности, базовые классы для чисел, функций, генератор случайных чисел.
  • Потоковый ввод и вывод, поддержку работы с файловой системой. Сюда входят модули для представления файлов, потоков, директорий.
  • API для работы с базами данных. В частности, DB-API.
  • Шифрование согласно алгоритмам MD5 и SHA1. Также доступен класс-обёртка над сокетами SSL.
  • Модули межпроцессной коммуникации. Модули mutex и signal.
  • Работу с Интернет-сервисами. Модули для клиент-серверной коммуникации с использованием HTTP, POP3, SMTP, telnet.
  • Работу с архивами, документами и другими мультимедиа. Сюда относятся модули для работы с форматами wav, zip, текстом и гипертекстом.
  • Некоторые специфические модули для работы в определённой ОС или на определённой машине. В частности, существуют специфические модули для Windows, OS X, Mac OS, UNIX.
  • Некоторые специфические модули, необходимые для внутренней работы языка, его интерпретатора и окружения. К примеру, средства интерпретации, анализа кода и обратной инженерии, собственная внутренняя IDE[137].

Версии Python для JVM и .NET Framework могут использовать, помимо стандартной библиотеки Python, библиотеки Java[138] [139] и .NET соответственно.

Суммируя (см. таблицу 2), Python очень портабельный, но не очень надёжный из-за особенностей множественного наследования и типизации. Библиотека позволяет применять его в различных областях. Язык очень лёгок, программы на нём легко читать и писать. Стоимость из-за механизма сборки мусора средняя.

2.5. Язык программирования C#

Язык C# был создан группой специалистов из Microsoft под руководством А. Хейлсберга. Microsoft требовался универсальный язык для их глобального проекта в области прикладной программной инженерии на ОС Windows, .NET Framework[140]. C# был спроектирован с этой целью. Впоследствии, появились свободные реализации .NET и для других платформ[141], а C# стал широко известен за пределами Windows-сообщества, на момент 2017 года занимая высокие позиции в рейтингах TIOBE и IEEE Spectrum [37] (см. таблицу 1).

.NET Framework состоит из нескольких компонентов, самыми значимыми из которых являются общеязыковая среда исполнения CLR, играющая роль, близкую к виртуальным машинам, и библиотека классов .NET, выполняющая функции API. С этими двумя компонентами могут работать самые разные языки программирования[142].

Данный язык является высокоуровневым. Он разрабатывался с учётом наработок Java и C++. Исполнение кода на C# зависит только от наличия .NET Framework на машине конечного пользователя. С точки зрения портируемости, важно отметить, что .NET Framework слишком тесно связан с Windows, некоторые версии этой ОС даже поставляются в комплекте с ним[143]. Однако энтузиастами были разработаны и кроссплатформенные варианты: в частности, технология Mono. На данный момент времени мало что мешает использовать приложения C# на Linux, Mac OS X, и на мобильных платформах. Создатели C# не стали идти по пути Java, и оставили некоторые возможности для низкоуровневого программирования. В частности, в этом языке можно использовать низкоуровневые указатели в стиле Си. Однако чтобы разрешить сборку такого кода, нужно установить параметр компиляции /unsafe[144]. В целом, C# можно назвать более простым и безопасным, чем C++, но обладающим схожим функционалом.

Основная концепция, на которую ориентировались создатели, это промышленное объектно-ориентированное программирование [13]. Язык содержит множество конструкций для ООП. Но не только для него.

Все типы данных в C# делятся на ссылочные типы (классы) и типы значений (структуры) [3, с. 59 – 67]. Первые и вторые могут включать в себя методы, поля и конструкторы. Методы и поля строго типизированы. Конструкторы представляют собой первые методы, выполняющиеся при инициализации объекта или типа (целиком). Конструкторы экземпляров структур имеют ограничения: они не могут создаваться без аргументов, и обязаны инициализировать содержимое структуры[145].

Ссылочные типы позволяют создавать иерархии классов. Все они неявно наследуют от корневого класса Object[146]. C# не поддерживает множественное наследование, вместо него реализована схема с интерфейсами. Интерфейсы, как и в Java, могут наследовать друг от друга и реализовываться в классах и структурах. Можно реализовать или унаследовать сразу несколько интерфейсов. Реализация интерфейсов и наследование в C# синтаксически выглядят одинаково (см. приложение 5)[147].

Существуют модификаторы доступа, которые можно задать каждому члену класса или структуры. Модификатор public делает информацию видимой для всех, private скрывает её, делая доступной только изнутри класса, protected – тоже скрывает, но оставляет доступ для наследников класса[148].

Полиморфизм присутствует в нескольких ипостасях: в частности, можно пометить метод как virtual, и переопределить его в классе-наследнике. Также можно перегружать операторы, или создавать методы с одинаковой сигнатурой, но различными аргументами. Есть и виртуальные методы без тела. Они входят в состав абстрактных классов. Как и в Java, такие классы предоставляют свои данные только при инициализации потомков, а абстрактные методы должны быть переопределены[149] [150].

ООП является основной парадигмой программирования на C#. Однако, этот ЯП не заставляет программировать в объектно-ориентированном стиле, реализуя, пусть и гораздо менее показательно, вообще все перечисленные в работе парадигмы программирования. Так, например, для императивного программирования, языку в наследство от C++ достались указатели и оператор безусловного перехода [3].

На C# возможно и функциональное программирование. Это обеспечивается синтаксисом[151], а также специальными классами – делегатами. Все эти классы отличаются тем, что представляют собой фактически ссылку на метод, с возможностью его отложенного вызова. Делегат может содержать в себе и несколько методов, или ссылку на несколько делегатов (каждый из которых может также ссылаться на несколько методов или делегатов). В этом случае, при его вызове, методы вызываются все и по порядку. Также, делегат можно инициализировать анонимным методом (см. приложение 4). Делегат, как и экземпляр любого класса, может быть создан, инициализирован и использован внутри другой функции[152] [153].

Декларативная парадигма программирования на C# используется для простого управления большими контейнерами и коллекциями классифицируемых данных (см. приложение 4). В частности, в .NET Framework есть специальный внутренний декларативный язык запросов, LINQ. Он используется для обработки данных[154]. LINQ-запросы легко интегрируются в код на C#, как библиотечные функции или даже как часть синтаксиса (см. приложение 4)[155].

Данный язык является JIT-компилируемым. На стороне программиста происходит трансляция кода на C# в промежуточную форму, называемую кодом IL. Этот код, при запуске на компьютере конечного пользователя, компилируется в машинный по мере выполнения программы. В частности, компилируется каждый новый метод перед исполнением. После компиляции, метод запускается, а его машинный код остаётся в динамической памяти на случай вторичного использования. Последующие вызовы метода работают только с машинным кодом конечного процессора, что обеспечивает прирост производительности. Также, в процессе компиляции код может быть оптимизирован [13, с. 37 – 41].

Каждая законченная программа для .NET называется сборкой[156]. Сборки могут включать в себя один или несколько управляемых средой CLR модулей и ресурсных файлов. Это позволяет разделить логическую и физическую составляющие программы. Сборки имеют манифест, цифровую подпись, правила безопасности и некоторые другие важные атрибуты, которые могут быть прочитаны средой CLR при запуске приложения [13, с. 58 – 78].

Данный ЯП использует сборку мусора. Объекты ссылочных типов в нём могут иметь финализатор (иногда называемый также деструктором)[157]. Деструктор синтаксически выглядит аналогично таковым в C++ (см. приложение 5), но имеет немного другой смысл своего существования. На финализаторы всех объектов, созданных в ходе выполнения программы, создаётся ссылка в списке финализации, специальной внутренней коллекции данных. Каждый объект имеет набор корней. Корнем называется адрес в памяти, по которому находится ссылка на объект. Как только корней у объекта не остаётся – он становится кандидатом на сбор мусора. Сборщик мусора вызывается, когда среде не хватает памяти для инициализации новых ресурсов, когда накопилось слишком много объектов без корней, при завершении работы приложения и среды, или посредством явного вызова программистом[158]. Сначала он помечает все объекты с корнями, затем – сжимает память кучи, чтобы объекты в ней не фрагментировались, и улучшалась производительность. В случае если на объект есть ссылка в списке финализации, его удаление откладывается, пока его деструктор не будет вызван и не завершит работу. Сборщик мусора выполняется в отдельном потоке, не мешая работе основного приложения. Для удаления объектов с финализатором ему может понадобиться сделать несколько проходов [13].

Роль основного API и рабочего инструмента в .NET играет так называемая стандартная библиотека классов, состоящая из нескольких пространств имён [3, с. 463]. Изначально .NET Framework создавался для операционной системы Windows, следовательно, и его библиотека классов рассчитывалась в основном на использование в данной ОС. Аргументом в пользу этого утверждения являются периодические упоминания Windows в технической документации и названиях пространств имён библиотеки[159]. К примеру, некоторые наследники класса SafeHandle, предназначенные для оперирования критическими и небезопасными ресурсами и их финализации, находятся в пространстве имён с лаконичным названием Microsoft.Win32.SafeHandles[160]. Также, существуют и дополнительные API для определённых ОС и версий платформы. В частности, в Mono существует библиотека Mono Class Library, отвечающая за дополнительный функционал для приложений, ориентированных на ОС Linux[161]. Основным же пространством имён стандартной библиотеки .NET Framework является System. Оно обеспечивает поддержку всех основных типов данных в C#. Рассмотрим некоторые возможности его дочерних пространств имён, описанные на официальном ресурсе компании Microsoft[162]:

  • Управление многопоточными приложениями, синхронизация и её примитивы.
  • Поддержка коллекций и контейнеров данных, транзакций, LINQ и SQL, работа с базами данных (включая параллельную обработку данных)[163].
  • Создание сетей, работа в Интернете. Специальные модули для поддержки ASP.NET, клиент-серверной технологии Microsoft[164].
  • Операции ввода и вывода, работа с файловой системой, идентификация аппаратного обеспечения.
  • Несколько специфических пространств имён для компиляции, поддержки рефлексии кода, генерации кода во время выполнения приложения и пр.
  • Обработка текстовой, звуковой, графической информации. Сюда также относятся такие новшества, как распознавание речи.
  • Специфические пространства имён для идентификаторов и модулей безопасности, шифрования и политики доступа.

Суммируя (см. таблицу 2), C# является не самым портабельным языком. Кроссплатформенные реализации .NET появились совсем недавно. С другой стороны, благодаря библиотеке и поддержке разных парадигм, он гибкий и читабельный. Синтаксис, как и в Java, несколько усложнён запретами. Также язык надёжен, хотя и допускает небезопасный код. Стоимость высокая.

2.6. Сравнительный анализ языков программирования с точки зрения одной из отраслей

По ходу Главы 2, характеристикам языков выставлялись баллы по шкале «Плохо» (0%) – «Средне» (50%) – «Хорошо» (100%). Такая наглядная система оценки языков частично позаимствована из книги Гослинга и МакГилтона [18, с. 69]. Попробуем выработать рекомендации для получившейся таблицы языков (см. таблицу 2).

Пример отрасли: системное программирование. Важнейшим критерием здесь является возможность быстро выполнить произвольный код без ограничений[165]. Уровень, на котором работает системный программист, поделён между ОС и аппаратным обеспечением[166]. ОС может быть устроена компонентно, иметь поддерживать абстрактные типы данных и иметь обширный системный API, аппаратное же обеспечение имеет свои аппаратно-зависимые операции и типы данных[167]. Таким образом, требования целостности языка разнятся: при работе только с операционной системой, типы данных и алгоритмы единообразны, в случае же программирования взаимодействий между системой, различным аппаратным обеспечением и/или прикладным ПО – наоборот.

Путём простого попарного сравнения (альтернативой ему может быть более сложный метод рангов, предлагаемый в частности С. Орловым)[168] [169], можно предположить следующущий порядок значимости: универсальность (максимум), стоимость (минимум), портабельность (максимум), целостность (максимум или минимум), читабельность и надёжность (максимум). Размер уступок – разность (при поиске максимума) или сумма (при поиске минимума) значений 1-го оптимального варианта по текущему критерию и n-го оптимального варианта (где n меньше или равно номеру текущего критерия).

Шаг 1. Универсальность – C++, C# (-25 – C, Java, Python).

Шаг 2. Стоимость – C (+50 – C++).

Шаг 3. Целостность – C++ либо C, в зависимости от сферы приложения.

Шаг 4. Портабельность – Java, Python (-25 – C, C++, C#).

Шаг 5. Читабельность и надёжность – C++ (+16,7 – Java, C#).

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

Результатом данного анализа становится, в зависимости от условия, Си (оптимален для действий внутри операционной системы) или C++ (оптимален для многоуровневых взаимодействий). К сожалению, для аналогичной оценки сред разработки ПО для определённой области, требуется создать ещё одну таблицу, т.к. современные IDE не привязаны к языкам. Однако промежуточный результат выглядит правдоподобно. Язык Си часто относят к языкам системного программирования[170] [171]. C++ также располагает инструментарием для создания системного ПО [172].

Выводы к Главе 2

Из рассмотренных в данной работе языков, большинство (кроме Си) реализуют объектно-ориентированную схему. C++, C# и Python реализуют много парадигм одновременно.

Java и Python обладают лучшей портативностью из рассмотренных языков. Наиболее универсален C++ и C#, безопасностью кода и удобочитаемостью обладают C# и Java. Разработка на Си – наименее затратная.

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

3. Некоторые современные среды разработки и их сравнение

3.1. Среда разработки Microsoft Visual Studio

Microsoft Visual Studio является платной средой разработки, хотя существует и бесплатная версия Community Edition, с некоторыми ограничениями[173]. Обе версии оперируют крупными модулями – решениями и проектами. Всего в линейке продуктов VS можно создавать как минимум 12 основных типов проектов. Проекты Visual Studio (далее VS) могут быть зависимыми или независимыми друг от друга. Именно эта среда более всех остальных ориентирована на работу с Windows и .NET Framework. Поддерживается Visual Basic, C/C++/C#, F#, Python и JavaScript. Она позволяет создавать на разных языках сборки, подписывать их и контролировать их версии[174] [175]. Это очень практично для разработки и развёртывания крупного коммерческого ПО. Существуют и неофициальные дополнения, позволяющие использовать Visual Studio для работы с 32-битной версией Java Development Kit. На момент начала 2018-го года, 64-битные версии Java данным расширением не поддерживаются, а сам проект находится на стадии бета-версии[176].

Основная платформа данной IDE – ОС Windows. Для запуска самой IDE, и создания приложений в ней, требуется значительное количество ресурсов[177]. Основной пласт использования (37%) – промышленная разработка для крупного бизнеса. 30,9% использования среды – малый бизнес, 32,1% - средний рынок [40]. Относительно использования VS студентами, среда считается приемлемой для этих целей, но не самой подходящей и не самой простой[178].

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

Технология IntelliSense облегчает поиск тех или иных модулей в текстовом редакторе, позволяет ссылаться на те или иные данные в исходном тексте значительно быстрее (см. рис. 10). Она умеет анализировать метаданные сборок и визуально отображать их программисту[179].

Технология CodeLens позволяет просматривать некоторые данные о каждом элементе кода в редакторе (например, какие внешние элементы программы ссылаются на этот него, более ранние версии этого фрагмента кода и т.д.). При этом не теряется контекст, в котором работает программист. Также, среда имеет хорошую поддержку регулярных обновлений, и информативную справку (см. рис. 9 – 10).

Панель редактора кода можно оптимизировать под свои нужды (см. рис. 6). Можно также включить управляемую отладку приложений. Технологии Visual Studio облегчают рефакторинг кода (см. рис. 7). Есть и расширения для VS, предоставляющие дополнительные возможности. Однако, при отказе некоторых единичных компонентов, может перестать работать вся IDE[180].

Современные версии VS привязаны к аккаунту пользователя, и их настройки можно легко переносить с одной версии IDE на другую (или, как вариант, с IDE на домашнем компьютере – на рабочий)[181].

3.2. Среда разработки NetBeans

Данная среда разработки была изначально создана для разработки с открытым исходным кодом при помощи Java Development Kit [42, 20]. Технология NetBeans разрасталась, появлялись пакеты с поддержкой других ЯП. На данный момент среда поддерживает чистый Си, C++ и Fortran[182]. С помощью сторонних плагинов можно редактировать и создавать проекты C# и Python (см. рис. 1).

Особенностями данной среды являются её системные требования. В частности, IDE может запускаться на очень многих операционных системах, включая Linux, OS X, Solaris и Windows, и помимо этого может использоваться и для удалённого развёртывания [20].

Основной пласт использования данной среды – свободное ПО и проекты для нужд малого бизнеса. Использование на среднем рынке или в крупных проектах распределено примерно равномерно, составляет 21 – 23%, согласно данным G2 Crowd [40]. Установка NetBeans может проходить довольно тяжело, однако это окупается простотой самой среды. В пользу этого фактора говорит то, что NetBeans использовалась в 2007-м году в Вестминстерском Университете, в крупном исследовании. Это означает возможность использовать её и в образовательных целях.

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

В данной среде есть множество компонентов. Раньше в NetBeans не было средств автокоррекции ошибок [20], однако на данный момент это по большей части исправлено (см. рис. 2). К среде всегда можно подключить плагины и расширения, вплоть до поддержки новых языков программирования[183]. IDE поддерживает некоторые возможности работы с удалёнными серверами, базами данных, и веб-сервисы.

Техническая поддержка и справочная система среды разработки NetBeans заслужила смешанные оценки пользователей [40]; с другой стороны, она как минимум весьма информативна и не запутывает программиста (см. рис. 5) [20].

3.3. Среда разработки Eclipse

Данная среда, как и NetBeans, была создана для бесплатного использования при разработке Java-приложений. Разработала её корпорация IBM, и одной из целей разработки было создание нового стандарта многоязыковых корпоративных IDE. У неё есть поддержка систем контроля версий и многоязыковая поддержка. Считалась сложной для новичков, но в последнее время были предприняты шаги по упрощению среды[184]. На данный момент, по мнению некоторых источников, она удобна для программиста любого уровня умений[185]. Основными языками платформы являются Java, C и C++. Однако, Eclipse нейтральна к любым языкам программирования, и для неё существуют реализации Python, Eiffel, PHP, Ruby, и C#[186].

Eclipse была написана на Java. Это делает её легко переносимой с одной платформы на другую[187]. Приложения в среде также легко развёртываются, в т.ч. в архиве или по сети.

Основной процент использования Eclipse IDE – приложения для крупного бизнеса (39,5%) и среднего рынка (37%) [40]. Оставшиеся 23,5% занимает разработка для малого бизнеса. Большинство респондентов сообщало, что данная IDE пригодна для разработки крупных бизнес-решений.

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

Данная среда разработки имеет очень гибкий и структурированный интерфейс с закладками (см. рис. 13). По исходному тексту можно перемещаться с помощью гипертекстовых ссылок. Рабочая среда Eclipse состоит из окон, которые могут включать в себя несколько страниц, а также нескольких панелей и редакторов. Панели показывают свойства и структуру той информации, с которой работает IDE. Всего в приложении, как правило, может быть только один экземпляр панели одного типа. Редакторов – наоборот, может быть много в программе; более того, возможно наличие в одной программе нескольких экземпляров одного и того же редактора[188].

Eclipse имеет очень хорошие средства работы с редактором кода. Они не только подсвечивают проблемные места и уведомляют о них программиста, но и предлагают решения (см. рис. 11), а также позволяют легко проводить автозамену и рефакторинг (см. рис. 12)[189].

Данная среда может инвариантно настраиваться под нужды пользователя. Она состоит из модулей, объединяемых в подсистемы, в соответствии с их назначением и функциональными возможностями. Модули очень обособлены друг от друга и могут использоваться по-отдельности. Особо крупные подсистемы являются фактически самодостаточными версиями среды. В частности, это Eclipse CDT для разработки на языках C/C++[190], и Eclipse JDT для разработки на языке Java[191]. Такая система с обособленными модулями называется Reach Client Platform[192]. К сожалению, отрицательной стороной такого решения является принудительная установка вручную некоторых важных модулей, доступных для других сред разработки изначально [20].

3.4. Сравнительный анализ сред разработки приложений с точки зрения одной из отраслей

Теперь, разобрав среды разработки, можно приступить к выработке критериев использования IDE в определённой сфере. В качестве отрасли, в продолжение эксперимента из Главы 2, выбрано системное программирование, а в качестве языка – Си.

Тут важно отметить, что перед поиском оптимальной IDE, стоит задуматься о таких базовых вещах, как системные требования и поддерживаемые языки, это сузит круг поиска. К примеру, для программирования на C# в ОС Windows без использования сторонних плагинов лучше всего подойдёт Visual Studio. Для программирования на языке Java предпочтительней Eclipse и NetBeans из-за отсутствия официальной реализации Java в Visual Studio. Если необходимы возможности по переносу среды разработки с одной операционной системы на другую, также предпочтительней использовать кроссплатформенные NetBeans и Eclipse. В данной работе рассмотрено программирование на Си без жёсткого требования к ОС, а значит, все среды, описанные в Главе 3, априори подходят для анализа.

Таблица с критериями (см. таблицу 3) составлена на основе двух таблиц нескольких рассмотренных ранее исследований [26, 40]. Критерии, повторяющиеся в разных источниках, приведены к среднеарифметическим показателям.

Системный программист может работать в неподготовленной для прикладной работы среде для создания ПО «реального времени» или тестировать свою программу при определённых условиях работы аппаратного обеспечения[193]. Важными показателями для него будут являться (по результатам попарного сравнения) доступность IDE, сохранение производительности в любых условиях (эффективность), безотказность, портабельность, техподдержка, администрирование, функциональность, а неважными – удобство использования и удобство создания коммерческого ПО.

Шаг 1. Доступность – Eclipse (-1,5 – NetBeans).

Шаг 2. Производительность – VS (-20 – NetBeans, Eclipse).

Шаг 3. Безотказность – NetBeans (-20 – VS).

Шаг 4. Портабельность – Eclipse (-40 – NetBeans, VS).

Шаг 5. Техподдержка – VS (-2,5 – Eclipse, NetBeans).

Шаг 6. Администрирование – NetBeans (-1 – VS).

Шаг 7. Функциональность – VS (-12,5 – Eclipse).

Необходимо увеличить уступку либо на шаге 1 (что нерационально), либо на шаге 7.

Шаг 8. Удобство использования – NetBeans (-0,5 – VS).

Шаг 9. Удобство коммерческого использования – Eclipse (-5 – VS).

Необходимо увеличить уступку либо на шаге 1 (что опять нерационально), либо на шаге 9.

Таким образом, оптимальные средства (из рассмотренных) для системного программирования найдены: это среда NetBeans и языки C/C++. Несколько менее оптимальной для решения таких задач будет являться Visual Studio. Также, данный анализ может быть легко повторён для других отраслей, либо с более широким спектром IDE и языков программирования. Важно отметить, что его результаты во многом зависят от требований ЛПР в условиях реального проекта. По ходу работы работоспособность метода анализа демонстрировалась на гипотетическом, относительно абстрактном примере.

Выводы к Главе 3

Среда разработки Visual Studio ориентирована на коммерческое применение профессионалами в рамках ОС Windows. Она – единственная из рассмотренных, поддерживает полноценно .NET Framework и C#, и может использоваться для развёртывания Windows-приложений наиболее эффективно, но у неё жесточайшие требования (включая и зависимость от Windows).

Eclipse больше подойдёт опытному программисту, имеющему крупный модульный проект и необходимость постоянно расширять условия разработки. NetBeans лучше всего может использоваться для обучения и разработки «экспромтом», благодаря своей простоте. Все рассмотренные IDE имеют полноценную поддержку плагинов и сетевых сервисов.

Все рассмотренные IDE могут быть проанализированы с точки зрения отраслевого использования, однако перед этим крайне желательно иметь предварительные аналогичные данные о языке программирования. В частности, для использования системными программистами, в ходе такого анализа были найдены среды NetBeans и (отчасти) Visual Studio.

ЗАКЛЮЧЕНИЕ

По результатам работы, было выведено следующее:

  • Самые популярные на сегодняшний день языки программирования поддерживают в обязательном порядке высокоуровневое программирование.
  • Многие современные среды проектирования многоязычны, их уже нельзя рассматривать в связке с одним ЯП.
  • Рассматривать ЯП и среды проектирования предпочтительно с точки зрения сферы их приложения, требования той или иной отрасли. Не существует «серебряной пули», универсально подходящей для решения любой задачи. Так, даже для одной детально разобранной отрасли применения (системное ПО), оптимальный вариант языка или среды изменится при перемене единственного условия.
  • Рассматривать высокоуровневые ЯП необходимо с учётом возможностей не только синтаксиса, но и библиотеки языка. К примеру, язык C++ реализует одну из парадигм проектирования посредством библиотеки STL.

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

Стоит отметить, что данный метод не даёт гарантированный результат, поскольку технологии постоянно развиваются, а требования к ним меняются. Однако, он позволяет оперативно определить технологии разработки ПО перед её непосредственным началом, существенно упрощая принятие решений в выборе таких технологий.

СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

Нормативно-техническая документация

1. ГОСТ 28397-89 (ИСО 2382-15-85). Языки программирования. Термины и определения // Информационная технология. Термины и определения: Сб. – М.: Стандартинформ, 2005. – С. 229 – 236.

2. Единая система программной документации: Сб. – М.: Стандартинформ, 2010. – 170 с.

3. Standard ECMA-334 C# Language Specification. 5th edition. – Geneva: Ecma International, 2017. – 516 p. Режим доступа: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf (дата обращения: 26.01.2018).

Моноиздания

4. Бизли Д. Python. Подробный справочник. – Пер. с англ. – СПб.: Символ-Плюс, 2010. – 864 с., ил. ISBN 978-5-93286-157-8.

5. Буйначев С.К. Основы программирования на языке Python: учебное пособие. / С. К. Буйначев, Н. Ю. Боклаг. – Екатеринбург: Изд-во Урал. Ун-та, 2014. – 91, [1] c. ISBN 978-5-7996-1198-9.

6. Кадырова Г.Р. Основы алгоритмизации и программирования: учебное пособие. – Ульяновск: УлГТУ, 2014. – 95 с.

7. Керниган Б. У., Ритчи Д. М. Язык программирования C, 2-е изд. : Пер. с англ. — М. : Вильямс, 2009. — 304 с.

8. Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. – СПб.: БХВ-Петербург, 2005  - 480 с.

9. Орлов С. Теория и практика языков программирования: Учебник для вузов. 2-е изд. Стандарт 3-го поколения. - СПб.: Питер, 2017. – 688 с.: ил. – (серия «Учебник для вузов»). ISBN 978-5-496-00032-1.

10. Подбельский В. В. Язык C#. Базовый курс: учеб. Пособие. – 2-е изд. перераб. и доп. – М.: Финансы и статистика, 2013. – 408 с.

11. Приходько О. В. Компьютерный практикум: учеб. Пособие для будущих специалистов по управлению персоналом / О. В. Приходько, М. А. Токарева. – Оренбург: ГОУ ОГУ, 2008. – 201 с.

12. Программирование и основы алгоритмизации: Для инженерных специальностей технических университетов и вузов. /А.Г. Аузяк, Ю.А. Богомолов, А.И. Маликов, Б.А. Старостин. Казань: Изд-во Казанского национального исследовательского технического ун-та – КАИ, 2013, 153 с.

13. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. — 4-е изд. — СПб.: Питер, 2013. — 896 с. — ISBN 978-5-496-00433-6.

14. Таненбаум Э. Архитектура компьютера. – 4-е изд. –СПб.: Питер, 2003. – 704 с. ISBN 5-318-00298-6.

15. Шилдт Г. Java. Полное руководство, 8-е изд.: Пер. с англ. — М .: Вильямс, 2012. — 1104 с .: ил. — Парал. тит. англ.

16. Эванс Б, Вербург М. Java. Новое поколение разработки. — СПб.: Питер, 2014. — 560 с.: ил. ISBN 978-5-496-00544-9

17. Blum R. Professional Assembly Language. – Wiley Publishing, Inc., 2005. – 576 p.

18. Gosling J., McGilton H. The Java Language Environment: A White Paper. – Sun Microsystems, October 1995. – 85 p.

Материалы конференций

19. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы // «Новые информационные технологии». Тезисы докладов XVII Международной студенческой конференции-школы-семинара. – М.: МИЭМ, 2009. – С. 60 – 66.

20. Analysis of integrated development environments for J2EE applications. /H. Dagdeviren, R. Juric, O. Ogunleye, I. Tesanovic // Proceedings of the 11th IASTED International Conference on Software Engineering and Applications. – Anaheim, CA: ACTA Press, 2007. – pp. 349–354.

21. Atkinson K., Flatt M., Lindstrom G. ABI Compatibility Through a Customizable Language // Proc. Of the Ninth International Conference on Generative Programming and Component Engineering (GPCE 2010), Eindhoven, The Netherlands, October 2010. – New York, NY: ACM, 2010. – pp. 147–156.

22. Obfuscator-LLVM — Software Protection for the Masses. / P. Junod, J. Rinaldini, J. Wehrli, J. Michielin // Software Protection (SPRO), 2015 IEEE/ACM 1st International Workshop on. – IEEE, 2015. – pp. 3-9.

23. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. ACM HOPL-III, June 2007. – 59 p. Режим доступа: http://www.stroustrup.com/hopl-almost-final.pdf (дата обращения: 26.01.2018).

Статьи в периодических изданиях

24. Вишнеков А.В., Иванова Е.М. Принятие решений при администрировании сложных технических проектов // Системный администратор. 2015.  №7-8 (152-153). URL: http://samag.ru/archive/article/3009 (дата обращения: 26.01.2018).

25. Кизянов А. О., Лучанинов Д. В. Анализ программных средств, реализующих язык программирования Python // Постулат. 2016. №8. URL: http://e-postulat.ru/index.php/Postulat/article/view/177/202 (дата обращения: 26.01. 2018).

26. Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++ // Современные научные исследования и инновации. 2016. № 8. URL: http://web.snauka.ru/issues/2016/08/70888 (дата обращения: 26.01.2018).

27. Любимцев Р.Г. Среда Eclipse для разработки программ на языке Java. / Под науч. рук. к.п.н. И.А. Буяковской // Информационно-коммуникационные технологии в педагогическом образовании. 2014. 02 (30). URL: http://infed.ru/articles/155/ (дата обращения: 26.01.2018).

28. Свердлов С. Арифметика синтаксиса // PC Week/RE. 1998. №42-43. URL: https://www.itweek.ru/themes/detail.php?ID=49177 (дата обращения: 26.01.2018).

29. Barendregt, H. The Impact of the Lambda Calculus in Logic and Computer Science // The Bulletin of Symbolic Logic. 1997. Vol. 3. №.2. – pp. 181–215.

30. Cardelli L., Wegner P. On understanding types, data abstraction, and polymorphism //ACM Computing Surveys (CSUR). 1985. Vol. 17. №. 4. – pp. 471-523.

Интернет-ресурсы

31. Интегрированная среда разработки Visual Studio // Microsoft Developer Network. URL: https://msdn.microsoft.com/library/dn762121 (дата обращения: 26.01.2018).

32. Староверов К.С. Сравнительный анализ микроконтроллеров с ядром ARM // Рынок Микроэлектроники. URL: http://www.gaw.ru/html.cgi/txt/publ/micros/arm.htm (дата обращения: 26.01.2018).

33. .NET Framework Class Library // Microsoft Developer Network. URL: https://msdn.microsoft.com/en-us/library/mt472912.aspx (дата обращения: 26.01.2018).

34. About Mono // Mono Project. URL: http://www.mono-project.com/docs/about-mono/ (дата обращения: 26.01.2018).

35. C++ Standard Library Header Files // Microsoft Developer Network. URL: https://msdn.microsoft.com/en-us/library/a7tkse1h (дата обращения: 26.01.2018).

36. Configuring NetBeans IDE 8.0 for C/C++/Fortran // NetBeans Docs & Support. URL: https://netbeans.org/community/releases/80/cpp-setup-instructions.html (дата обращения: 26.01.2018).

37. Diakopoulos N., Cass S. Interactive: IEEE Spectrum Top 2017 // IEEE Spectrum. URL: https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2017 (дата обращения: 26.01.2018).

38. Functional Programming vs. Imperative Programming (C#) // Microsoft Docs. URL: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/functional-programming-vs-imperative-programming (дата обращения: 26.01.2018).

39. Fundamentals of Garbage Collection // Microsoft Docs. URL: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#the_managed_heap (дата обращения: 26.01.2018).

40. Grid℠ for Integrated Development Environment (IDE) – Winter 2017 // G2 Crowd. – Систем. требования: браузер с поддержкой JS. URL: http://www.g2crowd.com/grid_report/documents/grid-for-integrated-development-environment-ide-winter-2017 (дата обращения: 26.01.2018).

41. IntegraStudio User Manual // SOFT-ERG website. URL: http://www.softerg.com/integra/docs/pages/is_intro.htm (дата обращения: 26.01.2018).

42. Integrated Development Environment Software Overview // TrustRadius. URL: https://www.trustradius.com/integrated-development-environment (дата обращения: 26.01.2018).

43. Overview (Java SE 9 & JDK 9). // Oracle Help Center. URL: https://docs.oracle.com/javase/9/docs/api/overview-summary.html (дата обращения: 26.01.2018).

44. Package Index // Android Developers. URL: https://developer.android.com/reference/packages.html (дата обращения: 26.01.2018).

45. The Python Language Reference // Python 3.6.4 documentation. URL: https://docs.python.org/3/reference/index.html (дата обращения: 26.01.2018).

46. The Python Standard Library // Python 3.6.4 documentation. URL: https://docs.python.org/3/library/index.html (дата обращения: 26.01.2018).

47. The Python Tutorial // Python 3.6.4 documentation. URL: https://docs.python.org/3/tutorial/index.html (дата обращения: 26.01.2018).

48. TIOBE Index // TIOBE – The Software Quality Company. URL: https://tiobe.com/tiobe-index/ (дата обращения: 26.01.2018).

ПРИЛОЖЕНИЯ

Таблица 1

Изменения первых 10 позиций рейтинга TIOBE за 2017-2018 гг.

Позиция (2018)

Позиция (2017)

Изменение позиции

ЯП

Индекс (2018)

Изменение Индекса

1

1

0

Java

14.215%

-3.06%

2

2

0

Си

11.037%

+1.69%

3

3

0

C++

5.603%

-0.70%

4

5

+1

Python

4.678%

+1.21%

5

4

-1

C#

3.754%

-0.29%

6

7

+1

JS

3.465%

+0.62%

7

6

-1

VB .NET

2.261%

+0.30%

8

16

+8

R

2.549%

+0.76%

9

10

+1

PHP

2.532%

-0.03%

10

8

-2

Perl

2.419%

-0.33%

Источник: TIOBE Index. URL: https://tiobe.com/tiobe-index/

(дата обращения: 26.01.2018).

Таблица 2

Свойства ЯП, выраженные в процентах

Тип критериев

C

C++

Java

Python

C#

Частичная стоимость

16,(6)%

66,(6)%

83,(3)%

83,(3)%

83,(3)%

оптимизация

0%

50%

100%

100%

100%

автоматизация некоторых операций

0%

50%

100%

100%

100%

сложность исходника

50%

100%

50%

50%

50%

Портабельность ЯП

75%

75%

100%

100%

75%

независимость от ОС

100%

100%

100%

100%

50%

аппаратная совместимость

50%

50%

100%

100%

100%

Универсальность

75%

100%

75%

75%

100%

синтаксическая

50%

100%

100%

100%

100%

семантическая

100%

100%

50%

50%

100%

Целостность

83,(3)%

16,(6)%

50%

50%

50%

простота синтаксиса

100%

0%

0%

0%

0%

простота ограничений

100%

50%

50%

50%

50%

единообразие

50%

0%

100%

100%

100%

Читабельность и надёжность

16,(6)%

83,(3)%

100%

83,(3)%

100%

типизация

0%

50%

100%

50%

100%

абстракции

50%

100%

100%

100%

100%

исключения

0%

100%

100%

100%

100%

Таблица составлена по: Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. – СПб.: БХВ-Петербург, 2005  - 480 с., Орлов С. Теория и практика языков программирования: Учебник для вузов. 2-е изд. Стандарт 3-го поколения. - СПб.: Питер, 2017. – 688 с.: ил. – (серия «Учебник для вузов»). ISBN 978-5-496-00032-1.

Таблица 3

Характеристики IDE

Критерий

Visual Studio

Eclipse

NetBeans

Функциональность

96,5%

84%

83%

Лучанинов, Ленкин, 2016

100%

80%

80%

G2 Crowd, 2017

93%

88%

86%

Установка и доступность

83,5%

93%

91,5%

Лучанинов, Ленкин, 2016

80%

100%

100%

G2 Crowd, 2017

87%

86%

83%

Удобство использования

82,5%

80%

83%

Лучанинов, Ленкин, 2016

80%

80%

80%

G2 Crowd, 2017

85%

80%

86%

Портабельность IDE

60%

100%

60%

Производительность

100%

80%

80%

Безотказность

80%

60%

100%

Техподдержка и удобство сопровождения

92,5%

90%

90%

Лучанинов, Ленкин, 2016

100%

100%

100%

G2 Crowd, 2017

85%

80%

80%

Удобство создания коммерческого ПО

83%

88%

79%

Удобство администрирования

86%

84%

87%

Таблица составлена по: Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++ // Современные научные исследования и инновации. 2016. № 8. URL: http://web.snauka.ru/issues/2016/08/70888 (дата обращения: 26.01.2018), Grid℠ for Integrated Development Environment (IDE) – Winter 2017 // G2 Crowd. – Систем. Требования: браузер с поддержкой JS. URL: http://www.g2crowd.com/grid_report/documents/grid-for-integrated-development-environment-ide-winter-2017 (дата обращения: 26.01.2018).

Рисунок 1. Создание нового проекта и внешний вид интерфейса NetBeans

Рисунок 2. Описание ошибок в NetBeans

Рисунок 3. Простой пример рефакторинга в NetBeans

Рисунок 4. Автодополнение кода в NetBeans

Рисунок 5. Справочная система NetBeans

Рисунок 6. GUI приложение в Visual Studio (Toolbox можно передвинуть в любую часть редактора)

Рисунок 7. Простой пример рефакторинга исходника в IDE Visual Studio

Рисунок 8. Внешний вид Visual Studio

Рисунок 9. Навигация при поиске ошибок в Visual Studio

Рисунок 10. IntelliSense и справочная система Visual Studio

Рисунок 11. Автоисправление ошибок в Eclipse

Рисунок 12. Простой пример рефакторинга в Eclipse

Рисунок 13. Внешний вид Eclipse

Рисунок 14. Сообщение об ошибке в Eclipse Community

Приложение 1

Простая иерархия классов и интерфейсов на Java

Статус: интерпретируется, работает (JDK 8, файлы Java сгруппированы в один листинг, требуется точка входа).

public interface IWeapon extends IUnsafeTechnology//Наследование интерфейсов

{public Boolean IsLethal();}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@FunctionalInterface //разрешает инициализацию с помощью анонимной функции

public interface IUnsafeTechnology

{public double GetCurrentTraumaRisks();}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

public interface IExplosive

{public double GetPower();}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

public class Fireworks implements IExplosive

{

public double GetPower()

{return 0.00009;}

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Реализация интерфейса и наследование от класса одновременно

public class RejectedFireworks extends Fireworks implements IUnsafeTechnology

{

@Override

public double GetPower()//Полиморфизм через переопределение метода

{return randompower;}

//инкапсуляция посредством присвоения полям модификатора private

private double randompower = Math.random(), randomrisks = Math.random();

//из методов Get принято получать доступ к инкапсулированным данным

public double GetCurrentTraumaRisks()

{return randomrisks;}

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

public class NuclearBomb implements IWeapon, IExplosive

{

//усложнённый конструктор требует указание мощности

//и отдельный объект-детонатор, реализующий интерфейс

public NuclearBomb(double power, IUnsafeTechnology detonationDevice)

{

private_power = power;

detonator = detonationDevice;

}

//упрощённый конструктор принимает числовые значения

//он вызывает усложнённый конструктор

//аргумент-интерфейс инициализируется анонимной функцией

public NuclearBomb(double power, double detonationRisks)

{this(power, () -> detonationRisks);}

private double private_power;

private IUnsafeTechnology detonator;

public Boolean IsLethal()

{return true;}

public double GetPower()

{return private_power;}

public double GetCurrentTraumaRisks()

{return detonator.GetCurrentTraumaRisks();}

protected void finalize()//Финализатор

{private_power = 0;}

}

Приложение 2

Множественное наследование на Python

Статус: интерпретируется, работает (стандартный интерпретатор CPython).

from abc import ABCMeta, abstractmethod

class SmartPhone: #Абстрактный класс 1

__metaclass__ = ABCMeta

def __init__(self, number): # конструктор может наследоваться без переопределения

self.__contacts = dict()

self.__number = number #инкапсуляция того, что нельзя произвольно переназначать

GetContacts = lambda self: self.__contacts # упрощённая функция, возвращает contacts

def GetNumber(self): # классически объявленная функция, аналогичная предыдущей

return self.__number # возвращает номер

@abstractmethod # абстрактные методы помечаются специальными декораторами

def GetManufacturer(self):

pass # pass означает, что данный блок кода фактически не имеет содержимого

class ChineseSmartPhone(SmartPhone): # Абстрактный класс 2

__metaclass__ = ABCMeta

GetManufacturer = lambda self: "Designed in China. Assembled in China."

class IPhone(SmartPhone): # Реализуемый класс

GetManufacturer = lambda self: "Designed by Apple in California. Assembled in China."

class ChineseIPhone(ChineseSmartPhone, IPhone): # Наследуется китайский GetManufacturer

pass # класс использует данные своих прародителей, собственных данных у него нет

Приложение 3

Пример ООП в коде C++

Статус: компилируется, работает (GNU Compiler Collection, требуется точка входа).

#include <iostream>

#include <stdexcept>

using namespace std;

class Creature

{

public:

Creature(unsigned int age) //Конструктор

{local_age = age;}

unsigned int GetAge()

{return local_age;}

virtual bool IsAlive() = 0;//Абстрактный метод

virtual void GetDamage(unsigned char damage) = 0; //Абстрактный метод

private:

unsigned int local_age; //Сокрытие поля, изменение которого нежелательно

};

class Human: public Creature //Человек наследует от абстрактного живого существа

{

protected:

Human(string name, unsigned char age, unsigned char age_min, unsigned char age_max)

: Human(name, age) //Защищённый конструктор может быть унаследован потомками

{

if(name.size() < 1 || age < age_min || age > age_max)

throw invalid_argument("Неверный возраст"); //исключение

}

public:

Human(string name,unsigned char age)

: Creature(age)

{

if(name.size() < 1)

throw invalid_argument("Неверное имя");

local_name = name;

}

string GetName() {return local_name;}

bool IsAlive(){return hp != 0;}

void GetDamage(unsigned char damage) {IncHP(damage);}

~Human() //Деструктор

{IncHP(0xff);}

private:

string local_name;

unsigned char hp = 0xff;

friend class MedicalSupplies;

void IncHP(unsigned char inchp)

{hp = hp > 0 && hp > inchp ? hp - inchp : 0;}

};

class MedicalSupplies

{

private:

void Heal(Human h)

{

if(h.hp != 0)

h.hp = 0xff;

}

friend class Medic;

};

class Employee: public Human

{

public:

Employee(string name, unsigned char age, unsigned int pay)

: Human(name,age,18,70)

{return;}

unsigned long GetCash() {return cash;}

void Pay() {cash += paystandard;}

private:

unsigned long cash;

unsigned int paystandard;

};

class Medic: public Human

{

public:

Medic(string name, unsigned char age)

:Human(name,age,18,80)

{return;}

void GivePills(Human h)

{

MedicalSupplies m;

m.Heal(h);

}

virtual bool IsLegal() {return false;}

//Не практикующий врач не может выписывать таблетки

};

class MedicalPracticioner:public Medic,public Employee

{

public:

MedicalPracticioner(string name, unsigned char age)

:Medic(name, age),Employee(name,age,30000)

{return;}

bool IsLegal()

{return true;}//Перекрытый IsLegal

};

Приложение 4

Пример класса для проверки массива байтов на C#

Статус: компилируется, работает (.NET Framework 4.5.2, требуется точка входа).

using System;

using System.Linq;

namespace ConsoleApplication5

{

class ArrayChecker

{

public static void DeclarativeCheck(byte[] array, params byte[] searchpattern)

{

int[] i = new int[256];

foreach (byte x in array)

i[x]++;

// Декларативный LINQ-запрос, сортирующий коллекцию согласно условию

foreach (byte b in (from y in searchpattern where i[y] != 0 select y))

Print(b, i);

}

public static void FunctionalCheck(byte[] array, params byte[] searchpattern)

{

int[] i = new int[256];

Array.ForEach(array, x => i[x]++); // 2-й аргумент – анонимная функция

// LINQ-запрос в функциональном стиле

Array.ForEach(searchpattern.Where(y => i[y] != 0).ToArray(), b => Print(b, i));

}

private static void Print(byte b, int[] countData)

{ Console.WriteLine(b + " найден x" + countData[b]); }

}

}

Приложение 5

Простая иерархия классов, структур и интерфейсов в C#

Статус: компилируется, работает (.NET Framework 4.5.2, требуется точка входа).

using System;

namespace Hierarchy

{

interface IElectronicCard:IDisposable//Наследование интерфейсов

{ bool IsActive { get; } }

interface IKey

{

bool TryOpenTheDoor(string facilityName);

string Facility { get; }

}

struct Key:IKey//Реализация интерфейса структурой

{

public Key(string facilityName) //Конструктор структуры

{ facility = facilityName; }

public bool TryOpenTheDoor(string facilityName)

{ return Facility == facilityName; }

public string Facility

{ get { return facility == null || facility == "" ? "Общий доступ" : facility; } }

private string facility;

}

}

namespace Hierarchy

{

class KeyCard: IElectronicCard, IKey//Реализация 2-х интерфейсов

{

public KeyCard(string owner,string facilityName) //Конструктор класса

{

if (facilityName == null || facilityName == "")

throw new ArgumentException();

code = facilityName;

local_company = owner == null || owner == "" ? "Общий доступ" : owner;

}

public string Facility { get { return local_company; } }

public bool TryOpenTheDoor(string facilityName)

{ return IsActive && facilityName == local_company; }

public bool IsActive { get; private set; }

string code, local_company;

public void Dispose()

{

IsActive = false;//Деактивация карточки

code = null;

}

~KeyCard() //Финализатор класса

{ Dispose(); }

}

}

Приложение 6

Пример низкоуровневого обработчика массива байтов на Си

Статус: компилируется, работает (GNU Compiler Collection, требуется точка входа).

void charChecker

(

unsigned int length,

unsigned char data[length],

unsigned char pattern_length,

unsigned char pattern[pattern_length]

)

{

unsigned int result[256] = {0};

// Создание массива int для записи количества совпадений при поиске

for(register unsigned int i = 0; i < length; i++) // Цикл с регистровой переменной

result[data[i]]++; //Увеличение значения по индексу

for(register unsigned char ch = 0, index; ch <= pattern_length; index = pattern[ch++])

if(result[index] != 0)

printf("%d найдено %d раз \n", index, result[index]);

// Даже если pattern_length = 255, программа будет работать

// Переменная ch при переполнении просто превращается в 0

// Подобные трюки – один из сомнительных плюсов низкоуровневого программирования

}

  1. Кадырова Г.Р. Основы алгоритмизации и программирования: учебное пособие. – Ульяновск: УлГТУ, 2014. – С. 6.

  2. Программирование и основы алгоритмизации: Для инженерных специальностей технических университетов и вузов. /А.Г. Аузяк, Ю.А. Богомолов, А.И. Маликов, Б.А. Старостин. Казань: Изд-во Казанского национального исследовательского технического ун-та - КАИ, 2013. С. 4 – 31.

  3. Единая система программной документации: Сб. – М.: Стандартинформ, 2010. С. 22.

  4. Программирование и основы алгоритмизации. С. 4 – 31.

  5. Таненбаум Э. Архитектура компьютера. – 4-е изд. –СПб.: Питер, 2003. – С. 334.

  6. Таненбаум Э. Архитектура компьютера. С. 18.

  7. Единая система программной документации. С. 161.

  8. Орлов С. Теория и практика языков программирования: Учебник для вузов. 2-е изд. Стандарт 3-го поколения. - СПб.: Питер, 2017. С. 157.

  9. Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. – СПб.: БХВ-Петербург, 2005. С. 27 – 29.

  10. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 39

  11. ГОСТ 28397-89 (ИСО 2382-15-85). Языки программирования. Термины и определения // Информационная технология. Термины и определения: Сб. - М.: Стандартинформ, 2005. С. 229 – 236

  12. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. // «Новые информационные технологии». Тезисы докладов XVII Международной студенческой конференции-школы-семинара. – М.: МИЭМ, 2009. – С. 60.

  13. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 16.

  14. Единая система программной документации: Сб. - М.: Стандартинформ, 2010. С. 162 – 169.

  15. Таненбаум Э. Архитектура компьютера. С. 517.

  16. Орлов С. Теория и практика языков программирования. С.49.

  17. Blum R. Professional Assembly Language. - Wiley Publishing, Inc., 2005. P. 9.

  18. Таненбаум Э. Архитектура компьютера. С. 19 – 21.

  19. Орлов С. Теория и практика языков программирования. С. 41.

  20. Единая система программной документации. С. 162 – 163.

  21. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 17

  22. Орлов С. Теория и практика программирования. С. 40 – 42.

  23. Blum R. Professional Assembly Language. pp. 7 – 8.

  24. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 16.

  25. Орлов С. Теория и практика программирования. С. 40 – 42.

  26. Таненбаум Э. Архитектура компьютера. С. 50 – 52.

  27. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 18.

  28. Орлов С. Теория и практика программирования. С. 78.

  29. Орлов С. Теория и практика программирования. С. 50.

  30. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. — 4-е изд. — СПб.: Питер, 2013. — С. 37 – 43.

  31. Единая система программной документации: Сб. - М.: Стандартинформ, 2010. С. 162.

  32. Blum R. Professional Assembly Language. P. 6.

  33. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 14.

  34. Приходько О. В. Компьютерный практикум : учеб. пособие для будущих специалистов по управлению персоналом / О. В. Приходько, М. А. Токарева. - Оренбург: ГОУ ОГУ, 2008. – С. 103.

  35. Таненбаум Э. Архитектура компьютера. С. 18.

  36. Таненбаум Э. Архитектура компьютера. С. 518.

  37. Единая система программной документации. С. 162.

  38. Blum R. Professional Assembly Language. P. 10.

  39. Таненбаум Э. Архитектура компьютера. С. 551 – 552.

  40. Obfuscator-LLVM — Software Protection for the Masses. / P. Junod, J. Rinaldini, J. Wehrli, J. Michielin. - Software Protection (SPRO), 2015 IEEE/ACM 1st International Workshop on. – IEEE, 2015. –pp. 4 – 6.

  41. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 38.

  42. Blum R. Professional Assembly Language. P. 6.

  43. Приходько О. В. Компьютерный практикум. С. 103.

  44. Таненбаум Э. Архитектура компьютера. С.24.

  45. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. ACM HOPL-III, June 2007. – pp. 25 – 26.

  46. Приходько О. В. Компьютерный практикум. С. 103.

  47. Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. С.16 – 19.

  48. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 15.

  49. Орлов С. Теория и практика языков программирования. С. 62.

  50. Программирование и основы алгоритмизации. С. 8.

  51. Орлов С. Теория и практика языков программирования. С. 55.

  52. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 15.

  53. Орлов С. Теория и практика программирования. С. 59.

  54. Программирование и основы алгоритмизации. С. 33.

  55. Barendregt, H. The Impact of the Lambda Calculus in Logic and Computer Science // The Bulletin of Symbolic Logic. 1997. Vol. 3. №.2.- P. 194.

  56. Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. С.18.

  57. Barendregt H. The impact of the lambda calculus in logic and computer science. P. 194.

  58. Functional Programming vs. Imperative Programming (C#) // Microsoft Docs. URL: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/functional-programming-vs-imperative-programming (дата обращения: 26.01.2018).

  59. Орлов С. Теория и практика языков программирования. С. 62.

  60. Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. С.18.

  61. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 28.

  62. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 542.

  63. Орлов С. Теория и практика языков программирования. С. 66.

  64. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#.

    С. 263.

  65. Cardelli L., Wegner P. On understanding types, data abstraction, and polymorphism //ACM Computing Surveys (CSUR). 1985. Vol. 17. №. 4. – pp. 471-523.

  66. Cardelli L., Wegner P. On understanding types, data abstraction, and polymorphism. pp. 475 – 479

  67. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 61.

  68. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 60.

  69. Grid℠ for Integrated Development Environment (IDE) - Winter 2017 // G2 Crowd. – Систем. требования: браузер с поддержкой JS. URL: http://www.g2crowd.com/grid_report/documents/grid-for-integrated-development-environment-ide-winter-2017 (дата обращения: 26.01.2018).

  70. Кизянов А. О., Лучанинов Д. В. Анализ программных средств, реализующих язык программирования Python // Постулат. 2016. №8. URL: http://e-postulat.ru/index.php/Postulat/article/view/177/202 (дата обращения: 26.01. 2018).

  71. Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++ // Современные научные исследования и инновации. 2016. № 8. URL: http://web.snauka.ru/issues/2016/08/70888 (дата обращения: 26.01.2018).

  72. Кизянов А. О., Лучанинов Д. В. Анализ программных средств, реализующих язык программирования Python.

  73. Орлов С. Теория и практика языков программирования. С. 30 – 40.

  74. Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. С. 19 – 25.

  75. Свердлов С. Арифметика синтаксиса // PC Week/RE. 1998. №42-43. URL: https://www.itweek.ru/themes/detail.php?ID=49177 (дата обращения: 26.01.2018).

  76. Орлов С. Теория и практика языков программирования. С. 37 – 38.

  77. Вишнеков А.В., Иванова Е.М. Принятие решений при администрировании сложных технических проектов // Системный администратор. 2015.  №7-8 (152-153). URL: http://samag.ru/archive/article/3009 (дата обращения: 26.01.2018).

  78. Орлов С. Теория и практика языков программирования. С. 28 – 29.

  79. Кадырова Г.Р. Основы алгоритмизации и программирования: учебное пособие. С. 29 – 30.

  80. Barendregt H. The impact of the lambda calculus in logic and computer science. P.196

  81. Таненбаум Э. Архитектура компьютера. С. 23.

  82. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 18.

  83. Таненбаум Э. Архитектура компьютера. С. 50.

  84. Орлов С. Теория и практика языков программирования. С. 28.

  85. Программирование и основы алгоритмизации. С. 32.

  86. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. - P.4.

  87. Опалева Э.А., Самойленко В.П. Языки программирования и методы трансляции. С. 31 – 32.

  88. Орлов С. Теория и практика языков программирования. С. 57 – 59.

  89. Шилдт Г. Java. Полное руководство, 8-е изд.: Пер. с англ. — М: Вильямс, 2012. С. 39.

  90. Орлов С. Теория и практика языков программирования. С. 65 – 66.

  91. Керниган Б. У., Ритчи Д. М. Язык программирования C, 2-е изд. С. 112.

  92. Орлов С. Теория и практика языков программирования. С. 66.

  93. Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++.

  94. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P.3.

  95. Cardelli L., Wegner P. On understanding types, data abstraction, and polymorphism. pp. 475 – 479.

  96. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 5.

  97. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 2.

  98. Программирование и основы алгоритмизации. С. 32 – 35.

  99. Программирование и основы алгоритмизации. С. 32 – 35.

  100. Программирование и основы алгоритмизации. С. 82 – 88.

  101. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 5.

  102. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 35.

  103. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 3.

  104. Свердлов С. Арифметика синтаксиса.

  105. Программирование и основы алгоритмизации. С. 142 - 147.

  106. Орлов С. Теория и практика языков программирования. С. 477 – 484.

  107. Программирование и основы алгоритмизации. С. 130.

  108. Керниган Б. У., Ритчи Д. М. Язык программирования C, 2-е изд. С. 112.

  109. C++ Standard Library Header Files // Microsoft Developer Network. URL: https://msdn.microsoft.com/en-us/library/a7tkse1h (дата обращения: 26.01.2018).

  110. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 10.

  111. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 53.

  112. Таненбаум Э. Архитектура компьютера. С. 50 – 51.

  113. Орлов С. Теория и практика языков программирования. С. 494.

  114. Шилдт Г. Java. Полное руководство. — С. 208 – 237.

  115. Эванс Б, Вербург М. Java. Новое поколение разработки. — СПб.: Питер, 2014. С. 509 – 512.

  116. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 62.

  117. Таненбаум Э. Архитектура компьютера. С. 51.

  118. Шилдт Г. Java. Полное руководство. С. 43.

  119. Таненбаум Э. Архитектура компьютера. С. 51.

  120. Свердлов С. Арифметика синтаксиса.

  121. Шилдт Г. Java. Полное руководство. — С. 161 – 162.

  122. Overview (Java SE 9 & JDK 9). // Oracle Help Center. URL: https://docs.oracle.com/javase/9/docs/api/overview-summary.html (дата обращения: 26.01.2018).

  123. Package Index // Android Developers. URL: https://developer.android.com/reference/packages.html (дата обращения: 26.01.2018).

  124. Таненбаум Э. Архитектура компьютера. С. 51.

  125. Diakopoulos N., Cass S. Interactive: IEEE Spectrum Top 2017 // IEEE Spectrum. URL: https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2017 (дата обращения: 26.01.2018).

  126. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 19.

  127. The Python Tutorial // Python 3.6.4 documentation. URL: https://docs.python.org/3/tutorial/index.html (дата обращения: 26.01.2018).

  128. The Python Tutorial // Python 3.6.4 documentation. URL: https://docs.python.org/3/tutorial/index.html (дата обращения: 26.01.2018).

  129. Кизянов А. О., Лучанинов Д. В. Анализ программных средств, реализующих язык программирования Python.

  130. Буйначев С.К. Основы программирования на языке Python : учебное пособие. / С. К. Буйначев, Н. Ю. Боклаг. – Екатеринбург : Изд-во Урал. ун-та, 2014. – С. 45 – 49.

  131. The Python Tutorial // Python 3.6.4 documentation. URL: https://docs.python.org/3/tutorial/index.html (дата обращения: 26.01.2018).

  132. Буйначев С.К. Основы программирования на языке Python. С. 5 – 6.

  133. The Python Language Reference // Python 3.6.4 documentation. URL: https://docs.python.org/3/reference/index.html (дата обращения: 26.01.2018).

  134. Эванс Б, Вербург М. Java. Новое поколение разработки. С. 271 – 272.

  135. The Python Standard Library // Python 3.6.4 documentation. URL: https://docs.python.org/3/library/index.html (дата обращения: 26.01.2018).

  136. Буйначев С.К. Основы программирования на языке Python. С. 31 – 40.

  137. Кизянов А. О., Лучанинов Д. В. Анализ программных средств, реализующих язык программирования Python.

  138. Бизли Д. Python. Подробный справочник. – Пер. с англ. – СПб.: Символ-Плюс, 2010. С. 769.

  139. Эванс Б, Вербург М. Java. Новое поколение разработки. С. 271.

  140. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 21

  141. About Mono // Mono Project. URL: http://www.mono-project.com/docs/about-mono/ (дата обращения: 26.01.2018).

  142. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 28 – 29.

  143. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 34.

  144. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 45.

  145. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 216 – 226.

  146. Орлов С. Теория и практика языков программирования. С. 496 – 497.

  147. Подбельский В. В. Язык C#. Базовый курс: учеб. пособие. - 2-е изд. перераб. и доп. – М.: Финансы и статистика, 2013. – С. 267 – 291.

  148. Подбельский В. В. Язык C#. Базовый курс. С. 175.

  149. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 198.

  150. Подбельский В. В. Язык C#. Базовый курс. С. 255 – 266.

  151. Functional Programming vs. Imperative Programming (C#) // Microsoft Docs. URL: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/functional-programming-vs-imperative-programming (дата обращения: 26.01.2018).

  152. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 434 – 463.

  153. Подбельский В. В. Язык C#. Базовый курс. С. 341 – 359.

  154. Functional Programming vs. Imperative Programming (C#) // Microsoft Docs. URL: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/functional-programming-vs-imperative-programming (дата обращения: 26.01.2018).

  155. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 775 – 779.

  156. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 64.

  157. Подбельский В. В. Язык C#. Базовый курс. С. 212 – 214.

  158. Fundamentals of Garbage Collection // Microsoft Docs. URL: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#the_managed_heap (дата обращения: 26.01.2018).

  159. .NET Framework Class Library // Microsoft Developer Network. URL: https://msdn.microsoft.com/en-us/library/mt472912.aspx (дата обращения: 26.01.2018).

  160. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 580.

  161. About Mono // Mono Project. URL: http://www.mono-project.com/docs/about-mono/ (дата обращения: 26.01.2018).

  162. .NET Framework Class Library // Microsoft Developer Network. URL: https://msdn.microsoft.com/en-us/library/mt472912.aspx (дата обращения: 26.01.2018).

  163. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 775 – 779.

  164. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 19.

  165. Орлов С. Теория и практика языков программирования. С. 29.

  166. Таненбаум Э. Архитектура компьютера. С. 23.

  167. Таненбаум Э. Архитектура компьютера. С. 480 – 489.

  168. Вишнеков А.В., Иванова Е.М. Принятие решений при администрировании сложных технических проектов.

  169. Орлов С. Теория и практика языков программирования. С. 39.

  170. Кадырова Г.Р. Основы алгоритмизации и программирования. С. 20.

  171. Таненбаум Э. Архитектура компьютера. С. 50.

  172. Stroustrup B. Evolving a language in and for the real world: C++ 1991-2006. P. 2.

  173. Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++.

  174. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 64.

  175. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 58 – 92.

  176. IntegraStudio User Manual // SOFT-ERG website. URL: http://www.softerg.com/integra/docs/pages/is_intro.htm (дата обращения: 26.01.2018).

  177. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 58 – 92.

  178. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 64.

  179. Рихтер Дж. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. С. 31.

  180. Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++.

  181. Интегрированная среда разработки Visual Studio // Microsoft Developer Network. URL: https://msdn.microsoft.com/library/dn762121 (дата обращения: 26.01.2018).

  182. Configuring NetBeans IDE 8.0 for C/C++/Fortran // NetBeans Docs & Support. URL: https://netbeans.org/community/releases/80/cpp-setup-instructions.html (дата обращения: 26.01.2018).

  183. Configuring NetBeans IDE 8.0 for C/C++/Fortran // NetBeans Docs & Support. URL: https://netbeans.org/community/releases/80/cpp-setup-instructions.html (дата обращения: 26.01.2018).

  184. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 64 – 67.

  185. Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++.

  186. Любимцев Р.Г. Среда Eclipse для разработки программ на языке Java. / Под науч. рук. к.п.н. И.А. Буяковской // Информационно-коммуникационные технологии в педагогическом образовании. 2014. 02 (30). URL: http://infed.ru/articles/155/ (дата обращения: 26.01.2018).

  187. Кизянов А. О., Лучанинов Д. В. Анализ программных средств, реализующих язык программирования Python.

  188. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 65.

  189. Любимцев Р.Г. Среда Eclipse для разработки программ на языке Java.

  190. Лучанинов Д.В., Ленкин А.В. Анализ сред разработки программного обеспечения на языке С++.

  191. Любимцев Р.Г. Среда Eclipse для разработки программ на языке Java.

  192. Чернышов Л.Н. Среды разработки программного обеспечения: история и перспективы. С. 65.

  193. Blum R. Professional Assembly Language. P. 29.