Что такое язык программирования опишите состав и интерфейс среды разработки программ на используемом
Целью данной работы является сравнение четырех языков: Ada, C, C++ и Java. А также поиск достоинств и недостатков каждого из них, сфер наиболее разумного применения.
Общие сведения о языках
С: Язык программирования Си отличается минимализмом. Авторы языка хотели, чтобы программы на нём легко компилировались с помощью однопроходного компилятора, после компиляции каждой элементарной составляющей программы соответствовало весьма небольшое число машинных команд, а использование базовых элементов языка не задействовало библиотеку времени выполнения. Однопроходный компилятор компилирует программу, не возвращаясь назад, к уже откомпилированному тексту. Поэтому использованию функции должно предшествовать её объявление. Код на Си можно легко писать на низком уровне абстракции, почти как на ассемблере. Иногда Си называют «универсальным ассемблером» или «ассемблером высокого уровня», что отражает различие языков ассемблера для разных платформ и единство стандарта Си, код которого может быть скомпилирован без изменений практически на любой модели компьютера. Си часто называют языком среднего уровня, учитывая то, как близко он работает к реальным устройствам.
Компиляторы Си разрабатываются сравнительно легко благодаря относительно низкому уровню языка и скромному набору элементов. Поэтому данный язык доступен на самых различных платформах (возможно, круг этих платформ шире, чем у любого другого существующего языка). К тому же, несмотря на свою низкоуровневую природу, язык позволяет создавать переносимые программы и поддерживает программиста в этом. Программы, соответствующие стандарту языка, могут компилироваться на самых различных компьютерах.
Одним из последствий высокой эффективности и переносимости Си стало то, что многие компиляторы, интерпретаторы и библиотеки других языков высокого уровня часто выполнены на языке Си. А системы на базе ядра Linux практически полностью написаны на Си.
C++ : компилируемый статически типизированный язык программирования общего назначения. Поддерживая разные парадигмы программирования, сочетает свойства как высокоуровневых, так и низкоуровневых языков. В сравнении с его предшественником — языком C, — наибольшее внимание уделено поддержке объектно-ориентированного и обобщённого программирования. Название «C++» происходит от языка C, в котором унарный оператор ++ обозначает инкремент переменной.
При создании C++ стремились сохранить совместимость с языком C. Большинство программ на C будут исправно работать и с компилятором C++. C++ имеет синтаксис, основанный на синтаксисе C.
Ada: Язык Ada - результат самого обширного и самого дорогостоящего из когда-либо предпринимавшихся проектов по созданию языка программирования. Язык Ada разрабатывался для Министерства обороны США, так что состояние существовавшей вычислительной среды способствовало определению его формы.
Работы по разработке были начаты в 1975 году после того как в Министерстве Обороны США был разработан список требований к языку, который был широко распространен. Однако, ни один из существовавших на тот момент времени языков программирования не соответствовал выдвинутым требованиям. В итоге, в 1977 году Министерство Обороны США выдвигает предложение создать новый язык.
Из большого числа предложений было отобрано четыре, для последующего пересмотра и доработки. Позже, для дальнейшего уточнения, из них отобрали два, и в финале выбрали проект представленный компанией Cii-Honeywell Bull. Этому языку и было дано имя Ада, в честь Августы Ады Байрон, графини Лавлейс, дочери английского поэта лорда Байрона. Она была сотрудницей Чарльза Беббиджа, изобретателя аналитической машины, и написала для этой машины программу вычисления чисел Бернулли - Августа Ада по праву считается первым в мире программистом. Разработкой данного проекта руководил Jean Ichbiah.
Язык претерпел пересмотр при введении нового ISO стандарта в начале 1995 года (ISO/IEC 8652:1995).
Этот стандарт исправляет многие упущения и недостатки оригинального языка, и дополняет его многими новыми полезными свойствами.
Java — объектно-ориентированный язык программирования, разработанный компанией Sun Microsystems (в последующем приобретённой компанией Oracle). Приложения Java обычно транслируется в специальный байт-код, поэтому они могут работать на любой виртуальной Java-машине (JVM) вне зависимости от компьютерной архитектуры.
Достоинством подобного способа выполнения программ является полная независимость байт-кода от операционной системы и оборудования, что позволяет выполнять Java-приложения на любом устройстве, для которого существует соответствующая виртуальная машина. Другой важной особенностью технологии Java является гибкая система безопасности благодаря тому, что исполнение программы полностью контролируется виртуальной машиной. Любые операции, которые превышают установленные полномочия программы (например, попытка несанкционированного доступа к данным или соединения с другим компьютером) вызывают немедленное прерывание.
Часто к недостаткам концепции виртуальной машины относят то, что исполнение байт-кода виртуальной машиной может снижать производительность программ и алгоритмов, реализованных на языке Java. В последнее время был внесен ряд усовершенствований, которые несколько увеличили скорость выполнения программ на Java:
- применение технологии трансляции байт-кода в машинный код непосредственно во время работы программы (JIT-технология) с возможностью сохранения версий класса в машинном коде,
- широкое использование платформенно-ориентированного кода (машинный-код) в стандартных библиотеках,
- аппаратные средства, обеспечивающие ускоренную обработку байт-кода (например, технология Jazelle, поддерживаемая некоторыми процессорами фирмы ARM).
Парадигма программирования — это совокупность идей и понятий, определяющая стиль написания программ. Парадигма, в первую очередь, определяется базовой программной единицей и самим принципом достижения модульности программы. Важно отметить, что парадигма программирования не определяется однозначно языком программирования — многие современные языки программирования являются мультипарадигменными, то есть допускают использование различных парадигм. Так на языке С, который не является объектно-ориентированным, можно писать объектно-ориентированным образом.
Императивный язык - Императивный язык должен описывать не столько саму задачу, сколько её решение. Несмотря на различие декларативных и императивных языков в конечном счёте скомпилированная программа представляет собой набор чётких и недвусмысленных инструкций, т.е. императивна.
Именно они отражают принципы Фон Неймана
- Понятия переменной, являющейся аналогом ячейки оперативной памяти
- Операторов ввода\вывода информации в ячейки
- Операторов присваивания, отражающих пересылки информации между ячейками
- Команд управления(усл. переход, циклы)
Объектно-ориентированный язык -Объектно-ориентированный язык позволяет использовать три парадигмы ООП: наследование, инкапсуляцию и полиморфизм.
Функциональный язык - Функциональное программирование - это парадигма программирования, в которой выполнение программы представляет собой вычисление некоторого выражения, описывающего применение функций (в математическом понимании) ко входным данным. В отличие от традиционного подхода к программированию (императивное программирование), где выполнение программы рассматривается как последовательная смена состояний в памяти компьютера (т.е. изменение значений переменных), в функциональном программировании нет понятия переменной и присваивания, функция не имеет явного внутреннего состояния, а оперирует только над входными данными. Из-за этого отсутствуют побочные эффекты, программа становится более простой в отладке.
Рефлексивный язык - означает наличие процесса, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения.
Обобщённое программирование — парадигма программирования, заключающаяся в таком описании данных и алгоритмов, которое можно применять к различным типам данных, не меняя само это описание.
Логическая - Программа представляет собой описание фактов и правил вывода в некотором логическом исчислении. Желаемый результат, который часто записывается как вопрос, получается системой в результате попытки применения описанных правил — путем логического вывода. Интересными особенностями являются отсутствие детерминированности в общем случае, внутренняя склонность к распараллеливанию.
Декларативная - противоположность императивному. Декларативный язык описывает не столько решение задачи, сколько саму задачу («ЧТО» нужно получить), а каким образом получить решение, уже должен определять компьютер.
Распределенная - Язык, содержащий специальные конструкции для поддержки распараллеливания программы на несколько компьютеров.
Со времени создания первых программируемых машин человечество придумало более двух с половиной тысяч языков программирования. [1] Каждый год их число увеличивается. Некоторыми языками умеет пользоваться только небольшое число их собственных разработчиков, другие становятся известны миллионам людей. Профессиональные программисты иногда применяют в своей работе более десятка разнообразных языков программирования.
Содержание
Стандартизация языков программирования
Язык программирования может быть представлен в виде набора спецификаций, определяющих его синтаксис и семантику.
Для многих широко распространённых языков программирования созданы международные стандарты. Специальные организации проводят регулярное обновление и публикацию спецификаций и формальных определений соответствующего языка. В рамках таких комитетов продолжается разработка и модернизация языков программирования и решаются вопросы о расширении или поддержке уже существующих и новых языковых конструкций.
Типы данных
Современные цифровые компьютеры обычно являются двоичными и данные хранят в двоичном (бинарном) коде (хотя возможны реализации и в других системах счисления). Эти данные как правило отражают информацию из реального мира (имена, банковские счета, измерения и др.), представляющую высокоуровневые концепции.
Статически-типизированные языки могут быть в дальнейшем подразделены на языки с обязательной декларацией, где каждая переменная и объявление функции имеет обязательное объявление типа, и языки с выводимыми типами. Иногда динамически-типизированные языки называются латентно-типизированными.
Структуры данных
Системы типов в языках высокого уровня позволяют определять сложные, составные типы, так называемые структуры данных. Как правило, структурные типы данных образуются как декартово произведение базовых (атомарных) типов и ранее определённых составных типов.
Основные структуры данных (списки, очереди, хеш-таблицы, двоичные деревья и пары) часто представлены особыми синтаксическими конструкциями в языках высокого уровня. Такие данные структурируются автоматически.
Семантика языков программирования
Существует несколько подходов к определению семантики языков программирования.
Наиболее широко распространены разновидности следующих трёх: операционного, деривационного (аксиоматического) и денотационного (математического).
Парадигма программирования
Язык программирования строится в соответствии с той или иной базовой моделью вычислений и парадигмой программирования.
В настоящее время также активно развиваются проблемно-ориентированные, декларативные и визуальные языки программирования.
Способы реализации языков
Языки программирования могут быть реализованы как компилируемые и интерпретируемые.
Программа на компилируемом языке при помощи компилятора (особой программы) преобразуется (компилируется) в машинный код (набор инструкций) для данного типа процессора и далее собирается в исполнимый модуль, который может быть запущен на исполнение как отдельная программа. Другими словами, компилятор переводит исходный текст программы с языка программирования высокого уровня в двоичные коды инструкций процессора.
Если программа написана на интерпретируемом языке, то интерпретатор непосредственно выполняет (интерпретирует) исходный текст без предварительного перевода. При этом программа остаётся на исходном языке и не может быть запущена без интерпретатора. Процессор компьютера, в этой связи, можно назвать интерпретатором для машинного кода.
Разделение на компилируемые и интерпретируемые языки является условным. Так, для любого традиционно компилируемого языка, как, например, Паскаль, можно написать интерпретатор. Кроме того, большинство современных «чистых» интерпретаторов не исполняют конструкции языка непосредственно, а компилируют их в некоторое высокоуровневое промежуточное представление (например, с разыменованием переменных и раскрытием макросов).
Как правило, скомпилированные программы выполняются быстрее и не требуют для выполнения дополнительных программ, так как уже переведены на машинный язык. Вместе с тем, при каждом изменении текста программы требуется её перекомпиляция, что замедляет процесс разработки. Кроме того, скомпилированная программа может выполняться только на том же типе компьютеров и, как правило, под той же операционной системой, на которую был рассчитан компилятор. Чтобы создать исполняемый файл для машины другого типа, требуется новая компиляция.
Интерпретируемые языки обладают некоторыми специфическими дополнительными возможностями (см. выше), кроме того, программы на них можно запускать сразу же после изменения, что облегчает разработку. Программа на интерпретируемом языке может быть зачастую запущена на разных типах машин и операционных систем без дополнительных усилий.
Однако интерпретируемые программы выполняются заметно медленнее, чем компилируемые, кроме того, они не могут выполняться без программы-интерпретатора.
Подобный подход в некотором смысле позволяет использовать плюсы как интерпретаторов, так и компиляторов. Следует упомянуть, что есть языки, имеющие и интерпретатор, и компилятор (Форт).
Используемые символы
Современные языки программирования рассчитаны на использование ASCII, то есть доступность всех графических символов ASCII является необходимым и достаточным условием для записи любых конструкций языка. Управляющие символы ASCII используются ограниченно: допускаются только возврат каретки CR, перевод строки LF и горизонтальная табуляция HT (иногда также вертикальная табуляция VT и переход к следующей странице FF).
Заметным исключением является язык APL, в котором используется очень много специальных символов.
Среды программирования (или как их еще называют, среды разработки) - это программы, в которых программисты пишут свои программы. Иными словами, среда программирования служит для разработки ( написания) программ и обычно ориентируется на конкретный язык или несколько языков программирования (в этом случае языки, обычно, принадлежат одной языковой группе, например, Си-подобные). Интегрированная среда программирования содержит в себе все необходимое для разработки программ:
- редактор с подсветкой синтаксиса конкретного языка программирования. В нем программист пишет текст программы, так называемый программный код;
- компилятор. Он, как мы уже с вами знаем, транслирует программу, написанную на высокоуровневом языке программирования в машинный язык (машинный код), непосредственно понятный компьютеру. Язык С++ относится к компилируемым языкам, поэтому для обработки текстов его программ служит компилятор, иногда вместо компилятора (либо вместе с ним) используется интерпретатор, для программ, написанных на интерпретируемых языках программирования;
- отладчик. Служит для отладки программ. Как мы все знаем, ошибки в программах допускают абсолютно все: и новички, и профессионалы - они могут быть синтаксическими (обычно они выявляются еще на стадии компиляции) и логическими. Для тестирования программы и выявления в ней логических ошибок служит отладчик.
Мы рассмотрели базовую комплектацию среды программирования, но иногда в них присутствуют еще и такие компоненты, как система управления версиями, различные инструменты для конструирования графического интерфейса программы, браузер классов, инспектор объектов и другие.
Общее описание работы среды программирования
Давайте сейчас подробно рассмотрим процесс разработки программы в среде программирования, от момента начала написания кода программы до получения скомпилированного экзешника (файла с расширением .exe), который уже можно непосредственно запускать вне среды разработки. Как правило, для того, чтобы выполнить программу на С++, надо пройти шесть этапов:
- Первый этап - редактирование;
- Второй этап - предварительная (препроцессорная) обработка;
- Третий этап - компиляция;
- Четвертый этап - компоновка;
- Пятый этап - загрузка;
- Шестой этап - выполнение.
Мы остановимся на системе С++, ориентированной на UNIX, чтобы лучше понять этот процесс. В Windows некоторые из этих этапов будут проходить автоматически без участия программиста.
Редактирование. Это первый этап разработки программы в среде программирования и представляет он собой редактирование файла (исходного файла, который в последствии будет содержать код программы). Он выполняется с помощью редактора программ, который напоминает нам обычный текстовый редактор, такой как блокнот, word и т.д. Программист набирает в этом редакторе свою программу на С++ и, если это необходимо, вносит в нее различные изменения или исправления. Одним словом, работает с кодом программы как с обычным текстом. Имена файлов программ на С++ часто оканчиваются расширением .с или .срр. (это вы сами сможете пронаблюдать, когда загляните в папку с проектом).
Компиляция. На этом этапе компилятором проверяется текст программы на наличие синтаксических ошибок и затем, если все хорошо, текст программы с подстановками, сделанными на предыдущем этапе, преобразуется в машинный код (код на языке, уже непосредственно понятный компьютеру). Иногда его еще называют объектным. На этом этапе создается файл с расширением .obj. Также в вашей программе могут использоваться кусочки уже готового машинного кода, расположенного в иных библиотеках (например, в файлах с расширением .lib). На этапе компиляции эти библиотеки еще не будут подключены к только что созданному машинному коду. Они подключаются на следующем этапе.
Компоновка. Следующий этап называется компоновка. Программы на С++ обычно содержат ссылки на функции, определенные где-либо вне самой программы, например, в стандартных библиотеках или в личных библиотеках групп программистов, работающих над данным проектом. Объектный код, созданный компилятором, обычно содержит «дыры» из-за этих отсутствующих частей. Компоновщик связывает объектный код с кодами отсутствующих функций, чтобы создать исполняемый загрузочный модуль (без пропущенных частей). Получаем в итоге файл с расширением .exe (для Windows), либо .out (для Linux).
Загрузка. Следующий этап называется загрузка. Перед выполнением программа должна быть размещена в оперативной памяти компьютера. Это делается с помощью загрузчика, который забирает исполняемый загрузочный модуль с диска (наш файл с расширением .exe) и перемещает его в оперативную память.
Выполнение. И наконец, рассмотрим самый последний этап - выполнение. С этого момента компьютер под управлением своего ЦПУ (центральное процессорное устройство) начинает последовательно выполнять в каждый момент времени по одной команде программы. Эти моменты времени носят название такт, каждый процессор имеет свою тактовую частоту, которую задает его внутренний тактовый генератор. Чем более высокая частота работы вашего процессора, тем, соответственно, лучше и тем быстрее выполняются ваши программы. На маленьких программах это, конечно же, не очень ощутимо, но когда запускаете какую-нибудь новомодную игрушку, то все очень даже заметно.
Среда CodeBlocks
Для разработки своих программ лично я использую среду программирования CodeBlocks. Вам, как начинающим советую использовать именно ее, т.к. она проста в использовании и, соответственно, лучше приемлема для начинающего программиста. В этой среде есть минимально необходимый комплект (редактор, компилятор и отладчик) для разработки программ. А сейчас займемся установкой (скачать CodeBlocks можно в разделе "В помощь программисту"):
- Распаковываем скачанный архив и запускаем инсталляционный файл, соглашаемся с лицензией. В окошке выбора компонентов для установки выбираем либо standart, либо full (принципиальной разницы нет).
- Выбираем путь установки, либо оставляем по умолчанию, ставим.
- Процесс установки благополучно завершен.
Проект к данной лекции Вы можете скачать здесь.
Основной целью этого курса является изучение основ объектного стиля разработки программных проектов. Для программиста, владеющего этими основами, не столь важно, на каком конкретном языке программирования или в какой среде ему необходимо разработать тот или иной программный проект, - на любом языке он будет создавать программный продукт требуемого качества. Тем не менее, у каждого программиста есть свои предпочтения, свой любимый язык и среда разработки .
Международной ассоциацией по стандартизации эта версия языка узаконена как стандарт ISO/IEC - 23270. Заметим, что первая версия стандарта языка была принята еще в 2001 году. Компиляторы Microsoft строятся в соответствии с международными стандартами языка.
Из других важных факторов отметим следующие:
Введение в язык инструментария, характерного для функционального стиля программирования, - лямбда-выражений, анонимных типов и функций. Андреас Хейлсберг полагает, что смесь императивного и функционального стилей программирования упрощает задачи разработчиков, поскольку функциональный стиль позволяет разработчику сказать, что нужно делать, не уточняя, как это должно делаться.
Новые возможности появились при реализации параллелизма в программных проектах.
Параллельные вычисления в ближайшие 5-10 лет станут реальностью повседневной работы программиста. В этом направлении развивается техника. Языки программирования должны поддерживать эту тенденцию.
Visual Studio 2008
Как уже отмечалось, принципиальной новинкой этой версии является возможность построения новых типов программных проектов, что обеспечивается новой версией каркаса Framework . Net 3.5. Если не считать этой важной особенности, то идейно Visual Studio 2008 подобна предыдущим версиям Visual Studio 2005 и Visual Studio 2003.
Рассмотрим основные особенности среды разработки Visual Studio.
Открытость
Таких расширений среды Visual Studio сделано уже достаточно много, практически они существуют для всех известных языков - Fortran и Cobol, RPG и Component Pascal, Eiffel, Oberon и Smalltalk.
Новостью является то, что Microsoft не включила в Visual Studio 2008 поддержку языка Java. Допустимые в предыдущих версиях проекты на языке J++ в Visual Studio 2008 в настоящее время создавать нельзя, ранее созданные проекты в студии не открываются.
В каркасе Framework . Net можно выделить два основных компонента:
- статический - FCL (Framework Class Library) - библиотеку классов каркаса;
- динамический - CLR (Common Language Runtime) - общеязыковую исполнительную среду.
Библиотека классов FCL - статический компонент каркаса
Понятие каркаса приложений - Framework Applications - появилось достаточно давно, оно широко использовалось еще в четвертой версии Visual Studio. Библиотека классов MFC (Microsoft Foundation Classes) играла роль каркаса приложений Visual C++.
Несмотря на то, что каркас был представлен только статическим компонентом, уже тогда была очевидна его роль в построении приложений. Уже в то время важнейшее значение в библиотеке классов MFC имели классы, задающие архитектуру строящихся приложений. Когда разработчик выбирал один из возможных типов приложения, например, архитектуру Document-View, то в его приложение автоматически встраивались класс Document, задающий структуру документа, и класс View, задающий его визуальное представление. Класс Form и классы, задающие элементы управления, обеспечивали единый интерфейс приложений. Выбирая тип приложения, разработчик изначально получал нужную ему функциональность, поддерживаемую классами каркаса. Библиотека классов поддерживала и традиционные для программистов классы, задающие расширенную систему типов данных, в частности, динамические типы данных - списки, деревья, коллекции, шаблоны.
За прошедшие годы роль каркаса в построении приложений существенно возросла - прежде всего, за счет появления его динамического компонента, о котором чуть позже поговорим подробнее. Что же касается статического компонента - библиотеки классов, то здесь появился ряд важных нововведений.
Единство каркаса
Каркас стал единым для всех языков среды разработки. Поэтому на каком бы языке программирования не велась разработка, она работает с классами одной и той же библиотеки. Многие классы библиотеки, составляющие общее ядро, используются всеми языками. Отсюда единство интерфейса приложения, на каком бы языке оно не разрабатывалось, единство работы с коллекциями и другими контейнерами данных, единство связывания с различными хранилищами данных и прочая универсальность.
Встроенные примитивные типы
Структурные типы
Частью библиотеки стали не только простые встроенные типы, но и структурные типы, задающие организацию данных - строки, массивы; динамические типы данных - стеки, очереди, списки, деревья. Это также способствует унификации и реальному сближению языков программирования.
Архитектура приложений
Существенно расширился набор возможных архитектурных типов построения приложений. Помимо традиционных Windows- и консольных приложений, появилась возможность построения Web-приложений. Большое внимание уделяется возможности создания повторно используемых компонентов - разрешается строить библиотеки классов, библиотеки элементов управления и библиотеки Web-элементов управления. Популярным архитектурным типом являются Web-службы, ставшие сегодня благодаря открытому стандарту одним из основных видов повторно используемых компонентов.
Модульность
Число классов библиотеки FCL велико (несколько тысяч), поэтому понадобился способ их структуризации. Логически классы с близкой функциональностью объединяются в группы, называемые пространством имен (Namespace). Основным пространством имен библиотеки FCL является пространство System, содержащее как классы, так и другие вложенные пространства имен. Так, уже упоминавшийся примитивный тип Int32 непосредственно вложен в пространство имен System и его полное имя, включающее имя пространства, - System.Int32.
В пространство System вложен целый ряд других пространств имен. Например, в пространстве System.Collections находятся классы и интерфейсы, поддерживающие работу с коллекциями объектов - списками, очередями, словарями. В пространство System.Collections, в свою очередь, вложено пространство имен Specialized, содержащее классы со специализацией, например, коллекции, элементами которых являются только строки. Пространство System.Windows.Forms содержит классы, используемые при создании Windows-приложений. Класс Form из этого пространства задает форму - окно, заполняемое элементами управления, графикой, обеспечивающее интерактивное взаимодействие с пользователем.
По ходу курса мы будем знакомиться со многими классами библиотеки FCL .
Общеязыковая исполнительная среда CLR - динамический компонент каркаса
Двухэтапная компиляция. Управляемый модуль и управляемый код
Заметьте, PE-файл, имеющий уточнение exe, хотя и является exe-файлом, но это не обычный исполняемый Windows файл. При его запуске он распознается как PE-файл и передается CLR для обработки. Исполнительная среда начинает работать с кодом, в котором специфика исходного языка программирования исчезла. Код на IL начинает выполняться под управлением CLR (по этой причине код называется управляемым ). Исполнительную среду следует рассматривать как виртуальную IL-машину. Эта машина транслирует "на лету" требуемые для исполнения участки кода в команды реального процессора, который в действительности и выполняет код.
Виртуальная машина
Компилятор JIT, входящий в состав CLR, компилирует IL код с учетом особенностей текущей платформы. Благодаря этому создаются высокопроизводительные приложения. Следует отметить, что CLR, работая с IL кодом, выполняет достаточно эффективную оптимизацию и, что не менее важно, защиту кода. Зачастую нецелесообразно выполнять оптимизацию на уровне создания IL кода, она иногда может не улучшить, а ухудшить ситуацию, не давая CLR провести оптимизацию на нижнем уровне, где можно учесть особенности процессора.
Дизассемблер и ассемблер
В этом курсе к ассемблеру мы обращаться не будем, упоминаю о нем для полноты картины.
Читайте также: