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

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

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

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

Низкоуровневый язык программирования (язык программирования низкого уровня) - язык программирования, близкий к программированию непосредственно в машинных кодах используемого реального или виртуального (например, Java, Microsoft .NET) процессора. Для обозначения машинных команд обычно применяется мнемоническое обозначение. Это позволяет запоминать команды не в виде последовательности двоичных нулей и единиц, а в виде осмысленных сокращений слов человеческого языка (обычно английских).

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

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

Рис.1. Пример машинного кода и представления его на ассемблере

Трансляторы делятся на:

    компиляторы - превращают текст программы в машинный код, который можно сохранить и затем использовать уже без компилятора (примером являются исполняемые файлы с расширением *. exe);

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

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

Преимущества

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

Недостатки

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

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

    значительное время разработки больших и сложных программ.

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

Ассемблер - язык низкого уровня, что широко применяется до сих пор.

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

Первым языком программирования высокого уровня считается компьютерный язык Plankalkül, разработанный немецким инженером Конрадом Цузе ещё в период 1942-1946 годах. Однако транслятора для него не существовало до 2000 г. Первым в мире транслятором языка высокого уровня является ПП (Программирующая Программа), он же ПП-1, успешно испытанный в 1954 г. Транслятор ПП-2 (1955 г., 4-й в мире транслятор) уже был оптимизирующим и содержал собственный загрузчик и отладчик, библиотеку стандартных процедур, а транслятор ПП для ЭВМ Стрела-4 уже содержал и компоновщик (linker) из модулей. Однако, широкое применение высокоуровневых языков началось с возникновением Фортрана и созданием компилятора для этого языка (1957).

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

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

Примеры: C, C++,C#, Java, Python, PHP, Ruby, Perl, Паскаль, Delphi, Lisp . Языкам высокого уровня свойственно умение работать с комплексными структурами данных. В большинстве из них интегрирована поддержка строковых типов, объектов, операций файлового ввода-вывода и т. п.Недостатком языков высокого уровня является больший размер программ по сравнению с программами на языке низкого уровня. Поэтому в основном языки высокого уровня используются для разработок программного обеспечения компьютеров и устройств, которые имеют большой объем памяти. А разные подвиды ассемблера применяются для программирования других устройств, где критичным является размер программы.

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

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

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

Набоp действий, котоpые могут выполняться внутpи функции очень огpаничен. Он состоит из вычисления фоpмульных выpажений, вызовов дpугих функций (что не является отдельным действием - вызов функции часто входит в выpажение), присваиваний, ветвлений (гpуппа действий, котоpая выполняется лишь при истинности некоторого условия) и циклов (гpуппа действий, выполняемых многокpатно, число повтоpений зависит от некотоpого условия). Действия могут быть вложены дpуг в дpуга. Может показаться, что набоp из ветвлений и циклов слишком мал, но это не так. Доказано, что любой алгоpитм, составленный из функциональных блоков (на низком уpовне - арифметических команд и команд пеpесылки данных), условных и безусловных пеpеходов может быть пpеобpазован в эквивалентный алгоpитм, составленный только из стpуктуpных блоков - функциональных блоков, ветвлений и циклов с пpовеpкой условия в конце. Это утвеpжение было сфоpмулиpовано в статье Бома и Джакопини (Corrado Bohm and Giuseppe Jacopini) "Flow diagrams, turing mashines and languages with only two formation rules" (Communications of ACM, Volume 9 / Number 5 / May, 1965).

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

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

Обычно языки пpогpаммиpования пpедоставляют достаточно огpаниченный набоp пpедопpеделенных типов пеpеменных и сpедства создания новых типов. Пpедопpеделены некотоpые из следующих типов:

    натуpальные и целые числа pазличной pазpядности;

    вещественные числа;

    символы - буквы, цифpы, знаки аpифметических действий и пp.;

    стpоки символов;

    логические значения;

    указатели

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

В языке C, напpимеp, не опpеделены символы, строки и логические значения. Его тип char на самом деле является коpотким целым и допускает аpифметические действия.

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

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

