Pull to refresh

«Проклятие» фигурных скобочек

Reading time 9 min
Views 48K
Допустим, вы крупная Компания. Занимаетесь разработкой Браузера, Почтовика и даже ОС для смартфонов. Неожиданно вы понимаете, что вам не нравится современный и мощный язык С++. Ну или нравится, но работать с ним невозможно. Бывает. И вот вы, взрослая стабильная компания решаете разработать новый язык программирования. Рецепт простой. Берете бочку денег, книжки по истории ИТ, роту программистов и грузовик МакБуков. Долго думаете, быстро кодите, разводите хайп в соцсетях (реддит, фейсбук, гитхаб). И вот, в 2015-м году вы даете сообществу The Язык. Назовем его Яист.

Язык это инструмент профессионалов. Работает по профессии — значит профессионал. Что первым делом читает профессионал при изучении нового языка? Конечно, объективное мнение коллег. Оно в основном положительное. Следом за мнением коллег профессионал читает описание языка. Больше двухсот страниц. Ох. Будет, чем убить время в метро.

Быстрый старт


Hello, World!


Самый важный этап изучения.

fn main() {
  println!("Hello, world!");
}

Что мы видим? fn, фигурные скобки, точку с запятой, println!. Это макрос, как нам поясняет автор. Строковая константа это строковая константа.

Очевидно, разработчики потрудились над сокращенным написанием ключевого слова fn. Это вам не кричащее PROCEDURE, которое писать долго, еще надо Shift зажимать. Этот пункт однозначное улучшение, по сравнению с восьмидесятыми. Функция main() возвращает ничего. Пустоту. Результат void, даже указывать не надо. Попробуйте объяснить void пятиклассникам. То-то же.
Фигурные операторные скобки. Такие скобки, как известно, экономили память на машинах 70-х. Теперь они экономят время программиста. Ему некогда писать BEGIN END, ведь 21-й век за окном. Время продуктивности.

Макрос println! обращает на себя внимание восклицательным знаком. Это вам не функция. Впрочем, о происхождении макроса мы ничего не знаем, так как полные квалификаторы сущностей не нужны. Может быть, он даже встроен в язык, ведь в примере нет никакой секции импорта (на самом деле есть, любая программа импортирует ограниченный набор из библиотеки std). Нет времени выяснять, просто println! В 90-х это бы записали как Log.String(«Hello, World!»). Лихое было время, мы выживали как могли.

Не забудьте точку с запятой. Это expression based язык программирования. Точка с запятой отделит одну скобочку от другой. Завершается процедура закрывающей скобочкой. В 90-х её завершили бы END Main. Хорошо, что те времена уже прошли.

Cargo


Карго это пакетный менеджер. Скачивает зависимости, занимается их построением. Яист предполагает культ карго. В 90-е такого не было. Тут нужно отдать должное авторам. Бочка денег была выпита не зря. Языком программирования инструмента Cargo является toml — ini на стероидах.

Примеры


Дальше автор книги рассматривает пример игры в угадайки.

use std::io;
fn main() {
  println!("Guess the number!");
  println!("Please input your guess.");
  let mut guess = String::new();
  io::stdin().read_line(&mut guess)
    .ok()
    .expect("Failed to read line");
  println!("You guessed: {}", guess);
}


Мы должны обработать ввод пользователя, поэтому надо использовать библиотеку io из библиотеки std. Use std::io, Luke; И снова мы стали свидетелями того, как тщательно поработали авторы языка над синтаксисом. Раньше ведь как, IMPORT StdIO, большими буквами приходилось писать. Беспощадное отношение к рукам программиста. И два двоеточия. Возможно, это как четыре плюса в символе #. Макрос println! уже видели.

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

Наличие мутабельных и иммутабельных псевдопеременных выводит нас на новый уровень контроля над данными. Переменные больше не переменны. Будущее наступило.

String это строка. new() это new(). Потом будет io::stdin() с текущим интерфейсом и println! с возможностью автоподстановки аргументов в результирующую строку.

Развитием этого примера является генерирование рандомного числа с помощью сторонней библиотеки.

extern crate rand;


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

