Классификация языков программирования

Оглавление

 

Введение

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

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

Язык программирования служит двум связанным между собой целям: он дает программисту аппарат для задания действий, которые должны быть выполнены, и формирует концепции, которыми пользуется программист, размышляя о том, что делать.  Первой цели идеально отвечает язык, который настолько "близок к машине", что всеми основными машинными аспектами можно легко и просто оперировать достаточно очевидным для программиста образом. Второй цели идеально отвечает язык, который настолько "близок к решаемой задаче", чтобы концепции ее решения можно было выражать прямо и коротко.

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

В настоящее время ведется много дискуссий об исключительности того или иного языка программирования, например, резкая критика C# - одной из основных составляющих новой платформы .NET от Microsoft, стала уже достаточно банальной. Мы постараемся дать некоторый исторический очерк развития различных языков и пояснить на примерах некоторые общие тенденции. А также мы постараемся показать всё разнообразие языков программирования. Возможно, нам удастся убедить кого-то в бесполезности проведения дискуссий, аналогичных вышеупомянутой.

1. Классификация языков программирования

1.1. Языки программирования низкого уровня

Языки программирования низкого уровня (машинно-ориентированные) (low-level language) – это языки, наборы операторов и изобразительные средства которых существенно зависят от особенностей ЭВМ (внутреннего языка, структуры памяти и т.д.). Эти языки программирования предназначены для определенного типа ЭВМ и отражают его внутренний машинный код. Особенности машинно-ориентированных языков:

  • высокое качество создаваемых программ (компактность и скорость  выполнения);
  • возможность использования конкретных аппаратных ресурсов;
  • предсказуемость объектного кода и заказов памяти;
  • для составления эффективных программ необходимо знать систему команд и особенности функционирования данной ЭВМ;
  • трудоемкость процесса составления программ;
  • низкая скорость программирования;
  • невозможность непосредственного использования программ, составленных на этих языках, на ЭВМ других типов.

Машинно-ориентированные языки по степени автоматического программирования подразделяются на классы [1,4,13].

1.1.1. Машинный язык

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

Машинный язык (computer (machine) language)– язык программирования, элементами которого являются команды компьютера, характеризующиеся:

  • количеством операндов в команде;
  • назначением информации, задаваемой в операндах;
  • набором операций, которые может выполнить компьютер и др.

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

1.1.2. Языки символьного кодирования

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

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

1.1.3. Автокод

Языки, включающие в себя все возможности ЯСК, посредством расширенного введения макрокоманд, называются Автокоды.

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

Развитые автокоды получили название Ассемблеры. Сервисные программы и пр., как правило, составлены на языках типа Ассемблер [1,4,13].

1.1.4. Макрос

Язык, являющийся средством для замены последовательности символов описывающих выполнение требуемых действий ЭВМ на более сжатую форму - называется Макрос (средство замены).

В основном, Макрос предназначен  для того, чтобы сократить запись исходной программы. Компонент программного обеспечения, обеспечивающий функционирование макросов, называется макропроцессором. На макропроцессор поступает макроопределяющий и исходный текст. Реакция макропроцессора на вызов-выдача выходного текста.

Макрос одинаково может работать, как с программами, так и с данными [1,4,13].

1.2. Языки программирования высокого уровня

Язык программирования высокого уровня (high-level language)- язык программирования, разработанный для быстроты и удобства использования программистом. Слово «высокоуровневый» здесь означает, что язык предназначен для решения абстрактных высокоуровневых задач и оперирует не инструкциями к оборудованию, а логическими понятиями и абстракцией данных. Это позволяет быстрее программировать сложные задачи и обеспечивает относительную независимость от оборудования. Программирование на языках высокого уровня проще, чем на языках низкого уровня. Оно не требует глубоких знаний устройства компьютера и поэтому вполне доступно людям, не являющимися специалистами в вычислительной технике. Однако, программы, написанные на языках низкого уровня, как правило, отличаются более высокой скоростью работы, меньшим объемом и более полным использованием ресурсов вычислительной техники. Использование разнообразных трансляторов и интерпретаторов обеспечивает связь программ, написанных при помощи языков высокого уровня, с различными операционными системами и оборудованием, в то время как их исходный код остаётся, в большей части, неизменным.

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

Наиболее распространёнными языками подобного типа являются C++, Visual Basic, Java, Python, Ruby, Perl, Delphi, PHP [2,13].

1.2.1. Императивные языки

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

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

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

Среди процедурных языков выделяют в свою очередь структурные и операционные языки. В структурных языках одним оператором записываются целые алгоритмические структуры: ветвления, циклы и т.д. В операционных языках для этого используются несколько операций. Широко распространены следующие структурные языки: Pascal, C, Ada, PL/1. Среди операционных известны Fortran, Basic, Focal [2,13].

1.2.2. Декларативные языки

Декларативное (непроцедурное) программирование (declarative (nonprocedural) language) появилось в начале 70-х годов 20 века, но стремительное его развитие началось в 80-е годы, когда был разработан японский проект создания ЭВМ пятого поколения, целью которого явилась подготовка почвы для создания интеллектуальных машин. К непроцедурному программированию относятся функциональные и логические языки.

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

Перечисленные свойства характеризуют аппликативные языки как языки программирования очень высокого уровня.

Первым таким языком был LISP (LIST Processing - обработка списков), созданный в 1959 году. Цель его создания состояла в организации удобства обработки символьной информации.

В логических (реляционных) языках (logical language) программа вообще не описывает действий. Она задает данные и соотношения между ними. После этого системе можно задавать вопросы. Машина перебирает известные и заданные в программе данные и находит ответ на вопрос. Порядок перебора не описывается в программе, а неявно задается самим языком. Классическим языком логического программирования считается PROLOG (PROgramming in LOGic — программирование в терминах логики). Этот язык был создан французским ученым А. Кольмероэ в 1973 году.

Языки логического программирования характеризуются:

  • высоким уровнем;
  • строгой ориентацией на символьные вычисления;
  • возможностью инверсных вычислений, то есть переменные в процедурах не делятся на входные и выходные;
  • возможной логической неполнотой, поскольку зачастую невозможно выразить в программе определенные логические соотношения, а также невозможно получить из программы все выводы правильные [2,13].

1.2.3. Объектно-ориентированные языки

Концепция объектно-ориентированного программирования (object- oriented language) подразумевает, что основой управления процессом реализации программы является передача сообщений объектам. Поэтому объекты должны определяться совместно с сообщениями, на которые они должны реагировать при выполнении программы. В этом состоит главное отличие ООП от процедурного программирования, где отдельно определённые структуры данных передаются в процедуры (функции) в качестве параметров. Таким образом, объектно-ориентированная программа состоит из объектов – отдельных фрагментов кода, обрабатывающего данные, которые взаимодействуют друг с другом через определённые интерфейсы.

Объектно-ориентированный язык программирования должен обладать следующими свойствами:

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

Элементы объектно-ориентированного программирования (ООП) появились в начале 70-х годов в языке моделирования Simula, затем получили свое развитие, и в настоящее время ООП принадлежит к числу ведущих технологий программирования [2,13].

1.2.4. Специализированные языки

Специализированные языки (special language) - языки программирования, ориентированные на решение определенного круга задач. Этих задах много, рассмотрим некоторые из них.

Классификация языков программирования по типам задач:

  • Задачи искусственного интеллекта (Lisp, Prolog, Planner, QA4, FRL, KRL, QLisp);
  • Задачи вычислительной математики и физики (Occam, PFOR, Glypnir, Actus, Cobol, Алгол, Фортран);
  • Разработка интерфейса (Forth, C, C++, Ассемблер, Макроассемблер, Simula-67, OAK, Smalltalk, Java);
  • Разработка программ-оболочек, разработка систем (Forth, C, C++, Ассемблер, Макроассемблер, Simula-67, OAK, Smalltalk, Java, РПГ);
  • Задачи вычислительного характера (Algol, Fortran, Cobol, Ada, PL/1, Basic, Pascal);
  • Оформление документов, обработка больших текстовых файлов, организация виртуальных трехмерных интерфейсов в Интернете (HTML, Perl, PHP, Tcl/Tk, VRML, XML, PL/SCL);
  • Языки программирования баз данных. (SQL, dBase II, FoxPro, Clipper);

Кроме того, существуют гибридные (комбинированные) языки (hibrid language) - языки программирования, использующие также и средства других языков [2,13,14].

2. Поколения языков программирования

Языки программирования по своим возможностям и времени создания принято делить на несколько поколений (Generation Language, GL). Каждое из последующих поколений по своей функциональной мощности качественно отличается от предыдущего. К сегодняшнему дню насчитывается пять поколений ЯП.

В первое поколение (1GL) входят языки, созданные в 40-50 гг., когда компьютеры только появились на свет. В то время программы писались в машинных кодах, то есть каждая компьютерная команда вместе с ее операндами вводилась в ЭВМ в двоичном виде. Это требовало огромных усилий по набору цифровых текстов и приводило к множеству трудноуловимых ошибок. Ситуация качественно изменилась в середине 50-х годов, когда был написан первый ассемблер. Хотя этот ассемблер был неполноценным в сегодняшнем понимании, но он позволял задавать названия команд в символическом виде и указывать числа не только в двоичном, но и в десятичном или шестнадцатеричном формате, что существенно облегчало работу программистов.