Есть и другие способы создания новых типов. Например, в языке Pascal возможно создание:

    типов-диапазонов (посредством задания диапазона значений);

    типов-перечислений (посредством перечисления возможных значений);

    типов-множеств

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

Какие бывают языки программирования? Что за концепции в них заложены? Как они развивались? В данной статье рассмотрим виды языков программирования основываясь на так называемых уровнях - от машинных кодов (низкий уровень, приближённый к компьютерному "железу") до таких языков, как Java или С# (высокий уровень). Чем меньше преобразований пройдёт текстовый листинг программы по пути превращения в набор нулей и единичек – тем ниже уровень. Далее мы рассмотрим:
  1. Языки низкого уровня (машинные коды и ассемблер)
  2. Средний уровень (C, Фортран ….)
  3. Высокий уровень (C++, Java, Python, Ruby, JavaScript ...)
Уровень также характеризует насколько подробно нужно детализировать листинг будущей программы для воплощения реализации. Насколько этот процесс прост для человека. Не стоит считать уровень языка однозначным показателем его возможностей. Язык программирования – это инструмент, который эффективен в одной области и менее полезен в других. И столяр, и плотник работают с деревом. У первого основной инструмент – набор стамесок, у второго – топор. Однако резной шкаф изящнее сделает столяр, а дом быстрее поставит плотник. Хотя каждый и способен выполнить работу другого, но сделает это гораздо менее эффективно. Различные данные в компьютере представлены в виде наборов нулей и единиц. Управляющие команды для её обработки – те же данные, содержащие внутри себя инструкции, которые определяют местоположение необходимой информации и способ модификации.

Машинные языки (Самый низкий уровень)

Нам придётся совершить краткий визит из Software области в Hardware. Рассмотрим в упрощенном виде. Процессор – основной «мозг» компьютера. Материнская плата, на которой он установлен, содержит контроллеры, служащие для взаимодействия с прочими устройствами через шины (каналы данных для связи).

Некоторые работают с большой скоростью (красные стрелки): процессор черпает из памяти команды и манипулирует данными, видеокарта – особенно в 3D играх, потребляет огромные объёмы текстур, фигур, координат пикселей и прочих объектов для построения изображения на экране монитора. Другим (в силу ограничения скорости обмена информацией) столь высокие показатели и не нужны. Разнообразные внутренние и внешние устройства подключены на схеме зелёными стрелками.

Внутренний мир процессора

Все команды процессора поступают из памяти на выполнение в двоичном виде. Формат, количество, подмножество инструкций зависят от его архитектуры. Большинство из них несовместимо друг с другом и следуют разным идеологиям. А также вид команды сильно зависит от режима (8/16/32… разрядность) и источника данных (память, регистр, стек…), с которыми работает процессор. Одно и то же действие может быть представлено различными инструкциями. Процессор имеет команды сложения двух операндов (ADD X,Y) и прибавления единицы к указанному (INC X). Добавление тройки к операнду можно выполнить как ADD X,3 или троекратно вызвав INC X. И, в отношении разных процессоров, нельзя предсказать какой из этих способов будет оптимальным по скорости или объёму занимаемой памяти. Для удобства двоичную информацию записывают в 16-ричном виде. Рассмотрим часть привычной программы (язык C, синтаксис которого сходный с Java) int func () { int i = getData ("7" ) ; return ++ i; . . . } Код, реализующий те же действия в виде последовательности инструкций для процессора: ... 48 83 ec 08 bf bc 05 20 00 31 c0 e8 e8 fe ff ff 48 83 c4 08 83 c0 01 ... Вот так, собственно и выглядит низкоуровневый язык программирования для процессора intel. Фрагмент, вызывающий метод с аргументом и возвращающий увеличенный на единицу результат. Это и есть машинный язык (код), который передается непосредственно сразу, без преобразований, на исполнение процессору. Плюсы:
  • Мы полностью хозяева положения, имеем самые широкие возможности использования процессора и аппаратуры компьютера.
  • Для нас доступны все варианты организации и оптимизации кода.
