Об авторе. Федерико Мена-Кинтеро — мексиканский программист, один из основателей проекта GNOME, автор книги «Язык программирования Rust».

Librsvg достиг переломного момента: внезапно выясняется, что легче портировать некоторые основные части из C на Rust, чем просто добавить аксессоры. Кроме того, всё больше «мяса» библиотеки сейчас написано на Rust.

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

Элегия C


Я влюбился в C около 24 лет назад. Выучил азы по второму изданию “The C Programming Language by K&R” в переводе на испанский. До этого я использовал достаточно низкоуровневый Turbo Pascal, с указателями и ручным распределением памяти, так что C казался приятным и придающим сил.

K&R — отличная книга для выработки стиля и лаконичности. Эта маленькая книжка даже научит вас реализовать простой malloc()/free(), что поистине просветляет. Даже низкоуровневые конструкции можно вставлять в самом языке!

В последующие годы я хорошо освоил C. Это небольшой язык с маленькой стандартной библиотекой. Вероятно, идеальный язык для реализации ядра Unix на 20 000 строк кода или около того.

GIMP и GTK+ научили меня причудливой объектной ориентации в С. GNOME научил, как поддерживать крупные программные проекты на С. Начало казаться, что первый проект в 20 000 строк кода C можно более или менее полно понять за несколько недель.

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

Мои приятные моменты работы с C


Первый раз прочитал исходники POV-Ray и научился объектной ориентации и наследованию в С.

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

Прочитал исходники SIOD, затем первые исходники Guile — и понял, как интерпретатор Scheme можно написать на C.

Написал первые версии Eye of GNOME и настроил рендеринг микротайлов.

Неприятные моменты


Когда в команде Evolution всё шло наперекосяк. Нам тогда пришлось купить машину Solaris просто чтобы иметь возможность купить Purify; тогда не было Valgrind.

Отладка взаимных блокировок gnome-vfs.

Безрезультатная отладка Mesa.

Принял первоначальную версию Nautilus-share и обнаружил, что там ни разу не используется free().

Пытался рефакторить код, где я понятия не имел о стратегии управления памятью.

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

Но ладно, давайте всё-таки поговорим о тех вещах Rust, которых мне не хватает в C.

Автоматическое управление ресурсами


Одной из первых статей, которые я прочитал о Rust, была статья «В Rust никогда не придётся закрывать сокет». Rust позаимствовал идеи C++: это идиома «получение ресурса есть инициализация» (RAII), умные указатели, он добавил принцип единственной ответственности для величин и автоматическое, детерминированное управление ресурсами в очень аккуратном виде.

  • Автоматическое: не нужно вручную расставлять free(). Память освобождается, файлы закрываются, мьютексы разблокируются вне зоны видимости. Если нужно обернуть внешний ресурс, просто реализуете трейт Drop, и это в основном всё. Такой ресурс становится как будто частью языка, потому что потом не нужно вручную нянчиться с ним.
  • Детерминировано: ресурсы создаются (память выделяется, происходит инициализация, файлы открываются и т.д.) и уничтожаются вне зоны видимости. Здесь нет сборки мусора: всё действительно уничтожается с закрытием скобки. Вы начинаете рассматривать потоки данных в программе как дерево вызовов функций.

Когда постоянно забываешь освободить/закрыть/уничтожить объекты C или, ещё хуже, пытаешься найти в чужом коде места, где забыли это сделать (или сделали дважды, что неправильно)… Нет, я не хочу снова этим заниматься.

Дженерики (обобщённые типы)


Vec<T> действительно представляет собой вектор, элементы которого имеют размер T. Это не массив указателей к отдельно выделенным объектам. Он компилируется специально для кода, который может обрабатывать только объекты типа T.

Написав кучу мусорных макросов на C для подобных вещей… не хочу снова этим заниматься.

Типажи (трейты) — не просто интерфейсы


Rust — это не Java-подобный объектно-ориентированный язык. Вместо этого у него есть типажи, которые на первый взгляд кажутся интерфейсами Java — простой способ динамической диспетчеризации: типа если объект реализует Drawable, то вы можете предположить наличие метода draw ().

Но типажи способны на гораздо большее.

Связанные типы


У типажей могут быть ассоциированные (связанные) типы. Например, типаж Iterator может выполняться таким образом:

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}

Это значит, что каждый раз при выполнении Iterator для какого-то итерируемого объекта нужно также определить тип Item для перебираемых элементов. Если выполняется next() и элементы ещё не закончились, то вы получите Some(YourElementType). Если у итератора закончились элементы, то он вернёт None.

Связанные типы могут ссылаться на другие типажи.

Например, в Rust вы можете использовать циклы for везде, где выполняется типаж IntoIterator:

pub trait IntoIterator {
    /// The type of the elements being iterated over.
    type Item;

    /// Which kind of iterator are we turning this into?
    type IntoIter: Iterator<Item=Self::Item>;

    fn into_iter(self) -> Self::IntoIter;
}

При выполнении такого типажа следует указать и тип Item в итераторе, и тип IntoIter — фактический тип для Iterator, который определяет состояние итератора.

Таким образом можно создавать паутину типов, которые ссылаются друг на друга. У вас может быть типаж «Я могу выполнить foo и bar, но только если предоставите тип, способный делать то и то».

Срезы


Я уже писал об отсутствии срезов строк в C и о том, как это неудобно, когда к ним привыкнешь.

Современные инструменты для управления зависимостями


Вместо этого:

  • Вызывать pkg-config вручную или с помощью макросов Autotools.
  • Разбираться с путями в include для заголовочных файлов...
  • … и файлов библиотек.
  • И надеяться, что у пользователя установлены правильные версии библиотек.

Вы просто пишете файл Cargo.toml, в котором перечисляете названия и версии своих зависимостей. Они загружаются c известного адреса или из другого указанного места.

Больше не нужно бороться с зависимостями. Всё сразу работает по команде cargo build.

Тесты


Использовать юнит-тесты в C очень трудно по нескольким причинам:

  • Внутренние функции зачастую статические. Это значит, что их нельзя вызвать за пределами исходного файла, где их объявили. Программа теста должна или сделать #include исходного файла с этими статическими функции, или использовать директивы #ifdef для удаления статики только на время тестирования.
  • Нужно пошаманить с Makefile, чтобы связать тестовую программу только с частью кода, где есть зависимости, или только с остальным кодом.
  • Следует выбрать фреймворк для тестирования. Зарегистрировать там тесты. Изучить фреймворк.

В Rust вы пишете в любом месте программы или библиотеки:

#[test]
fn test_that_foo_works() {
    assert!(foo() == expected_result);
}

… и когда набираете cargo test, ОН БЛИН ПРОСТО РАБОТАЕТ. Этот код связывается только с тестовым бинарником. Не нужно ничего компилировать дважды вручную или химичить с Makefile, или думать, как извлечь внутренние функции для тестирования.

Для меня это вообще киллер-фича.

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


Rust генерирует документацию из комментариев в синтаксисе Markdown. Код из документации запускается как тесты. Вы можете описать назначение функции и одновременно её протестировать:

/// Multiples the specified number by two
///
/// ```
/// assert_eq!(multiply_by_two(5), 10);
/// ```
fn multiply_by_two(x: i32) -> i32 {
    x * 2
}

Код вашего примера запускается в виде теста и гарантирует, что документация соответствует фактическому коду.

Дополнение 23.02.2018: QuietMisdreavus описал, как rustdoc преобразует doctests в исполняемый код. Это магия высокого уровня и чрезвычайно интересно.

Гигиенические макросы


У Rust есть гигиенические макросы, лишённые всех проблем с неумышленным скрытием идентификаторов в коде C. Вам не нужно писать каждый символ в круглых скобках, чтобы макрос max (5 + 3, 4) правильно работал.

Нет автоматических преобразований


Все эти баги в C, из-за которых int случайно преобразуется в short, char или что-то ещё — Rust так не поступает. Здесь необходимо явное преобразование.

Нет целочисленного переполнения


Сказано достаточно.

В целом, в безопасном Rust отсутствует неопределённое поведение


В Rust считается багом в языке, если нечто в «безопасном Rust» (то есть всё, что разрешено писать вне блоков unsafe {}) приводит к неопределённому поведению. Можете поставить >> перед отрицательным целым числом — и всё будет предсказуемо работать.

Сопоставление шаблонов


Знаете эти предупреждения gcc, когда оператор switch() применяется для enum, не обрабатывая все значения? Ну словно маленький ребёнок.

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

impl f64 {
    pub fn sin_cos(self) -> (f64, f64);
}

let angle: f64 = 42.0;
let (sin_angle, cos_angle) = angle.sin_cos();

Можно запустить match() на строках. ВЫ МОЖЕТЕ СРАВНИТЬ ГРЁБАНЫЕ СТРОКИ.

let color = "green";

match color {
    "red"   => println!("it's red"),
    "green" => println!("it's green"),
    _       => println!("it's something else"),
}

Показать непонятную строчку?

my_func(true, false, false)

