-
Notifications
You must be signed in to change notification settings - Fork 152
/
why_zig_rust_d_cpp.ru.md
114 lines (80 loc) · 17.1 KB
/
why_zig_rust_d_cpp.ru.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
---
title: "Зачем нужен Zig, если уже есть C++, D и Rust?"
mobile_menu_title: "Зачем нужен Zig, если уже есть..."
toc: true
---
## Без скрытых потоков управления
Если код на Zig не выглядит как вызов какой—то функции, тогда так оно и есть. Это значит, что вы можете быть уверены, что данный код вызывает только `foo()` и затем `bar()`, и это гарантировано независимо от типа:
```zig
var a = b + c.d;
foo();
bar();
```
Примеры скрытых потоков управления:
* D поддерживает `@property` функции, что есть методы, которые выглядят как доступ к полю, так что в примере выше `c.d` может вызывать функцию.
* C++, D и Rust позволяют перегружать операторы, так что оператор `+` может вызывать функцию.
* C++, D и Go поддерживают исключения, так что `foo()` может выбросить исключение и предотвратить вызов `bar()`. (Конечно, даже в Zig `foo()` может вызвать блокировку и предотвратить вызов `bar()`, но такое может произойти в любом Тьюринг–полном языке.)
Цель этого технического решения — улучшить читаемость.
## Без скрытых выделений памяти
Zig не вмешивается в процесс выделения кучи. Нет ни одного `нового` ключевого слова
или любой другой возможности языка, которая задействует распределитель кучи (например, оператор конкатенации строк[1]).
Вся работа с кучей осуществляется библиотекой и прикладным кодом, а не языком.
Примеры скрытых выделений:
* Функция `defer` в Go выделяет память для локального стека функции. Помимо того, что этот способ
работы потока управления неинтуитивен, он может привести к нехватке памяти, если вы используете
`defer` внутри цикла.
* Сопрограммы C++ выделяют память кучи, чтобы вызвать сопрограмму.
* В Go вызов функции может привести к выделению кучи, поскольку горутины выделяют небольшие стеки,
которые изменяют свой размер, когда стек вызовов становится достаточно глубоким.
* Основные API стандартной библиотеки Rust паникуют при нехватке памяти,
а альтернативные API, принимающие в качестве параметра распределитель кучи, недоработаны.
(см. [rust-lang/rust#29802](https://github.com/rust-lang/rust/issues/29802)).
Почти во всех языках со сборщиком мусора есть скрытые выделения памяти, поскольку
сборщик мусора прячет сведения об очистке.
Основная проблема со скрытыми выделениями памяти заключается в том, что они препятствуют *переиспользованию*
части кода, излишне ограничивая количество окружений, в которых код
мог бы быть развернут. Короче говоря, есть случаи использования, когда необходимо полагаться на то,
что поток управления и вызовы функций не будут иметь побочного эффекта выделения памяти,
следовательно, язык программирования может обслуживать такие сценарии использования, только если он может реально обеспечить такую гарантию.
В Zig есть функции стандартной библиотеки, которые предоставляют и работают с распределителями кучи,
но это необязательные функции стандартной библиотеки, которые не встроены в сам язык.
Если вы никогда не инициализируете распределитель кучи, вы можете быть уверены, что ваша программа не будет выделять кучу.
Каждая функция стандартной библиотеки, которой необходимо выделить память кучи, принимает для этого параметр `Allocator`.
Это означает, что стандартная библиотека Zig поддерживает "голое железо" (freestanding). Например,
`std.ArrayList` и `std.AutoHashMap` могут быть использованы для программирования "на голом железе"!
Пользовательские аллокаторы упрощают ручное управление памятью. Zig имеет отладочный распределитель,
который поддерживает безопасность памяти в условиях "использования после освобождения памяти" и "двойного освобождения памяти". Он автоматически
обнаруживает и печатает трассировку стека для утечек памяти. Также существует распределитель на основе регионов, позволяющий
объединять любое количество выделений памяти в одно и освободить их все сразу, а не управлять
каждым выделением отдельно. Специальные аллокаторы могут быть использованы для повышения производительности
или улучшения использования памяти для нужд конкретного приложения.
[1]: На самом деле, существует оператор конкатенации строк (в широком смысле оператор конкатенации массивов), но он работает только во время компиляции, так что он всё ещё не выполняет никакого распределения кучи во время выполнения.
## Первоклассная поддержка отсутствия стандартной библиотеки
Как было сказано выше, Zig имеет совершенно необязательную стандартную библиотеку. Каждый API стандартной библиотеки компилируется
в вашу программу только тогда, когда вы его используете. Zig имеет равную поддержку для связывания с стандартной библиотекой C или
отсутсвия оной. Zig дружелюбен к высокопроизводительной разработке и разработке "на голом железе".
Это лучшее из двух миров; например, в Zig программы на WebAssembly могут одновременно использовать
обычные возможности стандартной библиотеки и при этом создавать самые маленькие бинарные файлы по сравнению
с другими языками программирования, поддерживающими компиляцию в WebAssembly.
## Переносимый язык для библиотек
Одним из "святых Граалей" программирования является переиспользование кода. К сожалению, на практике мы сталкиваемся с тем, что нам приходится снова и снова "изобретать велосипед". Зачастую это оправдано.
* Если приложению нужны гарантии реального времени, то любая библиотека, использующая сборку мусора или любое другое недетерминированное поведение, отбрасывается как зависимость.
* Если в языке слишком легко игнорировать ошибки и, следовательно, трудно проверить, что библиотека правильно обрабатывает и выводит ошибки, может оказаться весьма заманчивым желание проигнорировать библиотеку и реализовать её заново, зная, что все соответствующие ошибки будут обработаны правильно. Zig разработан таким образом, что самое лёгкое, что может сделать программист, это правильно обработать ошибки, и поэтому можно быть достаточно уверенным в том, что библиотека будет правильно обрабатывать ошибки.
* В настоящее время с практической точки зрения верно, что C является наиболее универсальным и переносимым языком. Любой язык, не имеющий возможности взаимодействовать с кодом на C, рискует остаться неизвестным. Zig пытается стать новым переносимым языком для библиотек, одновременно обеспечивая простоту соответствия "бинарному интерфейсу приложений" (ABI) языка C для внешних функций, а также предлагая безопасность и модель языка, который предотвращает распространенные ошибки в реализациях.
## Пакетный менеджер (скоро) и система сборки для существующих проектов
Zig — это язык программирования, но он также поставляется с системой сборки и (в будущем) пакетным менеджером, которые должны быть полезны даже для традиционного C/C++ проекта.
Вы можете не только писать код на Zig вместо кода на C или C++, но и использовать Zig в качестве замены autotools, cmake, make, scons, ninja и т. д. И в дополнение к этому, он (будет) предоставлять пакетный менеджер для нативных зависимостей. Эта система сборки предназначена для использования даже в том случае, когда вся кодовая база проекта написана на C или C++.
Системные пакетные менеджеры, такие как apt-get, pacman, homebrew и т.д., играют важную роль для конечного пользователя, но их может быть недостаточно для нужд разработчиков. Пакетный менеджер для конкретного языка может стать изменить ситуацию с отсутствием разработчиков или их большим количеством. Для проектов с открытым исходным кодом сложность загрузки проекта для сборки может стать огромным препятствием для будущих разработчиков. Для проектов на C/C++ наличие зависимостей может стать фатальным, особенно на Windows, где нет пакетного менеджера. Даже при сборке самого Zig большинство потенциальных участников проекта испытывают трудности с зависимостью от LLVM. Zig будет предлагать проектам возможность напрямую зависеть от нативных библиотек — не полагаясь на наличие нужной версии в системном пакетном менеджере пользователя, и практически гарантированно успешно собирать проекты с первой попытки, независимо от используемой системы и платформы.
Zig разумно предлагается для замены системы сборки проекта на язык, использующий декларативный API для сборки проектов, который также обеспечивает управление пакетами, и, таким образом, возможность фактически зависить от других библиотек на C. Возможность иметь зависимости позволяет создавать абстракции более высокого уровня и распространять переиспользуемый высокоуровневый код.
## Простота
C++, Rust и D обладают таким большим количеством функций, что они могут отвлекать от реальной логики приложения, над которым вы работаете. Вместо того, чтобы заниматься отладкой приложения, разработчик начинает отлаживать свои знания языка программирования.
В Zig нет макросов и метапрограммирования, но при этом он достаточно мощный для того, чтобы выражать сложные программы понятным, немногословным способом. Даже в Rust есть макросы с особыми случаями, например, `format!`, который реализован в самом компиляторе. Между тем, в Zig эквивалентная функция реализована в стандартной библиотеке без использования специального кода в компиляторе.
## Удобство
Zig может быть скачан в разделе [Загрузка](/download/). Zig предоставляет архивы с двоичными файлами для Linux, Windows, macOS и FreeBSD. Ниже описано, что вы получите вместе с одним из этих архивов:
* устанавливается путем загрузки и распаковки одного архива, не требует настройки системы
* статически компилируется, поэтому не имеет зависимостей во время выполнения
* использует развитую и хорошо поддерживаемую инфраструктуру LLVM, которая обеспечивает глубокую оптимизацию и поддержку большинства основных платформ
* поддерживает кросс–компиляцию "из коробки" для большинства основных платформ
* поставляется с исходным кодом стандартной библиотеки C, которая будет динамически компилироваться при необходимости для любой поддерживаемой платформы
* содержит систему сборки с поддержкой кэширования
* компилирует код на C и C++ с поддержкой стандартной библиотеки C