Минусы:
  • Необходимо обладать обширными знаниями по функционированию процессоров и учитывать большое количество аппаратных факторов при выполнении кода.
  • Создание программ чуть более сложных чем приведенный пример приводит к резким увеличениям затрат времени по написанию кода и его отладку.
  • Платформозависимость: программа, созданная для одного процессора, как правило, не будет функционировать на других. Возможно, и для данного процессора, в остальных режимах его работы, потребуется редактирование кода.
Машинные коды широко использовались на заре появления компьютеров, других способов программирования в эпоху пионеров ЭВМ не было. В данное время ими изредка пользуются инженера в области микроэлектроники при разработке или низкоуровневом тестировании процессоров.

Язык ассемблера (низкий уровень)

В отличие от компьютера мы с вами лучше воспринимаем информацию в текстовом/смысловом, а не цифровом виде. Вы с легкостью назовете полсотни имён контактов в вашем смартфоне, но вряд ли сможете наизусть написать соответствующие им номера телефонов. Аналогично и с программированием. На лестнице типов мы поднимемся выше, сделав три основных шага:
  • Сопоставим группам цифровых инструкций процессора, выполняющих соответствующие действия, одну символьную команду.
  • Выделим аргументы инструкций процессора отдельно.
  • Введем возможность именовать области памяти, переменные, местоположение отдельных команд.
Сравним фрагменты прошлой программы в машинных кодах (по центру) и на языке ассемблера (справа): 2004 b0 48 83 ec 08 sub $0x8 , % rsp 2004 b4 bf bc 05 20 00 mov $0x2005bc , % edi 2004 b9 31 c0 xor % eax, % eax 2004 bb e8 e8 fe ff ff callq getData 2004 c0 48 83 c4 08 add $0x8 , % rsp 2004 c4 83 c0 01 add $0x1 , % eax Как видим, процесс написания программы упростился: нет необходимости пользоваться справочниками формирования цифровых значений команд, рассчитывать длины переходов, распределение данных в памяти по её ячейкам и иные особенности процессора. Мы описываем нужное действие из набора символьных команд и необходимых для логики из выполнения аргументов, а далее программа-транслятор переводит текстовый файл на понятный процессору набор нулей и единиц. Плюсы:
  • Процесс написания и модификации кода упростился.
  • Сохранился контроль ко всем ресурсам аппаратуры.
  • Относительно легче переносить программу на другие платформы, но требуется их модификация в зависимости от аппаратной совместимости.
Минусы:
  • Ассемблер относится к низкоуровневым языкам программирования. Создание даже небольших участков кода затруднено. К тому же также необходимо учитывать специфику работы аппаратуры.
  • Платформозависимость.
Самый популярный демонстрационный Java пример: public static void main (String args) { System. out. println ("Hello World!" ) ; } будет выглядеть (NASM синтаксис, с использованием Windows API и kernel32.lib) следующим образом: global _main extern _GetStdHandle@4 extern _WriteFile@20 extern _ExitProcess@4 section . text _main: ; DWORD bytes; mov ebp, esp sub esp, 4 ; hStdOut = GetstdHandle ( STD_OUTPUT_HANDLE) push - 11 call _GetStdHandle@4 mov ebx, eax ; WriteFile ( hstdOut, message, length (message) , & bytes, 0 ) ; push 0 lea eax, [ ebp- 4 ] push eax push (message_end - message) push message push ebx call _WriteFile@20 ; ExitProcess (0 ) push 0 call _ExitProcess@4 ; never here hlt message: db "Hello, World" , 10 message_end: Как и машинные коды, ассемблер чаще используется инженерами и системными программистами. На нём пишут аппаратно-зависимые части ядра операционных систем, критические по времени или особенностям реализации драйвера различных периферийных устройств. Но в последнее время к нему прибегают всё реже и реже, так как его применение сильно сужает переносимость программ на другие платформы. Иногда используют процесс дизассемблирования – создают ассемблерный листинг программы из цифровых кодов для разбора логики выполнения небольших фрагментов. В редких случаях, если первоначальный высокоуровневый код недоступен: анализ вирусов для борьбы с ними или потере исходного текста. Язык ассемблера причисляют к первому/второму поколению (мы не будем рассматривать отдельно псевдокоды до возникновения ассемблера и их отличие от символьных команд). Хотелось бы выделить использование ассемблера в Demo Scene (демо-сцена): сплав искусства, математики и низкоуровневого кодирования, воплощающие художественные замыслы своих создателей в виде программ, генерирующих видеоклипы при ограничениях в ресурсах. Часто общий размер файла программы и данных не должен превышать 256 байт (также популярен и формат в 4/64 килобайта). Вот пример 4 Кб программы:

Языки группы C/Фортран (средний/высокий уровень)

С развитием возможностей вычислительной техники объём функциональности и сроки реализации кода на ассемблере уже не устраивали. Затраты для написания, тестирования и сопровождения программ росли на порядок быстрее их возможностей. Необходимо было снизить требования от программиста в плане знаний функционирования аппаратуры, дать ему инструмент, позволяющий писать на языках, приближенных к человеческой логике. Перейти к новому уровню типов языков программирования. Предоставить возможность разбивать на разнообразные модули с дальнейшим последовательным вызовом (парадигма процедурного программирования), предоставить различные типы данных с возможностью их конструирования и т. п. Дополнительно эти меры привнесли улучшенную переносимость кода на другие платформы, более комфортную организацию командной работы. Одним из первых языков, поддерживающий всё вышеперечисленное был разработанный в 50-е годы прошлого века Фортран . Возможность создавать в текстовом виде с описанием логики выполнения используя циклы, ветвления, подпрограммы и оперируя массивами и представляя данные в виде вещественных, целых и комплексных чисел приводила инженеров и учёных в восторг. За короткое время были созданы научные «фреймворки» и библиотеки. Всё это и стало следствием того, что Фортран и поныне имеет актуальность, пусть и в узкой научной среде, и развивается, так как багаж наработок очень велик, одна только библиотека IMSL активно развивается с 1970 (!) года, много ли вспомните подобных актуальных software-старожилов? Другая ветка развития языков этого уровня – C . Если Фортран стал инструментом учёных, то C создавался в помощь программистам, создающим прикладное ПО: операционные системы, драйвера и т. д. Язык позволяет вручную управлять распределением памяти, даёт прямой доступ к аппаратным ресурсам. C-программистам приходится контролировать низкоуровневые сущности, поэтому многие придерживаются мнения, что язык C – усовершенствованный ассемблер и его часто называют языком «среднего» уровня. Привнеся в ассемблер типизацию данных, элементы процедурного и модульного программирования язык C и сегодня является одним из основных для системного программирования, чему также способствует и бурное развитие микроэлектроники в последнее время. Всевозможные гаджеты, контроллеры, сетевые и прочие устройства нуждаются в драйверах, реализации протоколов для совместной работы и прочем относительно низкоуровневом ПО для реализации взаимодействия с аппаратурой. Все вышеперечисленное способствует востребованности языка и в настоящее время. Объектно-ориентированные и функциональные принципы получили дальнейшее развитие в виде C++, C#, Java, взяв многое от синтаксиса C. Плюсы:
  • Упрощение процесса создания кода: введение типов, разбивка на модули, сокращение листинга программ.
  • Прозрачная логика заложенного алгоритма вследствие ухода от машинных кодов к более понятным для человека командам в семантически описательном стиле.
  • Переносимость. Стало достаточно перекомпилировать текст программы для выполнения на другой платформе (возможно, с небольшой модификацией).
  • Скорость откомпилированных программ.
Минусы:
  • Отсутствие автоматического управления памятью и необходимость постоянного её контроля.
  • Отсутствие реализации концепций объектно-ориентированного и функционального программирования.

Развитие языков высокого уровня

Высокоуровневые языки программирования, в плане создания ПО, стали всё по большей части удаляться от машинных кодов и реализовывать различные, помимо процедурного, парадигм программирования. К ним относят также и реализацию объектно-ориентированных принципов. C++, Java, Python, JavaScript, Ruby… – спектр языков данного типа наиболее популярен и востребован сегодня. Они предоставляют больше возможностей для реализации разнообразного ПО и нельзя однозначно определить «специализацию» каждого из них. Но популярность применения в соответствующих областях обусловлена библиотеками/фреймворками для работы с ними, например: JavaScript – Frontend. Язык был разработан для взаимодействия клиентского веб-браузера с пользователем и удалённым сервером. Наиболее популярные библиотеки: Angular, React и VUE. В данное время относительно активно употребляется и на web и т. п. серверах (backend), особенно популярен Node.js. Ruby – Backend. Применяется для создания скриптов (служебных сервисных файлов) и на web серверах. Основной фреймворк - Ruby On Rails. Python – научная и инженерная сфера (помимо веб-области). Является альтернативой стандартным вычислительным и математическим пакетам (Mathematica, Octave, MatLab…), но имеет привычную семантику языка и большое число библиотек. Имеет много поклонников в области систем машинного обучения, статистики и искусственного интеллекта. Из часто используемых библиотек необходимо упомянуть django, numpy, pandas, tensorflow. С++ – Универсал, эволюционное развитие языка C. Предоставляет возможности функционального и объектно-ориентированного программирования и не потеряв при этом способность низкоуровневого взаимодействия с аппаратным обеспечением. За счёт чего реализуется производительность и гибкость при создании ПО, но и цена соответствует: высокий порог вхождения за счёт сложной спецификации языка, необходимости самостоятельного контроля за ресурсами при выполнении программы. Многие однопользовательское и системное ПО написано с его применением: модули операционных систем (Windows, Symbian…), игры, редакторы (Adobe Photoshop, Autodesk Maya…), базы данных (MSSQL, Oracle…), проигрыватели (WinAmp…) и т. д. Следует отметить, что современное ПО является сложным продуктом, в разработке которого используется сразу несколько языков программирования и расставлять степень участия каждого из них в общий результат бывает весьма затруднительно.

Дальнейший прогресс

В последнее время набирает популярность и иной вид программирования - функциональное (дальнейшее развитие уровня языка) . Здесь уже другой вид абстракции для вычислений – функции, которые берут в качестве аргументов набор функций и возвращают другую. Роль переменных играют те же функции (привычные нам переменные – просто константные выражения, аналогичные final перед объявлением типа в Java). Собственно функция замкнута в своей области видимости, результат её работы зависит только от переданных аргументов. Отсюда вытекают два замечательных свойства:
  • Для тестирования нам необходимы только аргументы функций (результат работы не зависит от внешних переменных и т. п.).
  • Программа в функциональном стиле чудесным образом готова к параллельной работе: последовательные вызовы функций можно пускать в соседних потоках (так как на них не действуют внешние факторы) и им не нужны блокировки (то есть, проблемы синхронизации отсутствуют). Хороший стимул уделить время этой теме, учитывая повальное распространение многоядерных процессоров.
Однако и порог вхождения выше, чем для ООП: для эффективного кода необходимо строить программу, описывая в виде функций алгоритм выполнения. Но также для чистого функционального стиля неплохо бы знать азы логики и теории категорий. Наиболее популярные – Haskell, Scala, F#. Но не бойтесь, в Java (как и в других современных языках третьего поколения) появились элементы функционального программирования и их возможно комбинировать вместе с ООП. Более подробно вы познакомитесь со всеми этими подробностями на онлайн-стажировке JavaRush. Область логического программирования (следующий уровень языков) пока не нашла широкого практического применения в силу малой востребованности. Построение программ требует знание основ дискретной математики, логики предикатов, средств ограничений и других разделов математической логики. Наиболее популярный активный язык – Prolog.

Заключение

В настоящее время самые распространённые – языки ООП. Java, с момента возникновения, всегда находится в топе, обычно в тройке, востребованных языков. Помимо ООП, содержит элементы функционального программирования, и вы можете комбинировать разные стили составления ваших программ. Спектр применения Java весьма широк – это бизнес задачи, реализация веб-серверов (backend), основной язык создания Android-приложений, кроссплатформенные среды программирования и рабочих мест (IDE/АРМ) и моделирования и многое другое. Особенно сильны позиции Java в Enterprise секторе – области корпоративного программного обеспечения, которая требует качественный и долгоживущий код, реализацию самых сложных бизнес-логик.

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