Языки первого поколения продолжают использоваться и сегодня, хотя в значительно меньшем объеме. Чаще всего приходится писать программы в машинных кодах для новых микропроцессоров, для которых еще не разработаны компиляторы, поддерживающие требуемый набор команд [13].

Расцвет второго поколения языков программирования (2GL) пришелся на конец 50-х - начало 60-х годов. Был создан символический ассемблер, позволявший писать программы без привязки к конкретным адресам памяти. В него было введено понятие переменной, и он, по сути, стал первым настоящим (хоть и машинно-ориентированным) языком программирования со своим компилятором. Скорость создания и эффективность программ резко возросли. Ассемблеры активно применяются в настоящее время, как правило, для создания программ, максимально использующих возможности аппаратуры - различных драйверов, модулей состыковки с нестандартным оборудованием и т.д. [13].

Третье поколение ЯП (3GL) принято относить к 60-м годам. В это время родились языки, которые называют универсальными языками высокого уровня, с их помощью можно решать задачи из любых областей. Это общеизвестные Fortran, Cobol, Algol и др. Такие качества новых языков, как относительная простота, независимость от конкретного компьютера и возможность использования мощных синтаксических конструкций позволили резко повысить производительность труда программистов. Кроме того, понятная большинству пользователей процедурная идеология этих языков позволила привлечь к написанию небольших программ (как правило, расчетного или учетного характера), большое количество специалистов из некомпьютерных областей.

Подавляющее большинство языков 3GL успешно применяется и сегодня. Современные компиляторы с интегрированными средами разработки предоставляют очень удобные средства поддержки процесса создания программ. Практически все современные коммерческие продукты, рассчитанные на массовый рынок, написаны на языках 3-го поколения [13].

С начала 70-х годов по настоящее время тянется период языков четвертого поколения (4GL). Несмотря на рождение новых технологий (ООП, визуальное программирование, CASE-методологии, системный анализ), процесс создания больших программных комплексов оказался очень трудоемкой задачей, так как для реализации крупных проектов требовался более глобальный подход к решаемым задачам, чем предлагали имевшиеся средства разработки. Языки 4GL частично снимали эту проблему. Целью их создания было в первую очередь стремление к увеличению скорости разработки проектов, снижение числа ошибок и повышение общей надежности работы больших программных комплексов, возможность быстрого и легкого внесения изменений в готовые проекты. А также упрощение самих языков для конечного пользователя, активное внедрение технологий визуальной разработки и т. д. Все средства разработки 4-го поколения имеют мощные интегрированные оболочки и обладают простым и удобным пользовательским интерфейсом. Они чаще всего используются для проектирования баз данных и работы с ними (встроенные языки СУБД), что объясняется возможностью формализации всех понятий, используемых при построении реляционных баз данных. Как правило, в эти языки встраиваются мощные примитивы, позволяющие одним оператором описать такую функциональность, для реализации которой на языках младших поколений потребовалось бы написать тысячи строк кода.

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

Рождение языков пятого поколения относится к настоящему времени. Довольно неожиданно вокруг самого названия 5GL разгорелись жаркие споры. Возникло несколько программистских "школ", представители, каждой из которых, имеют свое мнение о том, какие средства разработки считать языками 5-го поколения, а какие нет. Например, на страницах лондонского журнала SURPRISE (Surveys and Presentations in Information Systems Engineering), выпускаемого при поддержке английских министерств по электронике и вычислительной технике, рассматривают средства разработки 5-го поколения в более широком аспекте, чем это принято делать в отношении обычных языков программирования. Они считают, что к системам 5GL можно отнести не только новые мощные языки, но и системы создания программ, ориентированные на непрограммиста. Подобные системы отличаются стремлением предоставить конечному пользователю-неспециалисту богатые возможности создания прикладных программ с помощью визуальных средств разработки без знания программирования. Главная идея, которая закладывается в эти системы 5GL - возможность компьютерного интерактивного или полностью автоматического преобразования инструкций, вводимых в систему наиболее удобными человеку методами в максимально наглядном виде, в текст на универсальных языках программирования, описывающий готовую программу.