А что если вместо этого сопоставить шаблоны, соответствующие аргументам функции:

pub struct Fubarize(pub bool);
pub struct Frobnify(pub bool);
pub struct Bazificate(pub bool);

fn my_func(Fubarize(fub): Fubarize, 
           Frobnify(frob): Frobnify, 
           Bazificate(baz): Bazificate) {
    if fub {
        ...;
    }

    if frob && baz {
        ...;
    }
}

...

my_func(Fubarize(true), Frobnify(false), Bazificate(true));

Стандартная, полезная обработка ошибок


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

#[derive(Debug)]


Если пишете новый тип (скажем, структуру с кучей полей), можете указать #[derive(Debug)] — и Rust будет знать, как автоматически вывести содержимое этого типа для отладки. Больше не придётся писать специальную функцию, которую нужно вызывать вручную в gdb чтобы просто проверить кастомный тип.

Замыкания


Больше не придётся вручную передавать указатели функций и user_data.

Заключение


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

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

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

Комментарии (149)


  1. yarric
    28.02.2018 15:47

    Эхх, хочется компилируемый язык с легковесным синтаксисом в стиле Go, управлением ресурсами и безопасностью в стиле Rust и лаконичностью (без этих var, func, mut) C...


    1. domix32
      28.02.2018 16:26

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


      1. PsyHaSTe
        28.02.2018 19:54

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


        1. domix32
          01.03.2018 10:48

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


      1. LSDtrip
        28.02.2018 20:02

        Писать новые нейронки. Вряд ли нейросеть сможет сделать что-то лучше, чем она сама. Очевидно же.


        1. Antervis
          28.02.2018 21:51

          1. LSDtrip
            01.03.2018 16:57

            Хорошо. Но с участием программиста и нейронки можно получить больше, чем просто одной лишь нейронкой. Больше это никогда не меньше.


            1. khim
              01.03.2018 17:11

              Далеко не всегда. В частности Alpha Go Zero (не использующая «человеческое знание») некоторое время отстаёт от AlphaGo (которая для начального обучения использует их), но со временем обгоняет и в конечном итоге результат получается лучше.


              1. LSDtrip
                02.03.2018 23:17

                Alpha Go Zero ведь то же люди… Просто их программисты лучше :)


                1. khim
                  02.03.2018 23:45

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

                  Оказалось, что сеть научается быстрее играть, если дать ей партии чемпионов… но также «научается плохому».

                  Как известно переучиться — сложнее, чем изначально научиться всё делать правильно… к нейронным сетям это, как оказалось, тоже относится…


                  1. LSDtrip
                    03.03.2018 01:04

                    Ну, по сути, программисты заменили себя каким-то кодом, который требует меньше их участия, но не лишились работы) Заменили себя, но от этого стали только нужнее… Ведь только они знают, как сделать замену замене)

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


                  1. LSDtrip
                    03.03.2018 01:46

                    Интересно, а что если нейросети показать только ошибки чемпионов и ничего больше?.. Это будет лучше? Чтобы она случайно не перепутала плохое с хорошим…


                    1. khim
                      03.03.2018 01:59

                      Для этого, как бы, нужно понять — где именно чемпионы делали ошибки.

                      А этого никто не знает — обе сети чемпионов выносят «всухую».

                      И обе при этом иногда делают ходы, которые до этого десятилетиями считались «слабыми». Но одна-таки играет лучше, другая — хуже.

                      Это-то мы можем понять: для того, чтобы сказать, что Ма?гнус Ка?рлсен играет сильнее Васи Пупкина не нужно даже правил игры знать — достаточно посмотреть на резлуьтаты матчей… но вот почему так — достоверно неизвестно.


        1. domix32
          01.03.2018 22:49

          Как-то серьёзно люди предложение приняли. Надо было тэг <sarcasm/> вставить По ссылке выше нейронка от гугла пыталась сгенерировать улучшенную нейронку и даже вроде успешно. Но с той скоростью обучения естественно что-то сложное писать оно научится лет через дцать.


    1. 0xd34df00d
      28.02.2018 19:06

      Прям хаскель с линейными типами.


    1. PsyHaSTe
      28.02.2018 19:56
      +3

      Rust и так лаконичнее некуда. Если что-то он и требует, то только для явности, которая является его священной коровой. Если вы хотите, чтобы все касты были автоматические, но компилятор ВДРУГ каким-то магическим образом определял, что вот тут может быть ошибка или переполнение — извините, не придумали пока. Кстати, явное приведение (что является примером «нелаконичности») автором оригинального поста рассматривается как существенный плюс, а не минус. Кстати, ключевого слова `var` в языке нет.


      1. khim
        01.03.2018 01:57

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

        Если у вас слишком большие и сложные программы — то, может быть, вам нужно делать менее запутанный дизайн, а не искать более лаконичный язык?


    1. uniqm
      01.03.2018 11:41

      Может Сrystal?


      1. lomnev
        01.03.2018 13:59

        Именно Crystal.
        Если найдется корпорация, которая вложит в него столько же, сколько вложили в Golang,
        Crystal имеет шансы войти в Top 5.


  1. sena
    28.02.2018 15:56

    удалено


  1. VioletGiraffe
    28.02.2018 16:27
    +2

    А зачем это нужно в С, когда почти всё это есть в С++? А С не для того и не о том (и вообще, имхо, не нужно в 2018 году ничего программировать на чистом С).


    1. berez
      28.02.2018 18:53

      На чистом С еще много где нужно программировать — например, драйверы ядра писать. Или на микроконтроллерах ковыряться — интернет вещей же, вычовычо.

      Но вообще статья странноватая. Взять два языка разного уровня и рассказывать, чего не хватает в низкоуровневом. Дык — коню понятно, чего не хватает: того, что добавлено в высокоуровневые языки. Думаю, в рекламке Rust все его преимущества описаны лучше и полнее, чем у товарища Федерико.


      1. smer44
        28.02.2018 19:29

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


        1. velvetcat
          01.03.2018 08:49

          Пример кроссплатформенного редактирования скомпилированной функции в студию, пожалуйста. Сравним с вызовом eval().


        1. Kobalt_x
          01.03.2018 11:30

          Это если в вашей ОС нету или отключен DEP и W^X страницы


      1. lain8dono
        28.02.2018 20:39

        На чистом С еще много где нужно программировать — например, драйверы ядра писать.
        Или на микроконтроллерах ковыряться — интернет вещей же, вычовычо.

        Можно и на Rust. Ладно, патч в ядро не примут, а с AVR лучше переходить на STM32 и компанию.


        1. quwy
          01.03.2018 02:27

          Никто ведь не произнес слова AVR, но в который раз слышу, что нужно переходить на этот STM32. А можно еще каких-нибудь аргументов подкинуть? Чем он такой чудесатый, что нужно все бросать и на него переходить?


          1. 0xd34df00d
            01.03.2018 19:40

            И правда, не нужно. На плюсах вполне можно писать и под AVR.


          1. lain8dono
            02.03.2018 04:20

            Никто ведь не произнес слова AVR

            Кое-кто произнёс "микроконтроллеры". Разве STM32 и AVR это не самое первое, что вспоминается на эту тему? Ну у меня так.


            Чем он такой чудесатый, что нужно все бросать и на него переходить?

            ТТХ либо сравнимо, либо сильно лучше при более низкой цене. Речь больше о том, что под AVR на Rust только при помощи костыльного https://github.com/avr-rust можно что-то делать. Могу ответить вам как фанбой фанбою: AVR ненужен ибо для прогания на оном при использовании Rust будет слишком много костылей. Вас устроит такой ответ? Лично для меня подобной проблемы вообще не существует. Ящитаю, что выбирать инструменты стоит из характера задач, а не по религиозным причинам.


            1. quwy
              02.03.2018 20:05

              Кое-кто произнёс «микроконтроллеры». Разве STM32 и AVR это не самое первое, что вспоминается на эту тему?

              Первое, что приходит в голову — это личная особенность каждого, кому-то и PIC приходит.

              ТТХ либо сравнимо, либо сильно лучше при более низкой цене.

              Хотелось бы конкретики. Вроде бы там более высокопроизводительное ядро, но как по мне, то в 99% практических задач скорость выполнения команд для контроллера — десятое дело. Гораздо интереснее периферия.
              • Что у STM с «обвесом» ядра по сравнению с тем же AVR?
              • Есть ли тараканчики по типу ATtiny, работающие без единой внешней детали?
              • Есть ли линейки полностью совместимых по ногам, но оснащенных разным количеством памяти наименований?
              • Что вообще с DIP? (в процессе экспериментов довольно трудно перепрошивать другие корпуса, а развести ISP не всегда возможно и всегда излишне для готового девайса).

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


      1. leotsarev
        28.02.2018 20:43
        +2

        Ну так Rust это вам не Go. Он нацелен на убийство C, у него нулевой рантайм и прочие фичи.


        1. gudvinr
          28.02.2018 23:40

          Строго говоря, у всего, что не ассемблер — рантайм не нулевой. Даже у C.
          Другое дело, что в стандартном рантайме там нет тяжелых вещей вроде сборщика мусора, но раскрутка стека, выделение/освобождение памяти — это тоже рантайм.
          Так что какой-то рантайм там есть, то он небольшой.


          1. zekefast
            01.03.2018 08:53

            Unwinding & Error processing/panic, но Rust может прикрасно обходиться без runtime, если нужно для твоей задачи, например, написания оси.


      1. Dicebot
        28.02.2018 21:22

        Rust — низкоуровневый язык. Уровень определяется близостью к железу, а не фичами языка.


        1. DistortNeo
          01.03.2018 14:15
          +1

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

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


          1. Dicebot
            01.03.2018 15:24

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


            Но про ассемблер неверно, так все такие языки позволяют писать платформозависимый код. В том же Rust inline assembly планируется как часть языка (емнип уже есть в nightly, но не stable сборках). В С на практике тоже, хотя это и не часть стандарта.


            Для меня сейчас понятие "уровня" полностью сводится к наличию/отсутствию обязательного рантайма и возможности unsafe работы с памятью.


            1. DistortNeo
              01.03.2018 20:18

              Для меня сейчас понятие "уровня" полностью сводится к наличию/отсутствию обязательного рантайма и возможности unsafe работы с памятью.

              Ага, я для себя на 4 уровня делю языки:


              1. Низкий уровень — уровень железа: ассемблер, включая ассемблерные вставки из более высокоуровневых языков и интринсики.
              2. Средний уровень: прямой доступ к памяти, машинозависимые типы.
              3. Высокий уровень: отсутствие прямого доступа к памяти, языковые абстракции типа классов.
              4. Сверхвысокий уровень: скриптовые языки.

              Современные языки довольно сложны, и они занимают сразу несколько уровней. Тот же C++ может быть как низкоуровневым (смесь шаблонов с векторными инструкциями в обработке изображений), так и высокоуровневым (код не использует сырые указатели вообще — только умные указатели).


      1. VioletGiraffe
        01.03.2018 13:38
        +1

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


    1. a1ien_n3t
      28.02.2018 18:59

      Например у C++ ABI не стандартизован. И вы не можете использовать библиотеку собранную другим компилятором. С растом такой проблемы нет, можно спокойно линковать библиотеку на раст с приложением на си и с++ с использованием любого компилятора.


      1. roman_kashitsyn
        28.02.2018 23:03

        С растом такой проблемы нет

        В расте же придётся отключить манглинг не так ли? Так и в C++ можно, если extern "C" написать.


        1. a1ien_n3t
          01.03.2018 01:04

          А что с классами из с++ делать? Оборачивать все в сишный интерфейс? То есть если вы хотите использовать вашу библиотеку написанную на с++ в коде на Си вы должны весь апи реализовать через сишные функции.
          Да в расте тоже придется сделать некоторые телодвижения, но значительно меньше.
          И что делать с исключениями с++ вобще не понятно… Хотя если функция rust возвращает Result или Options, то наверно тоже есть нюансы как с ней работать в С.
          Но в правы, я был слишком категоричен, забыл что можно использовать extern для получения возможности вызывать код написанные на c++ из с путем создание оберток, в самом коде


          1. a1ien_n3t
            01.03.2018 01:11

            При этом еще остается проблемма что типы могут не совпадать. Например интересный документ www.agner.org/optimize/calling_conventions.pdf


          1. biseptol
            01.03.2018 04:11

            > То есть если вы хотите использовать вашу библиотеку написанную на с++ в коде на Си вы должны весь апи реализовать через сишные функции.

            Завернуть его в С++ фасад с простым интерфейсом — не вариант?


            1. PsyHaSTe
              01.03.2018 13:21
              +1

              Ну вот я хочу сейчас сделать враппинг OpenCV на расте. Знаете, что мне посоветовал один из ключевых разработчиков самого OpenCV? Цитата в студию:

              adapting a ~1000 lines python monster (which to 90% covers weird edge cases) might look daunting, but on the other hand, doing things manually, like those folks try will result in a «toy example», that only covers the 5% most used cases. (which again IS cool, too, don't get me wrong. problem is, if you deviate only a millimeter from it, you're staring into an open abyss)


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


              1. roman_kashitsyn
                01.03.2018 15:54

                Если это не показывает сложность FFI вызова плюсового кода — то я даже не знаю

                Т.е. если написать систему аналогичного масштаба на чистом идиоматичном Rust (с RAII и компайл-тайм полиморфизмом), то реализовать биндинги к, например, Python, будет тривиальной задачей?


                1. humbug
                  02.03.2018 15:08
                  +1

                  К Ruby — тривиальная задача, если использовать Helix.


                  1. roman_kashitsyn
                    02.03.2018 17:35

                    К Ruby — тривиальная задача, если использовать Helix.

                    Это не означает, что Rust какой-то особенный. Для C++ тоже давно существуют аналоги: CLIF и SWIG.


          1. roman_kashitsyn
            01.03.2018 15:57

            А что с классами из с++ делать?

            А что делать с RAII-структурами в Rust?


            И что делать с исключениями с++ вобще не понятно

            Ловить вcё в сишных обёртках и конвертировать в коды возврата. С растовыми статусами этого не придётся делать?


            1. PsyHaSTe
              01.03.2018 16:25

              А что делать с RAII-структурами в Rust?

              Т.е. если написать систему аналогичного масштаба на чистом идиоматичном Rust (с RAII и компайл-тайм полиморфизмом), то реализовать биндинги к, например, Python, будет тривиальной задачей?

              Ну, явно попроще. Вот тут пример небольшой есть.

              Ловить вcё в сишных обёртках и конвертировать в коды возврата. С растовыми статусами этого не придётся делать?

              Код возврата это просто Union, проблем с ним нет. А вот эксепшны намного опаснее:
              To implement this we must think about emulation of C++ exceptions in C, classes/methods/objects, etc, including some «runtime library» to support this.
              For example, you could take a look on «golang» approach from here: #10129 (but they completely lost C++ exceptions handling).
              Also you could take a look on OpenCV Python bindings, there are exceptions are re-wrapped into Python «exceptions» leaving message string only. Classes are emulated via Python runtime.

              OpenCV 3.x doesn't not support C compilation mode officially. There are still legacy C API calls (from OpenCV 1.x) but they should be compiled in C++ compilation mode.
              Even if you succeeded to build code with C compiler (and avoid cvRound problem: #6585) it would lead to terrible behavior like #6221 or silent crashes in case of raised C++ exceptions.

              Гарантирую, что из-за использование растовых статусов silent crash'а произойти не может.


              1. roman_kashitsyn
                01.03.2018 16:31

                Код возврата это просто Union, проблем с ним нет.

                Что значит "проблем с ним нет"? Обёртки для си всё равно писать надо. Что если в этом юнионе объекты с деструкторами лежат? Если нужно писать обёртки, то и в плюсах можно написать catch(...) и конвертировать исключения в коды возврата.


                1. roman_kashitsyn
                  01.03.2018 18:16
                  +3

                  Попрошу минусующих показать, как вызвать из C rust-функцию, возвращающую Result<Resource, Error> без написания специальных сишных обёрток. C++ исключения — это проблема, но как вы убеждаетесь, что panic! не прилетит из глубин сторонней библиотеки, которой вы пользуетесь? Может, так? Чем это отличается от catch(...)?


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


              1. roman_kashitsyn
                01.03.2018 18:21

                Вот тут пример небольшой есть

                Там владение объекта не передаётся в сторонний код. Сторонний код видит только указатель на объект, создаваемый и уничтожаемый в rust. Если стороннему коду нужно создавать и уничтожать экземпляры RustObject, нужно написать функции-обёртки для конструктора и деструктора. Один-в-один как в C++.


                1. mayorovp
                  01.03.2018 18:24

                  Если стороннему коду нужно создавать и уничтожать… нужно написать функции-обёртки для конструктора и деструктора

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


                  1. roman_kashitsyn
                    01.03.2018 18:29

                    Ну так а чем тогда растовый FFI сильно проще плюсового?


      1. phponelove
        01.03.2018 05:56

        Только вот незадача, у раста нет «другого компилятора». И почему вдруг для раста вам хватает одного компилятора, а для С++ нет? Вы уж определитесь там.


        1. a1ien_n3t
          01.03.2018 09:39
          +1

          Для c/c++ у нас есть msvc/gcc/llvm/Green Hills/keil/iar/borland список можно долго продолжать. И мне «хватает» и одного. Проблемма в том что вам могут дать бинарник собранный другим компилятором.
          Кстати у раста тоже есть под windows две вариации тулчейна msvc и gnu.


          1. Kobalt_x
            01.03.2018 11:32

            интересно какое interopability между msvc и gnu версиями?


          1. phponelove
            01.03.2018 20:46
            -3

            Проблемма в том что вам могут дать бинарник собранный другим компилятором.

            Маловероятно, что вам кто-то пришлёт бинарники написанные на расте, поэтому это высосанный из пальца пример.

            Так же, разные версии раста несовместимы между собой. За примерами ходить не надо, мне уже кто-то рассказывал о том, что «в расте добавили супер-оптимизацию, которой нет в С/С++, потому что это супер-язык», а оказалось — просто врубили флажок существовавший в llvm уже сотни лет, который уже давно реализован в гцц/шланге(-fpack-struct). Естественно, что эти изменения породили бинарно-несовместимые версии компилятора раст.

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

            Поэтому, подобная проблема существует только на одной платформе и с одним компилятором, и то кейс нереалистичный. Никто не будет под эту платформу собирать бинари gcc, а если будут собирать, то они должны быть совместимы с msvs.

            По поводу подобного:

            Для c/c++ у нас есть msvc/gcc/llvm/Green Hills/keil/iar/borland список можно долго продолжать.

            Зачем эта глупя подмена понятий? Во-первых — откуда тут взялся си? Во вторых, с каких пор эти «компиляторы» стали уметь в С++?

            Живых кросслпатформенных компилятора существует только два — гцц/шланг. Под одну платформу существует альтернативно-одарённый компилятор, который недавно только начал хоть как-то «уметь» в С++. Про их совместимость я уже написал выше.


            1. Antervis
              01.03.2018 20:59

              даже бинарники из-под разных версий msvc не могут друг с другом слинковаться, а с gcc и подавно. Рантайм то он может быть и поддерживает, но скорее всего только если gcc собрать студией


              1. phponelove
                01.03.2018 23:28

                даже бинарники из-под разных версий msvc не могут друг с другом слинковаться

                И? Что же из этого следует? Да мало того, что ничего не следует и это очередной бред, да к тому же — я уже разобрал эту тему выше.

                а с gcc и подавно

                Заявления противоречат реальности. gcc должен уметь линковаться с msvs, и я на 99% уверен, что это именно так.

                Про шланг/гцц я уже говорил, и тут я уже точно знаю, что это работает.

                Рантайм то он может быть и поддерживает

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

                но скорее всего только если gcc собрать студией

                Как комментировать подобную ахинею я просто не знаю. Это ведь не просто ошибка — это отборный бред.

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


                1. a1ien_n3t
                  02.03.2018 00:05

                  Заявления противоречат реальности. gcc должен уметь линковаться с msvs, и я на 99% уверен, что это именно так.

                  Спешу вас расстроить. Берете Qt'шные библиотеки собранные для msvc, берете gcc компилируете код и удачи вам с линковкой. Когда слинкуетесь прихотиде расскажите.

                  Или можно на оборот библиотеки собранные под gcc а линковать msvc. Разультат тотже.

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


                  1. phponelove
                    02.03.2018 02:53

                    Спешу вас расстроить.

                    Это меня никак не расстраивает, т.к. а) это ничего не меняет, б) я и не утверждал подобного.

                    Берете Qt'шные библиотеки

                    С чего я должен их брать? Когда на вы мне кути на расте покажите — тогда приходите. Для проверки достаточно любого С++ кода.

                    Или можно на оборот библиотеки собранные под gcc а линковать msvc. Разультат тотже.

                    Это я вообще не обсуждал, т.к. не нужно.

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

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

                    Шланг c gcc может и слинкуются, так-как шланг старается мимикрировать под gcc.

                    Не может, а слинкуются.

                    Но гарантий нету никаких.

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

                    Да и то пока вы не будете передавать что-то через классы стандартной библиотеки. Так-как она у них по разному реализована.

                    Шланг почти всегда существовал с гнутой stdlib, да и сейчас существует. Если понадобиться линковаться к гцц, то никто не будет использовать libc++.


                  1. Kobalt_x
                    02.03.2018 07:26

                    Qt это C++. msvc/GCC бесплатно сосуществует только если наружу C API и рантайм нужной версии. В C++ интерьеров разумеется нету. Про разные версии msvc собираете Qt со статическим рантайм и линкуетемь от MSVC 2010+


                  1. 0xd34df00d
                    02.03.2018 07:43

                    Но гарантий нету никаких. Да и то пока вы не будете передавать что-то через классы стандартной библиотеки. Так-как она у них по разному реализована.

                    За гарантии не скажу (по факту не работали только abi tags некоторое время после того, как их добавили в gcc 5), а со стандартной библиотекой всё просто: clang по умолчанию использует гццшную на Linux. -stdlib=libstdc++ против -stdlib=libc++.


              1. sumanai
                02.03.2018 00:19

                даже бинарники из-под разных версий msvc не могут друг с другом слинковаться

                Если вы про объектные файлы, то у меня всё линкуется.


              1. Kobalt_x
                02.03.2018 07:23

                Только в режиме C++ и рантайм снаружи в других случаях, static runtime и C AP наружу торчит то все нормально линкуется и с GCC и clang. В случае C++ API наружу линкуется со всем msvc который поддерживает тот же стандарт что в api


        1. roman_kashitsyn
          01.03.2018 15:49

          Только вот незадача, у раста нет «другого компилятора»

          Я тоже так думал, но потом случайно наткнулся на https://github.com/thepowersgang/mrustc
          Он не production-ready, но какие-то усилия в этом направлении прилагаются.


      1. domix32
        01.03.2018 10:57

        Так оно же как раз по причине отсутсвия стандарта ABI все ещё unstable.


    1. mayorovp
      28.02.2018 19:45

      В языке С++ любая переменная живет до конца блока где она объявлена, даже если потеряла смысл раньше.


      1. mayorovp
        01.03.2018 13:31
        +1

        Наверное, стоит пояснить мысль.


        В C++ есть множество методов, которые инвалидируют объект — обычные сценарии использования объекта после такого вызова ведут к UB или ошибке времени выполнения (по крайней мере, до повторной инициализации).


        Среди них — std::unique_ptr::release, std::thread::detach и std::thread::join, std::future::share и std::future::get, перемещение через std::move.


        Язык не имеет механизмов для предотвращения дальнейшей работы с объектом после вызова подобных методов.


    1. Alex_ME
      28.02.2018 21:22

      На C++ можно программировать микроконтроллеры. C++ не обязательно тяжелее — никто не заставляет использовать его работу с памятью, STL, виртуальное наследование, исключения. Без всего этого он не тяжелее С, а жизнь упрощает существенно. Начиная от банальной перегрузки функций и заканчивая HAL на шаблонах без единого лишнего байта.


      причудливой объектной ориентации в С

      На мой взгляд — это костыли и извращения.


      1. VioletGiraffe
        01.03.2018 14:48

        STL — очень нужная вещь, взять, хотя бы, банальный pair. А также всё, что связано с шаблонами и compile-time трюками — type_traits, std::forward и т. п.
        Пришлось найти реализацию stdlib для AVR, и даже немного её дополнить свежими фичами из С++11/14. А вот в тулчейне Arduino Due, например, stdlib уже есть их коробки, и довольно свежий и полный.


        1. 0xd34df00d
          01.03.2018 19:45

          Когда мне последний раз нужно было писать под AVR, я брал crossdev, который мне собирал gcc и всё что нужно для AVR, и там был более-менее полноценный STL (find_if всякие точно были).


  1. impwx
    28.02.2018 16:47

    Pattern matching в формальных аргументах функции выглядит очень странно. Неужели именованные аргументы при вызове не поддерживаются?


    1. snuk182
      28.02.2018 18:08

      Если вы об этом


      my_func(Fubarize(true), Frobnify(false), Bazificate(true));

      то так никто не пишет, потому что это громоздко. Именованных аргументов нет, поскольку и без них не хватает рук на все запланированное (хотя периодически намеки на них приплывают). Кроме того, против вызовов методов в стиле do(a, b, c, true, false) существует и поощряется использование билдеров и типажей для эмуляции перегрузки функций.


    1. nexmean
      28.02.2018 18:15

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


      1. smer44
        28.02.2018 19:08

        или заместа многих true-false юзать переменную с битовыми флагами а заместа численных — указатель на первую то бишь массив. по моему отсутствию опыта.


    1. Amomum
      28.02.2018 19:15

      Вроде как есть только pre-RFC про это, но IntelliJ Rust может делать что-то похожее:
      image


      1. vitvakatu
        01.03.2018 11:14

        Это не именованые аргументы. IDE просто приводит подсказки из объявления методов.


        1. Amomum
          01.03.2018 13:13

          А вы читали мой комментарий? Я и не утверждал, что это именованные аргументы.

          IntelliJ Rust может делать что-то похожее


  1. gatoazul
    28.02.2018 17:32

    Закрытия — очевидно, имелись в виду замыкания?


    1. m1rko Автор
      28.02.2018 18:16

      Да, конечно, руки на секунду отделились от мозга, прошу прощения…


  1. smer44
    28.02.2018 19:03
    -1

    задолбали выдумывать языки, фича которых выпендрёжный синтаксис функционала который должен быть и есть либо в API либо в DSL.
    напишите на этом супер Rust нейронку с умножением матриц, конволюцией и паралелизмом для CPU и потом сравните с производительностью на C



    1. snuk182
      28.02.2018 19:37
      +2

      Написать-то можно что угодно на чем угодно, даже с учетом требований производительности.
      Вопрос в стоимости:


      • написания
      • поддержки написанного


    1. Salabar
      28.02.2018 19:47

      А зачем писать конволюцию на Си, когда её можно написать на ASM и подключить к Расту? И точно знать, что если баг есть, то он в коде на ASM.


    1. PsyHaSTe
      28.02.2018 19:59
      +2

      Такое ощущение, что вы лид проекта, который писали на С, и вдруг все разработчики взяли и разбежались по раст-вакансиям, прям такая обида сочится из поста…


      1. tgz
        28.02.2018 21:23

        Просто компилятор раста немного умнее его. :)


    1. Alex_ME
      28.02.2018 21:24
      -1

      В чем-то соглашусь. Вот делают какой-то язык с рядом новых фич (Rust, Kotlin). Фичи-фичами, но зачем вы отказываетесь от привычного впитанного с молоком матери си-подобного синтаксиса объявления переменных, функций...


      1. Antervis
        28.02.2018 22:09

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


      1. DistortNeo
        28.02.2018 23:54

        Проблема в том, что Си-подобный синтаксис накладывает довольно жёсткие ограничения, из-за которых дополнительные возможности языка выглядят как костыли. Хороший пример: язык-монстр С++17/2a+ с довольно многословным синтаксисом.


      1. beeruser
        01.03.2018 00:48

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

        Хотя в целом Rust выглядит неряшливо, на мой вкус.


        1. phponelove
          02.03.2018 08:44
          -2

          К тому же привычный — не значит лучший.

          Это не имеет смысла, ведь работает подобное и в обратную сторону. Если привычный — не значит лучший, то и «не привычный» — не значит лучший, а значит подобные заявления друг друга компенсируют.

          Современные языки массово используют var: type вместо type var, благодаря чему тип можно опустить.

          Нельзя. Именно для этого и существуют let-кастыли, т.к. выражение без типа — неоднозначно.

          Я видел очень мало людей, которые понимают сишный синтаксис. 99% вообще напишет тут void f(int f(void)) указатель на функцию. То же самое с type qualifiers, то же самое с теми же указателями. Люди не понимают, что тип у переменной не type *, а *, а type и всё что слева — относится к операции разыменования.

          Квалификаторы справа — дефолт, квалификатор слева в случае с * неоднозначен, а значит не может относится к *. Квалификаторы слева — так же никаких проблем, ведь всё логично.

          Дано я уже не видел объективной критики сишного синтаксиса. Кроме возврата указателя на функцию я вообще не видел ничего.


          1. Amomum
            02.03.2018 18:01
            +1

            Как насчет такого?

            char * const (*(* const bar)[5])(int )


          1. DistortNeo
            02.03.2018 23:07

            Дано я уже не видел объективной критики сишного синтаксиса. Кроме возврата указателя на функцию я вообще не видел ничего.

            Да пожалуйста.


            1. Оператор "запятая". Зачем она вообще нужна? Я не могу представить случая, где она была бы полезна. А вот ограничения на синтаксис при этом накладываются довольно сильные.


            2. Оператор switch крайне непродуман. Переход управления из одной ветви в другую — ситуация, которая случается крайне редко. Писать каждый раз break малость напрягает. Поэтому логичнее было бы от break полностью отказаться, а переход в следующую ветку реализовать через goto. Ну и группировать несколько подряд идущих case в один, указывая условия через запятую.


            3. Объявления типов с квалификаторами и слева, и справа — затруднение чтения кода. Я бы предпочёл, чтобы мухи (тип) и котлеты (объявление переменной) были отдельно: Type a, b;, причём указатели относятся к типу, а не к переменной, т.е. в объявлении int * a, b обе переменные будут должны тип int *. Объявление массивов фиксированного размера: int[10] a, а не int a[10].


            4. Про указатели на функции: аналогично п. 3. хотелось бы видеть что-то типа:
              int function(int, int) * variable_name вместо int (*variable_name)(int, int).


            5. Имена типов в виде крокодилов unsigned long long.


            6. [C++] Неоднозначности между определением функции и инициализацией объекта, костыль в виде двух видов записи вызова конструктора — с обычными и фигурными скобками.

            Нельзя. Именно для этого и существуют let-кастыли, т.к. выражение без типа — неоднозначно.

            Угу, в C++ это костыль в виде auto, именно потому, что обявление без типа не предусмотрено синтаксисом. Особенно смешно выглядят лямбды: [](auto x, auto y) { return x + y; }, когда можно было бы написать (x, y) -> x + y;


            1. khim
              02.03.2018 23:42
              +1

              Угу, в C++ это костыль в виде auto, именно потому, что обявление без типа не предусмотрено синтаксисом.
              Кому-то этого показалось мало. Теперь бывает не только auto, но еще и decltype(auto)!

              Кто из «знатоков» C++ способен пояснить где в функции foo — неопределённое поведение:
              decltype(auto) foo() {
                 int i = 1;
                 return (i);
              }
              И почему в функции bar его нету:
              decltype(auto) bar() {
                 int i = 1;
                 return i;
              }


              Кто не смог — сходите на godbolt

              Отличный язык, тщательно спроектированный для попадания в ногу…


            1. phponelove
              03.03.2018 01:28
              -1

              Да пожалуйста.

              Перво наперво — нужно осилить понятие «контекст», а уже потом приходить со своими пожалуйста. Но я помогу, контекстом был синтаксис описания типов, а не синтаксис вообще. Тем более, половина тут вообще не касается синтаксиса.

              Оператор «запятая». Зачем она вообще нужна? Я не могу представить случая, где она была бы полезна. А вот ограничения на синтаксис при этом накладываются довольно сильные.

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

              Оператор switch крайне непродуман.

              Продуман. Это банальная логика третий класс. Есть семантика перехода, есть переходы в свиче. Переходы не ограничены ничем.

              Переход управления из одной ветви в другую — ситуация, которая случается крайне редко.

              Каждая вторая — подобная ситуация.

              Ну и группировать несколько подряд идущих case в один, указывая условия через запятую.

              Т.е. для тех ситуаций, которых две строчки назад «крайне редко»? Сильно.

              Это итак работает. case: case: case: — сколько угодно.

              Объявления типов с квалификаторами и слева, и справа — затруднение чтения кода.

              Не объективно. Для меня затрудняет чтение обратное.

              Я бы предпочёл, чтобы мухи (тип) и котлеты (объявление переменной) были отдельно

              Это не критика. Меня мало должны волновать ваши предпочтения. Они так отдельно.

              обе переменные будут должны тип int *

              Как мне объявить int v, * p; в вашем супер-синтаксисе? Хотите ограничить типы — есть тайпдеф. Напишите там что угодно и это уже будет типов, а «составным типом».

              Объявление массивов фиксированного размера: int[10] a, а не int a[10].

              И? С каких пор «хочу» — стало критикой? [10] — это такое же свойство переменной. Хотите определить это на базе типа — есть тайпдефы.

              Про указатели на функции: аналогично п. 3. хотелось бы видеть что-то типа:

              Зачем нужно это «function» кастыльное непотребство? Мне не хотелось бы, дальше что?

              Имена типов в виде крокодилов unsigned long long.

              Есть тайпдефы, стандартизированные.

              [C++] Неоднозначности между определением функции и инициализацией объекта, костыль в виде двух видов записи вызова конструктора — с обычными и фигурными скобками.

              Нету никакой неоднозначности. Конструктор — это вызов функции. Другое дело, что на самом деле конструктор — инициализатор, а в си инициализатор {}. Поэтому всё вернулось на круги своя.

              Угу, в C++ это костыль в виде auto

              Это не костыль.

              именно потому, что обявление без типа не предусмотрено синтаксисом.

              Неверно. К синтаксису языка это не имеет никакого отношения — это фундаментальная неоднозначность между использованием и объявлением. И auto в С++ не кастыль, ведь синтаксис определения не изменяется. type var;, а вот в кастыльном var: type; — меняется, ведь нам нужно добавлять ненужность в виде let, как и ненужность в виде function/fn и прочего колхоза.

              Особенно смешно выглядят лямбды:

              Сишный синтаксис позволяет опускать типы, но в С++ как всегда — решили пойти своим путём.

              [](auto x, auto y) { return x + y; }, когда можно было бы написать (x, y) -> x + y;

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

              Почему вам «лишнее» слово тут «int function(int, int)» не мешает, а тут мешает? Вы уж там определитесь.

              А теперь [&]{ x += 1;}. Синтаксис намного мощнее, нежели эти хелворды.

              Тем более, этот синтаксис итак есть в крестах [](auto x, auto y) -> auto {}, только синтаксис крестов несоизмеримо мощней, нежели эти хелворды, которые вы пытаетесь выдать за синтаксис.

              Вы попробуйте облечь в них все те возможности, что есть в крестах. В этом проблема всех «критиков», помимо основной «я хочу так — это критика», — «я пащу левый синтаксис, который просто не может в ту семантику, которая существует в рамках крестов».


              1. DistortNeo
                03.03.2018 11:49
                +3

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

                Подобные однострочники нужно выжигать напалмом.


                Каждая вторая — подобная ситуация.

                Хм, видимо, вы программируете драйверы? Потому что в прикладном программировании я последние пару лет с такой ситуацией не сталкивался вообще.


                Как мне объявить int v, * p; в вашем супер-синтаксисе?

                Логично же:
                int v;
                int * p;


                И? С каких пор «хочу» — стало критикой? [10] — это такое же свойство переменной. Хотите определить это на базе типа — есть тайпдефы.

                Хочу — значит, что я критикую привязку свойств к переменной, а не к типу.
                И да, проблема в том, что typedef для массива — это фактически указатель.


                Зачем нужно это «function» кастыльное непотребство?

                Чтобы разделить тип и переменную, неужели не понятно?


                К синтаксису языка это не имеет никакого отношения — это фундаментальная неоднозначность между использованием и объявлением.

                Так может разрешить неоднозначность? Заодно и парсинг станет легче — в случае недостающей/лишней фигурной скобки ошибочное место станет легче искать.


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

                Самые частые лямбды — именно такие короткие, которые являются аргументами sort, map, reduce и т.д. А раздражают здесь слова auto и return, без которых можно было бы обойтись.


                Почему вам «лишнее» слово тут «int function(int, int)» не мешает, а тут мешает? Вы уж там определитесь.

                Потому что это определение функционального типа. Кстати, в C++ можно писать так: std::function<int(int, int)> — вполне удобно.


                В этом проблема всех «критиков», помимо основной «я хочу так — это критика», — «я пащу левый синтаксис, который просто не может в ту семантику, которая существует в рамках крестов».

                Просто я пишу ещё и на C# и вижу, насколько удобнее пользоваться шарповыми лябдами и делегатами.


          1. PsyHaSTe
            03.03.2018 17:42
            +2

            Это не имеет смысла, ведь работает подобное и в обратную сторону. Если привычный — не значит лучший, то и «не привычный» — не значит лучший, а значит подобные заявления друг друга компенсируют.

            У вас проблемы в логике, из A => B никак не следует, что !A => !B.
            Нельзя. Именно для этого и существуют let-кастыли, т.к. выражение без типа — неоднозначно.

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


        1. VulvarisMagistralis
          02.03.2018 12:45

          К тому же привычный — не значит лучший.


          Ну… Люди — многое делают по привычке столетиями.

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

          Цена использования этого метода для вас равна 0,01. А вот изучение нового, затем доведение до такого же автоматизма — это месяцы потерь.

          С учетом того, как многие вещи меняются в программировании шустро, лучше подумать сто раз, изучить отзывы коллег, чем тратить свое время на изучение очередной «серебрянной пули», которой как известно не существует (@Ф. Брукс)


      1. Fedcomp
        01.03.2018 01:42

        Если посмотреть историю, то изначально синтаксис смахивал на C. Значит в какой то момент поменяли и можно найти — почему.


      1. withkittens
        03.03.2018 03:01

        Скажу про переменные. В Rust let — это объявление не переменной, а привязки. Это имеет два последствия. Во-первых, доступен pattern matching и деструктурирование. Во-вторых, привязки могут быть переобъявлены.


        struct Foo(u32, u32);
        
        fn main() {
            let foo = Foo(2, 3);
            let Foo(a, b) = foo;
        
            assert_eq!(a, 2);
            assert_eq!(b, 3);
        
            let foo = "hello world";
        }


    1. sadpotato
      28.02.2018 22:00

      В рамках изучения языка написал «нейронку с умножением матриц, конволюцией и паралелизмом для CPU» для распознавания лиц: github.com/atomashpolskiy/rustface
      Производительность на 5-10% выше, чем на C++. Знающие люди подсказывают, что это в пррвую очередь благодаря более аггрессивным оптимизациям компилятора, который в Rust имеет точную информацию о том, где используется адресная арифметика (блоки unsafe): тема на reddit


      1. phponelove
        02.03.2018 10:20
        +1

        Производительность на 5-10% выше, чем на C++.

        Можно увидеть код на rust/C++, который сравнивается? А так же, желательно, код самого бенчмарка.


      1. VulvarisMagistralis
        02.03.2018 12:51
        +1

        Производительность на 5-10% выше, чем на C++


        Открыли Америку.

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

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

        В С++ слишком много автоматики, которая принимает решения просто так, на авось зачастую.

        Rust тем и отличается, что занудливо просит (нет, не так — требует даже) программиста уточнить намеряния.

        Эта требовательность Rust и позволяет произвести более глубокие оптимизации.

        Учитывая возраст C++ и возраст Rust — стоит ожидать только увеличения отрыва по мере оптимизации компилятора.


        1. Antervis
          02.03.2018 12:56
          -1

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

          В С++ слишком много автоматики, которая принимает решения просто так, на авось зачастую.

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

          Учитывая возраст C++ и возраст Rust — стоит ожидать только увеличения отрыва по мере оптимизации компилятора.

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


          1. VulvarisMagistralis
            02.03.2018 13:03
            +2

            «Автоматикой» пользоваться никто не заставляет, с++ всегда оставляет возможность сделать как минимум настолько же быстро, что и чистый си


            Ну да, а с ассемблерными вставками — еще быстрее.

            Мы не можем так говорить, как вы предлагаете. Так как это предполагает конкретного программиста, пишущего конкретную программу.

            Речь-то же об языке в целом.

            вы же понимаете, что почти все оптимизации в компилятор раста пришли из компиляторов тех же си/с++/фортрана?


            На низком уровне, например, как оптимизировать циклы или ветвления — да.
            На высоком — у разных языков свои особенности.

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

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


            1. Antervis
              02.03.2018 15:50

              Ну да, а с ассемблерными вставками — еще быстрее.

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

              Речь-то же об языке в целом.

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

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

              утечки — не самая хорошая альтернатива освобождению памяти


              1. VulvarisMagistralis
                02.03.2018 16:40
                +2

                утечки — не самая хорошая альтернатива освобождению памяти


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


                1. Antervis
                  02.03.2018 18:10
                  +1

                  я не спорю, что подобного рода оптимизаций может быть много. Давайте поставим вопрос иначе: что именно в расте позволяет проводить оптимизации аллокаций лучше, чем с++? Пока что я нашел лишь что в расте при OOM программа абортится


                1. 0xd34df00d
                  02.03.2018 20:22

                  В плюсах внезапно есть placement new, есть аллокаторы, и так далее.

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

                  Если бы я всё изначально писал на С, то я бы тоже, вероятно, пришёл бы к такому уровню производительности, но на разработку я бы потратил сильно больше времени.


              1. VulvarisMagistralis
                02.03.2018 17:27
                -2

                Нет такого понятия как «быстродействие языка», но можно оценить быстродействие инструментария.

                Строго говоря, язык программирования — это только синтаксис + API стандартной библиотеки.
                Но когда мы говорим «язык программирования» то подразумеваем, вестимо, и среду исполнения и компилятор и реализацию стандартной библиотеки, конечно.


        1. phponelove
          02.03.2018 13:31
          -1

          Открыли Америку.

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

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


          Действительно — С++ позволяет писать «как на си» и люди любят брать свойства этого «как на си» и натягивать на современные/новомодные С++-реалии. Именно на эту тему много спекуляций, но всё равно — формально это не так, и С++ действительно почти как си.

          А «чистый си» — это далеко не «быстрый си». Быстрый си почти никогда не бывает чистым.

          Rust тем и отличается, что занудливо просит (нет, не так — требует даже) программиста уточнить намеряния.

          Не видел ни единого проявления подобного поведения.

          Эта требовательность Rust и позволяет произвести более глубокие оптимизации.

          Есть примеры живые примеры?

          Учитывая возраст C++ и возраст Rust — стоит ожидать только увеличения отрыва по мере оптимизации компилятора.

          У раста нет компилятора — раст это фронтенд к крестовому llvm. И какие там вообще оптимизации на уровне фронтенда?

          А разрыва пока никто не показал.


          1. VulvarisMagistralis
            02.03.2018 13:39

            Действительно — С++ позволяет писать «как на си» и люди любят брать свойства этого «как на си» и натягивать на современные/новомодные С++-реалии. Именно на эту тему много спекуляций, но всё равно — формально это не так, и С++ действительно почти как си.


            С такой позиции мы будем обсуждать не язык, а конкретного программиста.

            У раста нет компилятора — раст это фронтенд к крестовому llvm. И какие там вообще оптимизации на уровне фронтенда?


            Например, по алгоритмам работы с памятью (стек, куча). До того как войдет в llvm


          1. VulvarisMagistralis
            02.03.2018 17:33

            Не видел ни единого проявления подобного поведения.

            Весь browning, к примеру.
            Понятно, что ради благого дела.


          1. PsyHaSTe
            02.03.2018 17:47
            +1

            Есть примеры живые примеры?

            Например вы можете получить две мутабельные ссылки и быть уверенным, что они указывают на разные объекты. Классический случай pointer aliasing'а. В плюсах есть костыль в виде__restrict__ , но компилятор никак не проверяет это, все на совести разработчика. Раст же не заставляет выбирать между производительностью и корректностью.


            1. phponelove
              03.03.2018 00:27
              -1

              Например вы можете получить две мутабельные ссылки и быть уверенным, что они указывают на разные объекты.

              И? Во-первых это попытка выдать ограничение за фичу.

              Во-вторых, алиаситься может не только мутабельное с мутабельным, а так же мутабельное с иммутабельным. Это подлог, либо явное непонимание темы.

              Второе, разные объекты ничего не значат. Ссылка на элемент массива и сам массив — являются разными объектами, но они алиасятся. Ссылка на поле и структура — так же. Я сомневаюсь, что нельзя взять ссылку на на поле, либо на елемент и что это идёт в счёт той самой «только одной» ссылки.

              Классический случай pointer aliasing'а.

              Для разных типов это итак не работает.

              В плюсах есть костыль в виде__restrict__

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

              но компилятор никак не проверяет это, все на совести разработчика.

              Продолжим, как вы ответите на мои вопросы. Но в любом случае — это невозможно.

              Раст же не заставляет выбирать между производительностью и корректностью.

              Это не производительность, даже близко. Люди, которые ничего о ней не знают — очень любят раст и порассуждать.

              Пруфы? Пожалуйста — начало ветки. У автора ансейф через ансейф. Где же мистическая «производительность без выбора»? Как только автор предоставит код — можно будет посмотреть, что именно там намерено и как. Уже потом можно будет и исходный крестовый код посмотреть. Пока что — тут рассуждать не о чём.

              Ещё пруфы? Пожалуйста, «предыдущая» тема про раст, которая касалась сравнения раста и С++. 72 плюса, 7 минусов и ноль сообщений о том, что это убогая клоунада, а не сравнение. Множество восторженных сообщений. Как вы это объясните?

              Нужны пруфы того, что это клоунада? Пожалуйста — habrahabr.ru/post/344282/#comment_10563198

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


              1. khim
                03.03.2018 01:53

                Во-вторых, алиаситься может не только мутабельное с мутабельным, а так же мутабельное с иммутабельным. Это подлог, либо явное непонимание темы.
                Ну да — вы «не понимаете тему», дальше что?

                Второе, разные объекты ничего не значат.
                В C/C++ — да.

                Ссылка на элемент массива и сам массив — являются разными объектами, но они алиасятся.
                И именно поэтому rust не даст вам передать в процедуру одновременно и ссылку на элемент массива и ссылку на массив.

                Я сомневаюсь, что нельзя взять ссылку на на поле, либо на елемент и что это идёт в счёт той самой «только одной» ссылки.
                А вы бы не сомневались, а почитали. «Живая» ссылка на любой элемент может быть одна и только одна. Что значит «живая» — описано в документации.

                Это, вообще говоря, сделано для безопасности — но ничто не мешает оптимизатору испольовать эту информацию и для чего-то ещё.

                Продолжим, как вы ответите на мои вопросы. Но в любом случае — это невозможно.
                Ага. Потому что земля плоская и стоит на трёх китах. Или черепахах?

                Это невозможно в C++, потому что там нет соотвествующих понятий. В rust — это возможно. Собственно это его основная фишка.

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

                Это не производительность, даже близко. Люди, которые ничего о ней не знают — очень любят раст и порассуждать.
                Где-то частица «не» пропущена. Ибо вы явно ненавидите rust, но берётесь о нём рассуждать не зная и не понимаю его. Типичное «Пастернака не читал, но осуждаю»…

                P.S. Я, кстати, не фанат rust'а. И я до сих пор не уверен, что в реальных проектах необходимость всё укладывать в «прокрустово ложе» borrow checker'а не приведёт к проблемам. Но я, в отличие от вас, хотя бы понимаю — чего в этом языке люди пытаются добиться и зачем.


                1. phponelove
                  03.03.2018 03:14
                  -1

                  Ну да — вы «не понимаете тему», дальше что?

                  Кроме трёпа ничего не будет, я правильно понимаю?

                  В C/C++ — да.

                  Неверно, это свойства базовой реальности. Почему вы проигнорировали это? Где ответы?

                  fn main() {
                  let s1 = String::from("hello");

                  let mut rs = &s1;
                  let mut len = calculate_length(&s1, &rs);
                  len = calculate_length(&s1, &s1) + len;
                  let mut slice = &s1[..3];

                  println!("The length of '{}' is {} is {} is {}.", s1, len, slice, rs);
                  }

                  fn calculate_length(mut s: &String, mut sl: &String) -> usize {
                  s.len() + sl.len()
                  }


                  Это что такое? Где вообще пруфцы от вас? Почему я вижу только ссылки на хрен пойми что в интернете и пустые заявления?

                  Это, вообще говоря, сделано для безопасности — но ничто не мешает оптимизатору испольовать эту информацию и для чего-то ещё.

                  Меня мало интересуют абстрактные обсуждения и ссылки на то, что «может быть». Я вам привёл свои рассуждения, которые вы никак не опровергли и начали ехать в сторону каких-то левых, не относящихся к теме, вещей.

                  И в инлайн и в статическую функцию в C++ могут придти пара указателей — и всё.

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

                  godbolt.org/g/V3KXCW — шлангу даже рестрикт не помог, а шансом 98% — это проблема в ллвм, в значит расту ничего не поможет.

                  Да, есть так нелюбимый вами __restrict__, но нет реальной культуры его применения.

                  Я уже сказал, что его нету. Культуры нет ни его применения, а написания производительного кода.

                  Где-то частица «не» пропущена. Ибо вы явно ненавидите rust, но берётесь о нём рассуждать не зная и не понимаю его. Типичное «Пастернака не читал, но осуждаю»…

                  Опять эти глупые попытки меня ловить. Меня мало волнуют ваши «явно» — я вижу ваш уровень, уровень раст-апологетов. Мне этого достаточно. Мнение о языка, о производительности тех, кто ничего в теме не понимает — меня волновать не должно.

                  А ненавижу я не раст, а рекламный булшит и балаболов.

                  И заметьте, я привёл чёткие причины моего недовольства — вы ответили что-то на них? Нет, вы всё неудобное вам игнорируете, занимаясь глупыми обвинениями. А чей-то трёп стоит ноль.

                  P.S. Я, кстати, не фанат rust'а.

                  Фанат. Без понимания чего-то лезть куда-то и что-то вещать — это типичная фанатичная глупость. Я где-то услышал какие-то лозунги — и пошел вещать об этом в комментах.

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

                  И я до сих пор не уверен, что в реальных проектах необходимость всё укладывать в «прокрустово ложе» borrow checker'а не приведёт к проблемам.

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

                  Да что там далеко ходить, оно даже слайс на константную(времени компилтайма) строку borrow checker'ом ловит. Колхоз колхоза.

                  Но я, в отличие от вас, хотя бы понимаю — чего в этом языке люди пытаются добиться и зачем.

                  Нет, вы не понимаете. И в этом проблема. Вы лезете в тему производительности, в тему лоулевел и С/С++, в которых ничего не понимаете. Как и все остальные адепты.

                  Хотите делать свои супер-языки? Делайте, но не лезьте в эти темы и не рассказывайте мне о том, что ваш колхоз хоть как-то заменяет С/С++.

                  А для чего мозилла производит этот хайповый булшит? График популярности броузеров за последние года — вам должен дать ответ на этот вопрос.

                  Почему весь хабр заспамлен этим булшитом? Пример я уже приводил(а вы его проигнорировали. Хотя это типичное, для вас, поведение). Всё просто — халявные инвайты, халявные плюсы. Пиши любую ахинею в рамках «руст так же быстр» — получай халяву от фанатиков.


                  1. khim
                    03.03.2018 04:13
                    +2

                    Это что такое?
                    Ну… я бы назвал это незнанием rust'а. Вы, в своём примере, наплодили миллион изменяемых ссылок на один неизменяемый обьект. Так как обьет неизменяем, то, разумеется, никаких проблем алиасинга нет и быть не может.

                    Чего вы этим хотите доказать и кому — я не знаю. Смею предположить, что вы просто не понимаете (или делаете вид, что не понимаете) в чём разница между mut s: &String и s : &mut String.

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

                    Я вам привёл свои рассуждения, которые вы никак не опровергли и начали ехать в сторону каких-то левых, не относящихся к теме, вещей.
                    Вы написали кучу бреда. А когда вас «припёрли к стенке» и потребовали конкретики — жидко обделались.

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

                    Ссылка на элемент массива и сам массив — являются разными объектами, но они алиасятся.
                    Однако использование этих ссылок — не является проблемой в случае, если обе ссылки указывают на неизменяемый объет. Что, собственно, в вашей программе и происходит.

                    Я сомневаюсь, что нельзя взять ссылку на на поле, либо на елемент и что это идёт в счёт той самой «только одной» ссылки.
                    Вы всё также не сделали то, что грозились сделать.

                    Так чего обсуждать-то?

                    godbolt.org/g/V3KXCW — шлангу даже рестрикт не помог, а шансом 98% — это проблема в ллвм, в значит расту ничего не поможет.
                    Не очень понятно что и как должен был помочь сделать __restrict__ в данном примере, так что неясно чего вы вообще тут пытаетесь доказать.

                    Да что там далеко ходить, оно даже слайс на константную(времени компилтайма) строку borrow checker'ом ловит.
                    Ещё одно невнятное утверждение, не имеющее смысла.

                    Вы хоть иногда пытаетесь за деревьями лес увидеть? Или только подгоняете примеры под нужные вам ответы не обращая внимание ни на что другое?


              1. mayorovp
                03.03.2018 09:50
                +1

                У автора ансейф через ансейф

                Шесть слов на весь проект. По сравнению с С++ — это очень мало (потому что в С++ весь код unsafe в понимании Rust)


        1. 0xd34df00d
          02.03.2018 20:18
          +2

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

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

          В С++ слишком много автоматики, которая принимает решения просто так, на авось зачастую.

          Можно пример таковой автоматики?


          1. DistortNeo
            02.03.2018 23:09

            и более строгой типизации.

            А можете пояснить, в чём заключается строгость типизации C++ по сравнению с C?


            1. 0xd34df00d
              03.03.2018 00:34

              Автоматически приводится меньше вещей, есть отдельные static/dynamic/const/reinterpret_cast (так что сразу видно, что каст делает), проще написать свои обёртки вроде всяких not_null/optional/what_not, которые читающему сразу что-нибудь хорошее расскажут про инварианты.


              1. DistortNeo
                03.03.2018 12:29

                Ну это если действительно писать на С++, а не на С с классами.


  1. gro
    28.02.2018 22:28
    +1

    Я, к сожалению, очень слабо во всём этом разбираюсь. Единственный вопрос: чего было такого в древнем Си по стравнению с Турбопаскалем в плане выделения памяти?


    1. smer44
      28.02.2018 23:26

      турбопаскаль был уродливым детищем чисто для ДОСа с его особенностями памяти а так лично мне просто синтаксис паскаля не нравился. ух как народ взбесился из за поста, посмотрю че за проэкты и заодно ознакомлюсь с языком.
      почему написал про API и DSL, например «сравнивать грёбаные строки» в производительном коде не надо так как сравнение по всей строке долго и заместо этого юзаем просто тип или enum или обходимся вообще без свича.
      а с каким кодом С++ вы сравниваете, этот ваш раст может компилить в sse инструкции или в несколько ядер, как это прописывается в языке?


      1. broken
        01.03.2018 08:10

        Rust использует llvm, как и clang, который транслирует в него си, плюсы и обжси. Вопрос снят?


    1. Zloboglaz
      01.03.2018 12:31

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


  1. VadimVP
    28.02.2018 23:38

    автор книги «Язык программирования Rust»

    Товарищ Федерико автором книги не является, и соответственно во это


    Я ещё не закончил работу над главой о «бесстрашном параллелизме»

    тоже интерпретировано неверно. Он имеет в виду что c многопоточностью в Rust еще не работал, а не то что главу не дописал.


  1. alex-pat
    01.03.2018 08:53

    Нет целочисленного переполнения
    Сказано достаточно.

    Хочу уточнить: переполнения проверяются при компиляции на debug, в release этого нет, ибо оверхед.


  1. RomanArzumanyan
    01.03.2018 12:00

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


    Очень странно слышать подобные вещи из уст опытного разработчика на С. Как будто о вызове по указателю он никогда не слышал.


    1. khim
      01.03.2018 15:03

      Откуда указатель возьмётся? Самозародится в тесте?


      1. RomanArzumanyan
        01.03.2018 16:09

        В контексте ООП на С, статические функции используются в качестве замены методов класса. Указатели на них берутся в тех функциях, которые генерируют структуры. Например, вот так:

        --my.h--
        typedef struct My
        {
        	int param;
        	void (*setParam)(struct My *self, int new_param);
        } My;
        
        My* MakeMy();
        
        --my.c--
        #include "my.h"
        
        static void My_setParam(My *self, int new_param)
        {
        	if(self)
        		*self->param = new_param;
        }
        
        My* MakeMy()
        {
        	My *self = (My*)calloc(1, sizeof(*self));
        	if(self) {
        		self->setParam = My_setParam;
        		return self;
        	}
        	
        	return 0x0;
        }
        
        --test.c--
        #include "my.h"
        
        int main()
        {
        	My *dummy_struct = MakeMy();
        	dummy_struct->setParam(10500);
        	
        	if(dummy_struct->param != 100500)
        		return 1;
        	else
        		return 0;
        }


        1. mayorovp
          01.03.2018 16:15
          +1

          Ошибочка: вместо dummy_struct->setParam(10500); должно быть dummy_struct->setParam(dummy_struct, 10500);


          1. RomanArzumanyan
            01.03.2018 16:16

            Да, вы правы. Забыл передать self.


        1. khim
          02.03.2018 17:23
          +2

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


  1. AlexPublic
    01.03.2018 13:55
    -3

    Смешная статья. 99% перечисленных вкусностей Rust'а имеются в C++, причём большинство уже очень давно. Если автору так это всё нравится, то совершенно непонятно где он был все эти годы — на другой планете, где нет C++?

    И да, у Rust'а имеется ряд преимуществ над C++. Это и более строгая работа с памятью и нормальное метапрограммирование (а не корявые вычисления на шаблонах) и т.п. Но про это в статье нет ни одного слова…


  1. Bismuth208
    01.03.2018 13:58

    Хм, все что вы описали есть в D. Есть Unit тесты, есть GC. На слайсы(slices) так вообще сделан большой упор. Весьма приятный синтаксис после C и C++. Максросы да, в С это опасное зло в неумелых руках. Их нет в D, но есть альтернативы, которые выглядят куда лаконичнее. Управление зависимостями сделано в DUB. Может Вам стоит рассмотреть и его?

    p.s. я знаю про вечный спор о Rust vs D.


    1. khim
      01.03.2018 15:08
      +3

      p.s. я знаю про вечный спор о Rust vs D.
      Не знаю ни о каком «вечном споре». Знаю что rust не пошёл на поводу у моды и вся его библиотека — работоспособна без всякого GC, что ставит его в один ряд с Pascal'ем, C, C++… и в другой класс, нежели D, Go, Java.

      Или сейчас у них уже есть не только громкие заявляения о том, что GC можно выключить, но это реально можно сделать?


  1. VulvarisMagistralis
    02.03.2018 12:40
    -3

    80% того, чего автору не хватает в С — отлично и безкомпромиссно компенсируется библиотеками.
    Ну например, про срезы строк — это просто смешная претензия, пока писал этот текст, уже мысленно набрасал решение. Причем, что и делать-то самому ничего не нужно. Это уже написано до вас. Нужно просто приучиться пользоваться определенным набором любимых библиотек.


    1. mayorovp
      02.03.2018 13:21
      +1

      Автоматическое управление ресурсами никакой библиотекой компенсировать невозможно, это может быть только свойство языка.

      Обобщённые типы без проседания производительности на Сях могут быть достигнуты только магией макросов. Но даже такое решение не позволит использовать типажи.

      Замыкания — это по определению элемент языка, в Си его просто нет.

      Что осталось-то?


      1. 0xd34df00d
        02.03.2018 20:24

        Автоматическое управление ресурсами никакой библиотекой компенсировать невозможно, это может быть только свойство языка.

        У меня, кстати, есть впечатление, что линейные типы могут быть выражены библиотечно через завтипы. Но я пока эту тему особо плотно не ковырял.


    1. nexmean
      02.03.2018 13:22
      +1

      80% это всё же не 100%. А главных фич Rust(семантика перемещения, borrow checker, lifetimes, отсутствие UB за пределами синтаксически выделенных участков кода, параметрический полиморфизм, явное приведение типов) в C нет и никакими библиотеками их не прикрутить. А если и прикрутить чем-то, то выйдет в любом случае коряво. Ну и зачем тогда это всё когда есть Rust? Только ради тех, кому лень в течении месяца по несколько часов в неделю тратить на изучение другого ЯП?


      1. VulvarisMagistralis
        02.03.2018 15:40
        -1

        А главных фич


        Почему в сравнении языков всегда всплывает этот бред?
        Разумеется языки разные.
        И ожидать от одного почти полного повторения того, что есть в другом — глупо.
        Делать язык «точно такой же как С, только синенький» тоже глупо. Языки должны быть сильно разные, чтобы можно было приложить значительные усилия к его развитию.


        1. mayorovp
          02.03.2018 16:07
          +1

          Напомню ваши слова:


          80% того, чего автору не хватает в С — отлично и безкомпромиссно компенсируется библиотеками.

          Так вот, автору не хватает именно фич языка! Которых в Си просто нет. И не будет. Именно потому что языки разные.