И всё же возникновение новых языков - явление довольно частое. Некоторые из них создаются студентами или любителями в качестве индивидуальных проектов, другие являются продуктами крупных производителей программного обеспечения . Даже небольшие и средние компании принимают участие в этом процессе, создавая языки для нужд своих отраслей. Так почему же люди продолжают изобретать велосипед снова и снова?

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

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

JavaScript хорош для добавления базовых элементов интерактивности веб-страницам, но когда код ваших веб-приложений состоит из тысяч строк, слабые места этого языка становятся заметны. Вот почему Google создала Dart - язык, который, как полагает компания, станет новым "родным" языком веб-программирования .

Как и в JavaScript, в Dart используются синтаксисы и ключевые слова, похожие на те, которые используются в языке C. Однако одним существенным различием является то, что в то время как JavaScript основывается на прототипах, объекты в Dart определяются с помощью классов и интерфейсов, как в C++ или Java . Также Dart позволяет программистам дополнительно задавать переменные со статическими типами. Идея заключается в том, чтобы сделать Dart таким же привычным, динамичным и гибким языком, как и JavaScript, который в то же время позволяет разработчикам писать коды, быстрые и лёгкие в выполнении, и в которых сложно сделать труднонаходимые ошибки.

Сегодня Dart мало где можно использовать. Он разработан для запуска либо на клиенте, либо на сервере (а-ля Node.js), но единственным способом запустить клиентскую версию Dart-кода является его кросскомпиляция в JavaScript. Однако и после этого он не будет запускаться во всех браузерах. Но так как Dart выпускается по бесплатной лицензии типа BSD , то любой продавец, который согласен с условиями Google, может свободно использовать этот язык в своих продуктах. Всё, что осталось сделать Google, - это убедить всю индустрию.

Код F# чем-то похож на код OCaml, но содержит свой собственный интересный синтаксис. Например, для облегчения проведения научных расчётов числовыми типами данных в F# могут являться единицы измерения. Также в F# имеются конструкции для облегчения асинхронных вводов/выводов, параллелизации ЦПУ и вывода процессов на графический процессор.

После длительного периода созревания в Microsoft Research, на сегодняшний день F# поставляется вместе с Visual Studio 2010 . Что ещё лучше, но не характерно для корпорации, Microsoft создала F# компилятор и корневую библиотеку, доступную по открытой лицензии Apache. Вы можете начать работу с ним бесплатно и даже использовать его на системах Mac и Linux (с помощью Mono runtime).

Естественно, с такого рода интегрированной системой в конце должно получиться что-то волшебное. Среда выполнения Opa объединяет собственный веб-сервер и систему управления базой данных , которые не могут быть заменены самостоятельными альтернативами. Как бы то ни было, это может быть не так уж и важно, учитывая возможность разработки современных веб-приложений , управляемых данными, с помощью всего лишь нескольких десятков строк кода. Opa поставляется бесплатно и на данный момент доступен для 64-х битных Linux и Mac OS X платформ, другие же порты пока разрабатываются.

Fantom распространяется бесплатно в соответствии с Academic Free License 3.0 и доступен для Windows и Unix-подобных платформ (в том числе и Mac OS X).

Исследуемый язык программирования №7: Zimbu

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

Единственной проблемой является портативность. Хотя Zimbu и является компилируемым языком, его компилятор выдаёт ANSI C код, а двоичные файлы могут быть созданы лишь на платформах со встроенным C-компилятором.

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

Исследуемый язык программирования №8: X10

Когда-то параллельная обработка данных была специализированной нишей разработки ПО, но с распространением многоядерных процессоров и распределённых вычислений, параллелизм обрёл популярность. К сожалению, нынешние языки программирования не успевают за этой тенденцией. Именно поэтому IBM Research создаёт X10 - язык, созданный специально для современных параллельных архитектур, который нацелен на увеличение производительности разработчиков "в десять раз".

Параллелизм в X10 возможен благодаря PGAS модели программирования (модели разделённого глобального адресного пространства). Код и данные выделяются в блоки и распределяются по разным "пространствам", тем самым облегчая шкалирование программы от однопотокового прототипа (одно пространство) до многопотокового, выполняемого на одном или более многоядерном процессоре (несколько пространств) в высокопроизводительном кластере .