match guess.cmp(&secret_number) {
  Ordering::Less => println!("Too small!"),
  Ordering::Greater => println!("Too big!"),
  Ordering::Equal => println!("You win!"),
}


Метод cmp() служит для сравнения всего сравнимого. Результат сравнивается с преопределенными значениями из Enum'а c помощью оператора match. Раньше для такого был оператор CASE, условный выбор. Но теперь другие времена. Життя по-новому. Стрелочка => которую вы могли принять за составной оператор сравнения с точки зрения арабской письменности на самом деле является указателем на выражение, соответствующее варианту сопоставления.

С циклами в примере все хорошо. Есть break и continue, все как во взрослых языках. Дейкстра уже умер, можно не волноваться, что он не одобрит выход из середины цикла. Это ведь не усложняет понимание цикла. В 90-х усложняло, а сейчас люди умнее стали, и инструменты мощнее. И вообще, профессионалы не ошибаются.

Философы кушают


Структуры Philosophers Едят методом eat(). Автор плавно переходит к примеру про философов. Вводит читателя в курс дела, что есть структуры, у них есть связанные функции с параметром &self (аналог this). Это в 90-х можно было назвать связанный объект как тебе угодно, в 2015 такая фича слишком сложна для реализации. Читаем про метод new, он конструирует новый экземпляр класса. Может иметь пользовательские параметры.

Несколько философов размещаются в списке с помощью макроса vec!. Тип переменной списка мы не указываем. Но он есть.
В программу вводятся примитивы параллельного программирования.

let handles: Vec<_> = philosophers.into_iter().map(|p| {
  thread::spawn(move || {
    p.eat();
  })
}).collect();


Экономия усилий программиста во всем, в именовании методов. в синтаксисе замыканий. В отсутствии необходимости указывать тип данных. А что, и так все понятно. Это Пэ, это Век. Программирование тредов в примере опирается на мьютексы. Ну и хорошо. А то навыдумывали в 90-е всяких активных объектов. Сплошные проблемы от этого. Лучше старого доброго мьютекса ничего нет, если хочешь писать серьезный взрослый софт. Тем временем синтаксис описания импорта обрастает новыми возможностями.

use std::sync::{Mutex, Arc};


Возможности языка это краеугольный камень успеха.

Использование Яист извне


После философских обедов автор решает сфокусировать свое внимание на более приземленных вещах — на использовании Яист при построении shared library.

Это не так интересно с точки зрения программиста, ведь до сих пор функциональность shared libraries в Windows/Linux довольно убогая. Нет возможности получить информацию об интерфейсе, проблемы с кроссплатформенностью, проблемы с версионностью (точнее, отсутствие версионности, которое становится проблемой клиентского кода), авторам высокоуровневых языков приходится приземляться на уровень Cи. Некоторые языки вообще не могут так низко пасть. Но это же их проблемы. Ведь на дворе 2015-й год, а технология использования dll проверенная, надежная. У профессионалов давно есть инструменты, типа FFI. Так что не надо думать, что все технологии из семидесятых это что-то плохое. На какие укажут, те и плохие, а некоторые — хорошие. Например, модульность на уровне shared library.

#[no_mangle]
pub extern fn process() 


Это Кличка Гога Shared Library на Яисте.

Эффективный Яист



Управление памятью


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

Параметры функций


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

Тестирование


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

Условная компиляция


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

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

Документация


Она есть. Даже с HTML. Мы можем многое.

Итераторы


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

Многопоточность


Треды, мьютексы, каналы, безопасная передача между тредами, мутабельность/иммутабельность. Проверено-надежно.

FFI


Добро пожаловать в мир Си-интерфейсов функций и Си-типов данных. КМПВ, в мире бабочек и пони никому не придется использовать эти ужасные инструменты. А пока приходится жить в мире FFI, где дух семидесятых и свобода от порядка раскладывания параметров на стек.

Borrow and AsRef traits


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

Яист l4ngu4g3 6еЗНoГNМ



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

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

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

Заключение


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

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

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

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

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

Слово «проклятие» иносказательное. Чтобы передать смысл явления. Не принимайте близко к сердцу. Мир вам.
Tags:
Hubs:
0
Comments 377
Comments Comments 377

Articles