О языках программирования
TL;DR: выборка из переписки об изучении нового языка программирования (ЯП).
Grigory, [16.12.20 21:01]
Любой ЯП определяется следующими своими свойствами:
- Сложность по Тьюрингу. Всё, что слабее машины Тьюринга, нас не интересует.
- Система типов (какие есть базовые типы, как делаются производные типы, какие проверки когда делаются)
- Система выделения ресурсов (какие есть классы хранения для переменных и констант, как определяется и кем контролируется время жизни объектов)
- Объём синтаксического сахара, который нужно зазубрить, чтобы считать себя профессионалом
- Как устроены принципы расширения и переиспользования функциональности
4.1 Объём и полезность стандартной библиотеки, поставляемой с языком
4.2 Кипучесть жизни сообщества, создающего и поддерживающего остальные библиотеки - Как язык работает с исключительными ситуациями
Примеры того, как некоторые ЯП ложатся на эту систему.
Ассемблер
- Удовлетворяет.
- Нетипизирован. Есть один тип данных — сырые числа.
- Все ресурсы управляются вручную, или же описаны в ABI (то есть вне языка)
- Относительно небольшой. В лучшем случае есть: секции, макросы, комментарии, псевдотипы данных
- Не определяются языком, в лучшем случае тулчейном для него.
4.1 В лучшем случае доступно то, что есть в API/ABI операционной системы или через сервисы EFI/BIOS.
4.2 Обычно только то, что сам написал. С другой стороны, если уж пишешь на ассемблере, то умей подключать либы, написанные на других ЯП. - Язык обычно не определяет механизмов для обработки ошибок. Эти механизмы прописаны в ABI и/или в архитектуре ЦПУ.
С++
- Удовлетворяет
- Традиционные скалярные примитивные типы в наличии. Статически и динамически типизирован.
- Есть следующие классы: константы, автоматические переменные, динамические переменные. Управление ресурсами ручное.
- Просто дохуя сахара, и его только прибавляется.
- Удивительным образом, до сих пор не определён в языке. Всем понятно, что это ЁБАНЫЙ СТЫД в 2020 году.
4.1 Хороший объём и полезность. STL решает много проблем
4.2 Большое сообщество. Однако см. пункт о библиотеках, что портит жизнь значительно. - Механизм исключений (опциональный)
Язык Markdown
- Не Тьюринг-полный. Это же язык разметки
Питон
- Удовлетворяет
- Базовые скалярные и контейнерные типы в наличии. Динамически типизирован. В версии 3.9 появились необязательные аннотации статических типов.
- Один класс хранения — динамически аллоцируемые данные. Автоматическая сборка мусора.
- Приемлемое количество сахара. Его объём медленно растёт.
- Изящная система модулей. Не без косяков.
4.1 Принцип Питона — batteries are included. В стандартной либе есть очень много полезного.
4.2 Современная система пакетов и систем для управления ими. - Механизм бросания/перехвата исключений.
Java
- Удовлетворяет
- То же самое, что С++ и Питон.
- Примерно как Питон. Автоматическая сборка мусора.
- Адекватное количество сахара.
- Нормальные модули, стандартная либа и сообщество.
- Механизм бросания/перехвата исключений.
Исключения из нормы
- Язык Lua — в системе типов нет целых, только с плавающей запятой. Очень неудобно для некоторых доменов применения.
- Язык Perl — объём сахара просто зашкаливает и, наверное, побивает в этом С++.
Зачем всё это
Почему это важно?
Новички в каждом языке много времени тратят на пункт 3 (синтаксис). На практике же достаточно изучить подмножество, достаточное для написания Тьюринг-полных программ (т.е. знать как сделать цикл), а остальное учить по пути.
Классы хранения могут стать непреодолимой преградой для довольно большого числа людей. Известно, что только доля населения Земли в состоянии освоить концепцию “указатель на переменную”. В этом плане языки с управляемой памятью являются для них единственным выходом.
После освоения ядра языка всё остальное время проводится в поиске и переиспользовании уже написанного кода. Поэтому пункт 4 важнее всех остальных вместе взятых.
Для очень хорошей коллекции библиотек часто проще написать новый язык, который её использует, чем учить оригинальный, на котором эти библиотеки были написаны.
Примеры: для JVM есть несколько языков, которые все используют общие либы https://en.wikipedia.org/wiki/List_of_JVM_languages. То же самое для .NET: https://en.wikipedia.org/wiki/List_of_CLI_languages
То есть например можно реально забить на весь сахар языка С# и писать на любимом тебе Бэйсике, и всем от этого будет нормально.
Успех ЯП в 21 веке определяется объёмом библиотек, доступных для него, и интероперабильностью его с другими языками.
Классы хранения?
Пример из С++:
enum {
i_am_literal = 1234
};
static int v1 = 0;
static const char *str = "hello";
void main()
{
char auto_var = 56;
double *p_d = new(double);
}
В этом примере i_am_literal
— литерал, v1
и str
— статические, имеют время жизни, равное времени жизни программы. Затем, auto_var
— автоматическая переменная, живёт, пока не закончится окружающий её блок {}
.
Наконец, *p_d
— динамическая переменная. Время жизни данных, на которые указывает *p_d
, определяется программистом. Если он не позовёт delete()
, то память утечёт.
В Питоне, Джаве и других языках все переменные одного класса хранения. Занятая ими память освобождается без прямого контроля со стороны программиста. В таких языках нет указателей. В таких языках все переменные — это ссылки. Есть исключения, конечно, но сейчас не о них.
[Я упрощаю про Джаву, но для Питона это верно]
Ещё проще
Если ещё проще, то изучение нового ЯП для меня — это понимание, как в нём делаются следующие вещи:
- Декомпозиция
- Абстракция
- Работа со скучными проблемами
Пункты 1 и 2 влияют на то, как решать сложные задачи, а 3 — как не сойти с ума от ежедневной рутины.