Код X10 больше всего похож на Java. По сути, среда выполнения X10 доступна как в качестве встроенных исполнимых файлов , так и как классовые файлы для JVM. Компилятор X10 может выдавать исходные коды либо на C++, либо на Java. В будущем планируется разработать прямую совместимость с Java.

А пока язык развивается, хотя он уже довольно разработан. Компилятор и среда выполнения доступны для различных платформ, в том числе Linux, Mac OS X и Windows. В качестве дополнительных утилит выступают интерактивная среда разработки (IDE), основанная на Eclipse, и отладчик, которые распространяются по лицензии Eclipse Public License.

Исследуемый язык программирования №9: haXe

Многие языки можно использовать для написания переносимого кода. C-компиляторы доступны практически для всех ЦПУ архитектур, а Java-байткод будет выполняться везде, где есть JVM. Но haXe (произносится как "хекс") является более чем просто переносимым. Это мультиплатформенный язык, который может использоваться в различных операционных средах, начиная от встроенных

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

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

Первый машинный язык был придуман в 1941 году Конрадом Цузе, который является изобретателем аналитической машины. Чуть позже, в 1943 г., Говард Эйкен создал машину "Марк-1", способную считывать инструкцию на уровне машинного кода.

В 1950-х годах начался активный спрос на разработку программного обеспечения, а машинный язык не выдерживал большие объемы кода, поэтому был создан новый способ общения с компьютерами. "Ассемблер" является первым мнемоническим языком, заменившим машинные команды. С годами список языков программирования только увеличивается, ведь область применения компьютерных технологий становится обширнее.

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

На данный момент существует более 300 языков программирования. Каждый из них имеет свои особенности и подходит для одной определенной задачи. Все языки программирования можно условно разделить на несколько групп:

  • Аспектно-ориентированные (основная идея - разделение функциональности для увеличения эффективности программных модулей).
  • Структурные (в основе лежит идея создания иерархической структуры отдельных блоков программы).
  • Логические (в основе лежит теория аппарата математической логики и правил резолюции).
  • Объектно-ориентированные (в таком программировании используются уже не алгоритмы, а объекты, которые принадлежат определенному классу).
  • Мультипарадигмальные (сочетают в себе несколько парадигм, и программист сам решает, каким языком воспользоваться в том или ином случае).
  • Функциональные (в качестве основных элементов выступают функции, которые меняют значение в зависимости от результатов вычислений исходных данных).

Программирование для начинающих

Многие задаются вопросом, что же такое программирование? По сути, это способ общения с компьютером. Благодаря языкам программирования мы можем ставить перед различными устройствами определенные задачи, создавая специальные приложения или программы. При изучении данной науки на начальном этапе самое главное - это выбрать подходящие (интересные для вас) языки программирования. Список для начинающих приведен ниже:

  • Basic придуман в 1964 году, относится к семейству высокоуровневых языков и используется для написания прикладных программ.
  • Python ("Питон") довольно легко выучить благодаря простому читаемому синтаксису, преимущество же в том, что на нем можно создавать как обычные десктопные программы, так и веб-приложения.
  • Pascal ("Паскаль") - один из древнейших языков (1969 г.), созданных для обучения студентов. Его современная модификация имеет строгую типизацию и структурированность, однако "Паскаль" - вполне логичный язык, который понятен на интуитивном уровне.

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

Новички имеют возможность ускорить изучение программирования и его основ благодаря специальным инструментам. Основной помощник - это интегрированная среда разработки программ и приложений Visual Basic («Визуал Бейсик» одновременно является и языком программирования, который унаследовал стиль языка Basic 1970-х годов).

Уровни языков программирования

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

Низкоуровневые языки предназначены для создания машинных команд для процессоров. Главное их преимущество в том, что они используют мнемонические обозначения, т. е. вместо последовательности нулей и единиц (из двоичной системы счисления) компьютер запоминает осмысленное сокращенное слово из английского языка. Самые известные языки низкого уровня - это "Ассемблер" (существует несколько подвидов этого языка, каждый из которых имеет много общего, а отличается лишь набором дополнительных директив и макросов), CIL (доступен в платформе.Net) и Байт-код JAVA.

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

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

