Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ещё одна методичка по ЛО.doc
Скачиваний:
17
Добавлен:
23.03.2016
Размер:
433.15 Кб
Скачать

60

Лекция № 11 (2 часа)

1. ОБЩАЯ ХАРАКТЕРИСТИКА

ЯЗЫКОВ ПРОГРАММИРОВАНИЯ

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

1.1. ХАРАКТЕРИСТИКИ И СВОЙСТВА

ЯЗЫКОВ ПРОГРАММИРОВАНИЯ

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

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

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

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

Так, если какое-либо понятие используется в различных контекстах, то правила использования должны быть одни и те же. Единообразие понятий требует согласованного, единого подхода к описанию и использованию всех понятий.

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

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

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

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

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

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

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

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

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

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

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

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

знать их зависимость от многочисленных требований (рис.1.1).

1.2. ПУТИ РАЗВИТИЯ И КЛАССИФИКАЦИЯ

ЯЗЫКОВ ПРОГРАММИРОВАНИЯ

Первый язык программирования высокого уровня Фортран [12-- 14] создан в 1955 г. С этом времени развитие языков программирования характеризуется двумя основными тенденциями:

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

══════════════════════════════════════════════════════════════════

Мощность + +

Уровень + + + +

Концептуальная целостность + + +

Экономия понятий + +

Ортогональность понятий + +

Единообразие понятий + + +

══════════════════════════════════════════════════════════════════

■ Удобочитаемость

■ Надежность

■ Гибкость

■ Полнота

Простота ■

Мобильность ■

Эффективность ■

══════════════════════════════════════════════════════════════════

Легкость изучения

Легкость использования

Легкость модификации программы

Трудность допущения ошибок

Легкость автоматизации поиска ошибок

Легкость поиска ошибок вручную

Легкость понимания программы

Легкость документирования программы

Легкость разбиения программ на модули

Легкость описания логики программы

Легкость описания структур данных

Легкость управления аппаратурой

Наличие инструментальных средств

Наличие ППП

Наличие стандарта языка

Качество описания языка

Независимость от ЭВМ

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

Независимость от компилятора

Эффективность компиляции

Эффективность объектного кода

══════════════════════════════════════════════════════════════════

Стало возможным разрабатывать программы методом сверху вниз с помощью последовательном уточнения абстрактных действий. Язык Кобол [16, 17] заслуживает внимания за развитие такой важной части языков программирования как средства описания и обработки файлов. Однако и Фортран, и Алгол-60, и Кобол не были в полном смысле универсальными. Первые два были предназначены в основном для расчетных задач, а последний для экономических. Первым действительно универсальным языком программирования был ПЛ/1 [ 18 -- 20 ], объединивший многие возможности и средства языков Фортран, Алгол-60, Кобол. Он предоставляет практически все необходимые средства описания алгоритмов, хотя и не столь развитые, как в современных языках, средства описания и обработки таких сложных типов данных, как массивы и структуры, а также простых типов данных.

Параллельно с развитием универсальных языков создавались и специализированные языки, в которых за счет сужения области их использования удавалось построить отдельные высокоуровневые механизмы для описания и данных, и действий. Так, в языке Лисп [21, 22] допускается лишь один тип данных -- список и один базовый механизм выполнения -- рекурсивные функции.

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

Лисп функциональный язык в отличие от большинства других языков, которые являются императивными (программы на них строятся в виде последовательности команд выполнения требуемых операций). Целью создания Лиспа было использование его в системах автоматического доказательства теорем. Поэтому он называется также языком искусственного интеллекта. К этой группе языков относятся также разработанные позже и вобравшие в себя многие идеи Лиспа языки Пролог [23, 24], Плэнер [25]. Еще одним специализированным языком, созданным в начале 60-х годов, является Снобол [26]. Основной тип данных в Сноболе -- строка символов. Он содержит высокоуровневые средства для обработки строк, в основе реализации которых лежат нормальные алгоритмы А.А. Маркова. Поэтому он относится к марковским языкам. Областями применения Снобола являются конструирование компиляторов, символьная математика, обработка текстов, перевод с естественных языков и др. И, наконец, язык АПЛ [ 27, 28] -- мощный и высокоуровневый язык для решения научных задач. Основным типом данных является массив; имеется огромное множество разнообразных средств для описания действий с массивами. Этот язык -интерактивный: он позволяет программисту вмешиваться в процесс трансляции и исполнения, внося на любой стадии исправления и изменения, в отличие от пакетных языков, которые не предоставляют таких возможностей.