Однако большая группа специалистов считает, что языки 5-го поколения являются именно языками программирования, требующими от разработчика соответствующей квалификации и умения составлять программы вручную. Сторонники этого мнения под языками 5GL понимают специализированные языки, оперирующие не абстрактными переменными, а понятиями своей предметной области, например, бухгалтерскими счетами или ферзями и пешками. Это, как правило, узкоспециализированные языки, предоставляющие программисту мощные высокоуровневые возможности обработки информации из конкретной области знаний. К языкам 5-го поколения относят также интегрированные с базами знаний и экспертными системами программные комплексы с собственными языками программирования. Типичный пример - созданная в Австралии самообучающаяся нейронная сеть "LISA" с встроенным языком описания фактов, сущностей и взаимосвязей между ними, на торговой марке которой красуется "лейбл" 5GL.

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

Пока сложно сказать, насколько успешной окажется тенденция стремления к полной и недостижимой универсальности. На практике с помощью систем 5GL этого направления пока удавалось создать небольшие и логически простые приложения, которые при реализации на языках 3-го поколения потребовали бы не более 10 000 исходных строк кода. При попытках разработки сложных программ возникает проблема, типичная для более старых языков — необходимость отладки, что требует от пользователя высокой квалификации.

Языки 5GL, ориентированные на конкретные области применения, уже в ближайшее время могут завоевать самую широкую популярность. Наиболее вероятно это для продуктов, позволяющих создавать приложения для работы с базами данных, области информатики, наиболее успешно поддающейся формализации [13].

3. История развития основных языков программирования

3.1 С чего все начиналось

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

3.2. Assembler (Ассемблер)

Может показаться, что это событие не было из ряда вон выходящим: как были машинные коды, так и остались. Однако это не так. Да, программирование в машинных кодах осталось, но она стало символическим кодированием машинных команд. Это был огромный шаг вперед, теперь программисту вовсе не нужно было разбираться в программировании команд на аппаратном уровне. В программировании на Ассемблере стало возможным использование меток, что облегчало в значительной мере отладку программ. Появилась возможность разработки целой серии вычислительных машин с одинаковой или сходной системой команд, что можно назвать первым подобием переносимости кода. Ассемблер нес в себе еще одну революционность для программирования: появилось два представления программ на нем: в машинных кодах и в чистом, откомпилированном виде. Но, по мере развития Ассемблера, его постоянного усложнения, дизассемблирование, т.е. перевод из одного представления программы в другой, становилось все более трудным делом. Надо отметить, что в итоге автоматическое дизассемблирование стало невозможным - для этой цели стали появляться специальные программы-дизассемблеры [15].

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

Рисунок 1. Эволюция языков программирования.

3.3. Lisp (Лисп)

С 50-х годов специалисты по ИИ (ИИ - искусственный интеллект) искали язык, пригодный для манипулирования понятиями, выраженными словами и фразами на естественном языке. Первым результатом этих поисков явилось семейство языков под названием IPL, от (Information Processing Languages — языки обработки информации). Оно было создано пионером ИИ Алленом Ньюэллом и его сотрудниками. Вначале работа велась в «Рэнд корпорейшн», а затем в Технологическом институте Карнеги (позднее Карнеги—Меллона) в Питтсбурге, бастионе исследований по ИИ.

Центральной идеей IPL было понятие списка.

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

Понятие списка интересовало и другого выдающегося члена тесного сообщества исследователей ИИ — Джона Маккарти, блестящего и разностороннего математика. В 1958г., когда при его помощи организовалась лаборатория по ИИ при МТИ, Маккарти начал работу над языком высокого уровня, в котором понятие списка сочеталось с системой обозначений, заимствованной из экзотической области математики — так называемого лямбда-исчисления. Введенное в 1931 г. математиком и логиком Алонзо Черчем, это исчисление оперирует только тремя элементами: символами, представляющими переменные и константы, скобками для группировки символов и обозначениями функций, выражаемыми греческой буквой "Лямбда".  Маккарти назвал свой язык LISP от List Processing — обработка списков [1,2].

3.4. FORTRAN (Фортран)

FORTRAN - это первый язык программирования высокого уровня, который получил признание и стал широко применяться. В своем исходном варианте FORTRAN был разработан фирмой IBM в 1957 г. как язык для работы на компьютерах IBM 704. В это время программисты, привыкшие к использованию языка ассемблера, сомневались в возможности использования языков высокого уровня. Наиболее серьезным аргументом была малая эффективность выполнения кода, получающегося в результате трансляции программ, написанных на этих языках. Первые версии FORTRAN были ориентированы главным образом на обеспечение эффективности выполнения.  Первое стандартное определение языка появилось в 1966 г., а затем в 70-х были внесены существенные изменения, которые привели к появлению FORTRAN 77, и в 90-х - FORTRAN 90.

Классификация языков программирования