Следующий список языков программирования: C ("Си"), C# ("Си-шарп"), "Фортран", "Паскаль", Java ("Ява") - входит в число самых используемых высокоуровневых синтаксисов. Он обладает следующими свойствами: эти языки работают с комплексными структурами, поддерживают строковые типы данных и операции с файлами ввода-вывода информации, а также имеют преимущество - с ними гораздо проще работать благодаря читабельности и понятному синтаксису.

Самые используемые языки программирования

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

  • языки ООП: Java, C++, Python, PHP, VisualBasic и JavaScript;
  • группа структурных языков: Basic, Fortran и Pascal;
  • мультипарадигмальные: C#, Delphi, Curry и Scala.

Область применения программ и приложений

Выбор языка, на котором написана та или иная программа, во многом зависит от области ее применения. Так, например, для работы с самим "железом" компьютера (написания драйверов и поддерживающих программ) лучшим вариантом станет C ("Си") или С++, которые входят в основные языки программирования (список смотрите выше). А для разработки мобильных приложений, в том числе игр, следует выбрать Java или С# ("Си-шарп").

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

Рассказывает программист Вильям В. Вольд

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

Введение

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

Тем не менее, я написал абсолютно новый язык. И он работает. Наверное, я что-то делаю правильно.

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

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

Первые шаги

«А с чего вообще начинать?» - вопрос, который другие разработчики часто задают, узнав, что я пишу свой язык. В этой части постараюсь подробно на него ответить.

Компилируемый или интерпретируемый?

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

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

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

Прим. перев. Кстати, у нас есть краткий обзор - это отличное упражнение для тех, кто изучает Python.

Выбор языка

Своеобразный мета-шаг: язык программирования сам является программой, которую надо написать на каком-то языке. Я выбрал C++ из-за производительности, большого набора функциональных возможностей, и просто потому что он мне нравится.

Но в целом совет можно дать такой:

  • интерпретируемый ЯП крайне рекомендуется писать на компилируемом ЯП (C, C++, Swift). Иначе потери производительности будут расти как снежный ком, пока мета-интерпретатор интерпретирует ваш интерпретатор;
  • компилируемый ЯП можно писать на интерпретируемом ЯП (Python, JS). Возрастёт время компиляции, но не время выполнения программы.

Проектирование архитектуры

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

Лексический анализатор / лексер

Строка исходного кода проходит через лексер и превращается в список токенов.

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

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

Flex

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

Одним из основных таких инструментов является Flex - генератор лексических анализаторов. Он принимает на вход файл с описанием грамматики языка, а потом создаёт программу на C, которая в свою очередь анализирует строку и выдаёт нужный результат.

Моё решение

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

Синтаксический анализатор / парсер

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

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

Bison

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

Преимущества кастомных программ

С лексером моё решение писать и использовать свой код (длиной около 200 строк) было довольно очевидным: я люблю задачки, а эта к тому же относительно тривиальная. С парсером другая история: сейчас длина кода для него - 750 строк, и это уже третья попытка (первые две были просто ужасны).

Тем не менее, я решил делать парсер сам. Вот основные причины:

  • минимизация переключения контекста ;
  • упрощение сборки;
  • желание справиться с задачей самостоятельно.

В целесообразности решения меня убедило высказывание Уолтера Брайта (создателя языка D) в одной из его статей :

Я бы не советовал использовать генераторы лексических и синтаксических анализаторов, а также другие так называемые «компиляторы компиляторов». Написание лексера и парсера не займёт много времени, а использование генератора накрепко привяжет вас к нему в дальнейшей работе (что имеет значение при портировании компилятора на новую платформу). Кроме того, генераторы отличаются выдачей не релевантных сообщений об ошибках.

Абстрактный семантический граф

Переход от синтаксического дерева к семантическому графу

В этой части я реализовал структуру, по своей сути наиболее близкую к «промежуточному представлению» (intermediate representation) в LLVM. Существует небольшая, но важная разница между абстрактным синтаксическим деревом (АСД) и абстрактным семантическим графом (АСГ).

АСГ vs АСД

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

Запуск

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

Варианты компиляции

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

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

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




Top