Конец 60-х -- начало 70-х годов -- период завершения развития средств описания действий и интенсификация развития средств описания данных. Идеи Алгол-60 доведены до совершенства в языке Алгол-68 [29, 30], который оказал значительное влияние на языки следующего поколения. Один из них RТL/2 [31] является образцом применения идей Алгола к проектированию языков. Он предоставляет унифицированное и надежное множество конструкций для четкого выражения программных передач управления. Язык С [32; 33] также вобрал в себя многие возможности предшественников, но содержит и ряд - интересных

идей, связанных с максимальной полнотой и эффективностью использования ЭВМ.

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

Независимо от Паскаля разработан язык Симула-67 [37 -- 39], который относится к языкам моделирования, т.е. используется как средство для имитационного моделирования сложных систем (к этому классу языков относятся также, например, GPSS [40], Симскрипт [41], Слам [42] ). Симула-67 содержит в качестве подмножества Алгол-60. Но что более важно и что поставило этот язык впереди своего времени, он содержит также новую конструкцию -- класс. Под классом понимается специальное средство описания типа данных, которое позволяет специфицировать как структуру типа, так и последовательность действий, которые предназначены для его обработки. Однако этот язык не располагал таким богатым набором типов данных, как Паскаль, что не позволило воспользоваться всеми преимуществами понятия класса. Объединение этих двух важных идей было осуществлено в языке Параллельный Паскаль. Развитие идеи, заложенной в понятие класса, происходило и в рамках других языков. Например, язык Смолток [43] основан на понятии объекта, содержащего понятийную и процедурную части. Объекты взаимодействуют между собой, посылая сообщения, представляющие собой требования выполнить те или иные процедуры над объектами-получателями сообщений. Этот язык принадлежит к классу объектноориентированных языков программирования. В языке Модула [44] введена конструкция "модуль", которая управляет доступом к объектам данных, ограничивая область вокруг объекта и операций над ним. Это существенное отличие от понятия класса стало основной идеей на последующих этапах развития языков программирования.

Параллельно с этим в различных языках программирования появились и другие важные идеи. Язык Евклид был разработан с целью обеспечить существенную поддержку верификации программ с помощью внесенных в текст программы утверждений о ее выполнении. В языке LIS разработаны механизмы для раздельной компиляции модулей. Язык МЕSА позволил накопить опыт использования подпрограмм обработки исключений. Во многих языках вводились конструкции параллельного программирования.

Язык Ада [ 45, 46] вобрал лучшие идеи языков-предшественников. Здесь две основные тенденции развития языков программирования достигли одновременной кульминации: и средства описания данных, и средства описания действий в Аде наиболее мощные, высокоуровневые, концептуально связанные в единое целое среди всех современных универсальных языков.

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

Кроме этом, необходимо наличие соответствующего программного обеспечения. Таким образом, можно уже говорить не о развитии языков, а о развитии языковых систем, включающих язык, транслятор, методы и процедуры автоматического (автоматизированного) доказательства правильности программ, верификатор и ряд других средств поддержки разработки программ. И раньше, конечно, говорили о системах программирования на том или ином языке. Однако из них вполне можно было выделить сам язык и разрабатывать, изучать его отдельно. При развитии указанной третьей тенденции делать это можно и нужно только в комплексе. Ряд языковых систем подобном рода разработаны, например системы IOTA [47], АFFIRM [4], СIР [48]. В перспективе эта новая тенденция развития языков приведет, как кажется, к постановке значительно более заманчивой цели -- построению языковых систем автоматической (автоматизированной) разработки корректных программ, первые шаги к которой сделал Э. Дейкстра [2].