На днях прошла встреча международного комитета по стандартизации C++ в американском городе Кона. Это была не просто встреча, а feature freeze! Никакие серьёзные новые идеи больше не могут просачиваться в стандарт, остаётся лишь пара встреч на добавление предварительно одобренных вещей, исправление недочётов и устранение шероховатостей.

Ожидать ли Модули и Корутины в C++20, будет ли там быстрая библиотека для форматирования вывода, сможет ли она работать с календарями, добавили ли std::stacktrace, начнёт ли компилятор сам вызывать std::move в ряде случаев, приняли ли std::flat_map? Всё это и многое другое ожидает вас под катом.



Coroutines TS


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

Выбор был не простой, у каждого подхода есть свои минусы и плюсы:

  • N4775:
    • + нет ограничений на то, что сопрограммы должны быть описаны в заголовочном файле
    • ? нет строгих гарантий, что не произойдёт динамическая аллокация
    • ± не самый простой интерфейс (P1477R0 это исправляет)
    • ? страшненькие ключевые слова co_await и co_yield (предложение P1485R0 от РГ21 это исправляет)
    • + 3 года применяются на практике

  • P1063R2:
    • + нет динамических аллокаций
    • ? сопрограммы должны быть описаны в заголовочном файле или самим надо хитровыкручиваться с type erasure
    • ? ещё более страшные ключевые operator[<-] и [->]
    • ? нет рабочего прототипа
    • ? не самый простой интерфейс для создания асинхронных вещей

  • P1430R0:
    • + нет динамических аллокаций
    • ? сопрограммы должны быть описаны в заголовочном файле или самим надо хитро выкручиваться с type erasure
    • + нет страшных ключевых слов, всё гладенько
    • + пользователи корутин не видят страшных корутиновых внутренностей (даже не видят co_await аналогов, всё из коробки работает)
    • ? первое предложение, ни разу не обсуждалось, требует кучи доработок
    • ? невозможно реализовать на текущих технологиях (требуют поддержки структур динамического размера), требуют огромных трудозатрат для реализации
    • ± немного напоминают лапшу из callback


После долгих дебатов сопрограммы были приняты в C++20 в том виде, в котором они были в Coroutines TS (с co_* префиксами и старыми точками кастомизации).

Modules


На обсуждение модулей повлиял один интересный документ с замерами производительности:
P1441R0. Трактовать результаты можно по разному: от «существующие системы сборки и реализация модулей ещё недостаточно оптимизированы» до «модули плохо масштабируются с ростом сложности проекта».

Помимо этого документа, комитет обсудил ряд небольших правок к текущим модулям. В итоге, спустя 15 лет обсуждения, прототипирования и экспериментов с внедрениями, модули были приняты в C++20.

Format


Good news everyone! Если не найдут фатальных недостатков в подгруппе Library, то в C++20 можно будет безопасно и очень быстро форматировать строки. Скажите «до свидания» std::ios, std::locale и прочим ужасам 90-х! Теперь Python подобный синтаксис для форматирования доступен из коробки в С++: P0645R5.

Более того, было принято предложение на интеграцию нового форматирования и календарных времён P1361R0. Если всё пойдёт по плану, то и даты можно будет выводить по-человечески!

Networking, Executors и Properties


Executors являются важным кирпичиком для поддержки Networking в C++ из коробки. Для Executors нужны Properties — возможность модифицировать тип данных, в зависимости от параметра переданного на этапе компиляции, не меняя концепт типа.

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

В итоге решено было Properties включать в язык только в C++23, а соответственно и Executors, и Networking в C++20 не появятся.

Прочее


В черновик C++20 уже были внесены следующие изменения:

  • Структуры без конструкторов (агрегаты) теперь можно инициализировать, используя круглые скобки P0960. На практике это значит, что теперь std::make_shared, std::make_unique, std::*::emplace* будут корректно работать с агрегатами без ошибок компиляции
  • Были добавлены функции lerp для линейной интерполяции P0811
  • Добавлена возможность векторизировать алгоритмы стандартной библиотеки P1001
  • Методы std::span теперь возвращают беззнаковые типы (по аналогии со всей стандартной библиотекой) + была добавлена функция std::ssize для получения размера контейнера в виде знакового числа P1227
  • Unordered контейнеры научились искать значения, используя заранее посчитанный хеш P0920

Много других вещей ожидают финального ревью в подгруппах Library и Core, для включения в C++20:

  • Эффективное ожидание на std::atomic; классы семафоров и барьеров P1135
  • std::flat_map P0429
  • std::flat_set P1222
  • std::function_ref P0792
  • constexpr для <cmath> и <cstdlib> P0533
  • std::ranges::to<любой-контейнер> для сохранения диапазона значений в контейнер P1206
  • Возможность эффективно извлекать строки из std::*stringstream и передавать во владение пользовательские строки P0408
  • Множественные правки для operator<=>, ranges, constexpr

Заслуги РГ21


В самый первый день за горячо любимое в Яндекс.Такси предложение на Stacktrace P0881R3 взялась подгруппа Core. Замечания по дизайну были дополнительно обсуждены в подгруппе LEWG, ещё раз проработаны в Core. В итоге в течении всей недели вносились правки и велись обсуждения. В черновик стандарта предложение ещё не включено, но должно оказаться в C++20 (если не найдут вдруг какой-то фатальный недостаток).

До обсуждения нашей идеи P1485R0 на приведение ключевых слов для корутин дело не дошло.

Также в SG1 Concurrency обсуждали идею concurrent unordered map P0652R2. Нас попросили перепроверить, что предложенное API позволяет избежать reader contention. Также сказали поисследовать concurrent unordered контейнеры, которые не имеют функции erase и не защищают значение контейнера от конкурентной модификации.

Предложение от ZaMaZaN4iK на специализацию std::hash для различных классов стандартной библиотеки P1406R0 решено было сильно порезать. Комитет порекомендовал оставить специализации только для std::pair, std::tuple, std::array и std::basic_string от пользовательских аллокаторов.

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

Также обсуждали наши незначительные предложения, включая feature testing macro P1424R0 и политики на их добавление в стандарт.

Быстро обсудили нашу идею, позволяющую компилятору убирать лишние копирования R0889R1. Нам сказали продолжать работу в этом направлении и накидали примеров, которые не должны ломаться с новыми правилами.

Вместо итогов


C++20 будет так же разительно отличаться от C++17, как С++11 отличался от C++03. Огромное количество новых технологий и новых парадигм: Concepts, Contracts, Ranges, Modules, Coroutines, constexpr контейнеры и constexpr динамический полиморфизм, «ниблойды» и т. д.

В скором времени мы, Рабочая Группа 21, отправим комментарии к черновику стандарта C++20. Поэтому, если у вас есть какая-то боль или вы не согласны с каким-то нововведением, пожалуйста, оставляйте свои мысли на этой странице.

Следующее собрание международного комитета будет летом, на нём могут начать рассматривать нововведения для C++23. Если вы хотите что-то изменить в C++ или предложить свою идею, то всегда можете написать на https://stdcpp.ru/, где люди из РГ21 помогут вам донести ваши желания до комитета.

Желаете поговорить с нами вживую? Скоро состоится открытая встреча РГ21, следите за анонсами на events.yandex.ru. Так же ищите нас на апрельской конференции C++ Russia в Москве.

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


  1. denaspireone
    06.03.2019 10:59
    +2

    Clickhouse станет еще быстрее? ;)
    PS: go девелоперы всплакнули…


    1. antoshkka Автор
      06.03.2019 11:27

      Станет :) В стандарте немного подкрутили правила для типов и улучшили стандартную библиотеку. Так что компиляторы смогут оптимизировать ещё чуточку лучше.

      А вот GO разработчикам ещё рано плакать — корутины приняли, но в стандартной библиотеке нет готовых классов для их использования. Придётся первое время писать всё самим, так что C++ тут пока отстаёт от GO. (Но мне по секрету сказали, что постараются добавить необходимые классы в std::experimental в очень скором времени, ещё до C++23).


    1. creker
      07.03.2019 00:27
      -2

      Плакать скорее хочется от того, как жутко выглядит код с корутинами. Да и совершенно непонятно, как это все будет исполняться, ни в одном документе из трех нет подробностей — будет это типичный в основном однопоточный async/await для асинхронности как в C#, т.е. распиленный на теже самые колбэки код, но с видом сбоку, или будет полноценная многозадачность с планировщиком как в Go. Даже первое конечно сильно лучше текущего положения дел, но, имея опыт работы с C# и С++ async/await из UWP, принципиально это ситуацию не улучшает. Мало мальски сложный C# код обрастает кучей костылей и не очевидного поведения. C++ так вообще превращается в страшный ужас даже на простом коде. Так что Go можно спать спокойно, ничего близко по удобству работы с конкурентным кодом не предвидится. Тем более что сам подход принципиально другой с зелеными потоками.


      1. arseny30
        07.03.2019 09:13

        А можете раскрыть мысль? Да, корутины будут stackless. Да, это просто хитрое преобразование кода. Но почему это мешает использовать их в многопоточном коде?

        Да даже семантику Go должно быть несложно воспроизвести на основе новых корутин.


        1. creker
          07.03.2019 11:43
          +1

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

          Да даже семантику Go должно быть несложно воспроизвести на основе новых корутин.

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


          1. DistortNeo
            07.03.2019 12:22

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

            Всё зависит от планировщика. Вам ничто не мешает написать свой планировщик, который будет действительно однопоточным и работать с iocp/epoll. Я уже писал такое в качестве эксперимента — разгонялся до миллиона IOPS, так что уверен, что механизм рабочий и жизнеспособный. Единственное — пришлось отказаться от штатных Socket и Delay и заменить их своими реализациями.


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

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


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

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


            Сложно. Go это сложный и умный рантайм, без которого вся эта семантика коту под хвост.

            Сложно — не значит невозможно.


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

            Так это принципиально разные вещи. Вытесняющая многозадачность — это обычное параллельное выполнение задач на пуле потоков. Как раз тот сценарий, от которого Go пытался избавиться за счёт горутин и планирования в userspace.


          1. antoshkka Автор
            07.03.2019 12:35
            +1

            Корутины в C++20 нисколько не противятся многопоточности. Можно посмотреть например на мини туториал, и запустить writerQueue.Run(); из нескольких потоков.

            Подход корутин в C++20 и правда отличается от Gо. При этом корутины С++20 позволяют полностью избегать динамических аллокаций (или позволяют использовать свои хитрые аллокаторы) и не требуют GC.

            Подход со stackfull корутинами всё ещё валиден в C++. Например мы в Yandex.Taxi его реализовали и успешно используем. Достигли такого же удобства как и в Go (опять таки без всякого GC). И не мы одни такие, есть пяток опенсорсных движков от крупных компаний, реализующих те же идеи.


            1. Andruh
              07.03.2019 14:31

              А можно названия опенсорсных движков? Очень интересно поглядеть.


              1. antoshkka Автор
                07.03.2019 14:39

                1. Andruh
                  07.03.2019 17:00

                  Спасибо. Нашёл ещё github.com/facebook/folly/tree/master/folly/fibers.
                  Я темой корутин интересовался давно — в 2008-м писал eDonkey-клиента на IOCP (правда там не корутины, а callback hell, но вобщем понятно), в 2013 написал свой фреймворк поверх бустовых корутин, включавший собственный корутиновый http-клиент. Потом забросил, а недавно обнаружил boost::fibers. Хочется разобраться во всём современном зоопарке, поэтому и интересно найти максимум библиотек на эту тему.


      1. DistortNeo
        07.03.2019 11:41

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

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


        1. creker
          07.03.2019 11:50
          +1

          Это совсем несложно

          Конечно. Почитайте на досуге райнтам Go. Всего-то годы работы первоклассных инженеров, которые до сих пор вылавливают неочевидные кейсы, которые возникают в high-load проектах.


          1. DistortNeo
            07.03.2019 12:32
            +1

            Написать однопоточный планировщик "зелёных" потоков на C++, который будет уметь работать с таймером и сокетами, и при этом иметь прекрасную производительность (держать десятки тысяч соединений и не тупить) — это действительно несложно, на него нужно потратить пару дней — сужу по своему опыту, т.к. писал его в качестве разминки для мозгов.


            А вот написать масштабируемый на несколько потоков планировщик, да ещё и определёнными потребностями со стороны HighLoad — это действительно сложно.


            P.S. Опыт также показывает, что написание велосипеда для решения конкретной задачи оказывается эффективнее, чем использование универсального решения. В HighLoad и не так заморачиваются.


      1. mayorovp
        07.03.2019 12:51

        Насколько я помню, вся «полноценная многозадачность» в Go заканчивается при любом интеропе или системном вызове.

        Для такого языка как C++ такой вариант просто недопустим.


  1. justru
    06.03.2019 11:17
    -9

    Все программисты на C++ уже вымерли, остался лишь кружок «в американском городе Кона»


    1. TargetSan
      06.03.2019 12:25
      +11

      Скажите это Autodesk, Dassault Systemes, PTC, Siemens. Посмеёмся вместе.


      1. antoshkka Автор
        06.03.2019 12:40
        +13

        Ещё можно сказать это Yandex, Yandex.Taxi, Google, Facebook, 95% игровых движков, Microsoft, Apple, всем современным автомобильным производителям, Лаборатории Касперского, Bloomberg и остальным HFT компаниям, CERN, IBM, Intel, всем производителям браузеров…


    1. KanuTaH
      06.03.2019 22:19
      +1

      octoverse.github.com/projects#languages

      Ну а так-то да, «азаза затралено».


  1. youROCK
    06.03.2019 11:54

    Мне кажется, уже давно настал момент, когда пора выделить "хороший и современный" кусок C++ в отдельный язык (назвать его C++ Lite, например), потому что в противном случае изучить C++ новичку будет в скором времени уже практически невозможно :).


    1. NeoCode
      06.03.2019 12:02

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


      1. antoshkka Автор
        06.03.2019 12:11

        Это частично исправляют Concepts — с ними можно забыть о страшных std::enable_if и прочем SFINAE.

        Полный фикс, с человеческой кодогенерацией, подоспеет вместе с Reflections TS.


    1. kITerE
      06.03.2019 12:54
      +5

      Это уже сделано, просто нужно придерживаться C++ Core Guidelines (анонс был еще в сентябре 2015).


    1. Overlordff
      06.03.2019 13:19
      -1

      -


    1. aslepov78
      06.03.2019 21:49
      +1

      Шаблоны — мощь С++, она же боль.


  1. pvsur
    06.03.2019 11:59

    Блин, хотел переползать на RUST потихоньку, а тут вкусняшки :)


    1. antoshkka Автор
      06.03.2019 12:23
      +2

      Мне в комитете сказали, что я ещё стал разработчиком Rust, сам того не зная.

      Сейчас в Rust думают на корутинами, и их очень сильно смущает выбор C++ со страшными ключевыми словами co_await/co_yield. Моё предложение на нормальные ключевые слова их очень сильно заинтересовало, они ждут развития событий. Как комитет по C++ решит, какие выводы сделает — на основе этого Rust будет решать, как делать у себя.


      1. TargetSan
        06.03.2019 12:31

        У Rust есть вариант сделать атрибут #[async] вместо полноценного кейворда и, как результат, получить кейворд await! в виде контекстного макроса.


        Кстати, почему действительно не использовать атрибуты?


        [[async]] future<int> somefunc() { ... }


        1. antoshkka Автор
          06.03.2019 12:54

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

          struct y?ield{};
          struct a?wait{};
          struct async{};
          
          template <class T>
          future<int> some_coro() async {
              await something;     // Аналог co_await из Coroutines TS
              yield something2;    // Аналог  co_yield из Coroutines TS
              async something3;    // OK
              return something3;   // Аналог  co_return из Coroutines TS
          }


        1. Antervis
          06.03.2019 12:58
          +4

          Кстати, почему действительно не использовать атрибуты?

          потому что All attributes unknown to an implementation are ignored without causing an error (since c++17). В данном случае нужен механизм, гарантирующий определенное поведение


          1. TargetSan
            06.03.2019 13:27
            +1

            Вот это поворот… Интересно, когда получим "any textual string is a valud program in C++".


      1. humbug
        06.03.2019 13:57
        +9

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

        А пацаны-то и не знают.


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


        И async/await давно можно пользоваться, например, для описания комбинаторов. Но почему-то ждут, как же сделают в С++.


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


        1. antoshkka Автор
          06.03.2019 14:06
          +1

          1. humbug
            06.03.2019 14:12
            +2

            пересказываю услышанное; не ручаюсь за достоверность.

            Не ручаетесь за достоверность? Оукей.


        1. antoshkka Автор
          06.03.2019 14:15
          +1

          Ну и «Requirements Rust nightly-2019-02-19 for async_await, await_macro» по той ссылке что вы кинули как бы намекает, что вы тоже не сильно в теме готовности этого решения.

          Эти ключевые слова уже высечены в камне для Rust, или всё ещё может поменяться?


          1. humbug
            06.03.2019 14:22
            +3

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

            Аккаунт https://github.com/kpp связан с https://habr.com/en/users/humbug/. Та либа лежит в репе https://github.com/kpp/futures-async-combinators, из чего следует, что вы говорите с автором библиотеки. Внимательнее надо быть ;)


            1. antoshkka Автор
              06.03.2019 14:26
              +2

              Спасибо, впредь буду внимательнее


          1. humbug
            06.03.2019 14:54
            +3

            Эти ключевые слова уже высечены в камне для Rust, или всё ещё может поменяться?

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


            Другое дело, что решения Rust с корутинами сильно отличаются безопасностью.


            Например, в предложенном варианте N4775 есть такая фраза:


            [Note: If a coroutine has aparameter passed by reference, resuming the coroutine after the lifetime of the entity referred toby that parameter has ended is likely to result in undefined behavior.— end note]

            Rust тоже столкнулся с таким вопросом, но было предложено безопасное решение (без UB, без проверок в рантайме, полностью zero-cost и без пенальти) в цикле статей:


            Async/Await I: Self-Referential Structs
            Async/Await II: Narrowing the Scope of the Problem
            Async/Await III: Moving Forward with Something Shippable
            Async/Await IV: An Even Better Proposal.


            И таки теперь это решение в стабильной версии компилятора. И естественно на нем основываются генераторы и async/await. Ну круто же? =)


            1. antoshkka Автор
              06.03.2019 15:22
              +5

              Да, с безопасностью в Rust очень круто! С этим спорить бесмысленно


            1. naething
              06.03.2019 21:25

              Ну круто же?
              Круто, что быстро запилили (и мы уже активно используем), но вот сам механизм pin/unpin довольно сложный для понимания на мой взгляд, и большинство реализаций «стандартных» комбинаторов требуют unsafe (пример)

              До этого комбинаторы были проще внутри.


              1. PsyHaSTe
                07.03.2019 14:18

                Pin/Unpin все-таки костыль, который позволяет добавить механизм «после активации перемещать низя». Сделать красиво и удобно можно было бы, но пришлось бы пересматривать все основы, то есть менять борроучекер и его правила, на что авторы языка не готовы были пойти.


                1. khim
                  07.03.2019 15:22

                  Могут попробовать во второй версии языка исправить.

                  Вообще самая большая проблема C++, которая была до сих — отсуствие модулей.

                  Потому что из-за их отсутствия код «чужой» библиотеки вставлялся прямо в «новый» код через #include. То есть совместимость требовалась полная — вплоть до C++98.

                  Вроде rust может себе позволить развести разные «правила игры» в разных модулях, так что в версии 2 могут и исправить правила борроучекера… Не знаю пока C++23 (и последующих) — можно ли там будет такие вещи делать…


            1. 0xtcnonr
              07.03.2019 08:28
              +1

              И таки теперь это решение в стабильной версии компилятора.

              В чём смысл достижения? Это банальность банальная — константный указатель. К тому же, в ситуации с C++ — это вообще ненужно, т.к. ссылка итак pinned. Это какая-то борьба с расто-проблемами не актуальными в С++? Или это действительно такая наивность?

              К тому же, это никак не решает проблему времени жизни — если локальный сторедж для объекта умрёт — объект умрёт. А временем жизни этого стореджа — управлять нельзя. Управлять временем жизни можно только в глобальном сторедже — т.е. в хипе. А это уже оверхед и подобные рассуждения:

              без UB, без проверок в рантайме, полностью zero-cost и без пенальти)

              По умолчанию являются несостоятельными.

              К тому же, все всегда забывают, что «ограничение» — есть оверхед и никакого zero-cost уже нет. Допустим, если мы вводим ограничение на кол-во мутабельных ссылок — это уже оверхед и не zero-cost и любые попытки назвать это zero-cost — враньё и манипуляции.

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


              1. humbug
                07.03.2019 11:17
                +2

                Я тут немного полазил по вашим комментариям. Давайте я раскрою вам глаза на происходящее =)


                Да, настоящее время раст имеет ровно один компилятор — но это не значит, что так будет всегда.
                Какая глупость. (автор этих слов 0xtcnonr)

                Компиляторов уже два. Посмотрите на https://github.com/thepowersgang/mrustc, пару месяцев назад проскальзывала статья, как они забутстраппились.


                К тому же, это никак не решает проблему времени жизни — если локальный сторедж для объекта умрёт — объект умрёт. А временем жизни этого стореджа — управлять нельзя. Управлять временем жизни можно только в глобальном сторедже — т.е. в хипе.

                А вы уверены, что вы правильно поняли семантику Rust? В С++ время жизни — это рантаймовое свойство, тогда как в Rust это статическое свойство, известное на этапе компиляции. Стораджей-ссылок нет.


                К тому же, все всегда забывают, что «ограничение» — есть оверхед

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


                Допустим, если мы вводим ограничение на кол-во мутабельных ссылок — это уже оверхед и не zero-cost и любые попытки назвать это zero-cost — враньё и манипуляции.

                И так как время жизни в Rust — это статическое свойство, известное на этапе компиляции, подсчет кол-ва мутабельных/иммутабельных ссылок стоит ровным ничего(прямо как С++ шаблоны), компилятор может сделать вывод о том, будет ли объект, на который ссылается ссылка, жить достаточно, чтобы замыкание/корутина/тред могли использовать ссылку или нет.


                В чём смысл достижения? Это банальность банальная — константный указатель. К тому же, в ситуации с C++ — это вообще ненужно, т.к. ссылка итак pinned. Это какая-то борьба с расто-проблемами не актуальными в С++?

                В Раст существует настоящая мув-семантика, например:


                fn main() {
                    let b = String::from("Hello world!");
                    let a = b; // Перемещение
                    println!("a = {}", a);
                }

                После перемещения обращаться к b переменной нельзя. Она исчезла, переместилась, ее больше нет. Это сделано специально, чтобы избежать неопределенного поведения, присущего С++:


                std::vector<std::string> v;
                std::string str = "example";
                v.push_back(std::move(str)); // str is now valid but unspecified
                str.back(); // undefined behavior if size() == 0: back() has a precondition !empty()

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


                • Если это самоссылающаяся структура на стеке, то ее нельзя перемещать. Пользоваться такой корутиной можно, но локально. Ее можно создать на стеке, но нельзя возвращать из функции и нельзя перекидывать в другую переменную по типу let a = b. За этими нельзя следит компилятор без пенальти для рантайма, без UB, полностью zero-cost.
                • Но можно создать самоссылающуюся структуру в хипе и, как вы правильно заметили, перемещать константный указатель без перемещения содержимого. Это вариант с пенальти по хипу.

                В Rust реализовали оба, пользуйся любым.


                Почитайте статьи, это действительно увлекательное чтиво.


                Async/Await I: Self-Referential Structs
                Async/Await II: Narrowing the Scope of the Problem
                Async/Await III: Moving Forward with Something Shippable
                Async/Await IV: An Even Better Proposal


                В чём смысл достижения?

                std::pin — это возможность дать компилятору инфу о том, можно ли перемещать объект или нет. Т.е. история с "переместить стековую корутину нельзя, а хиповую можно" было описано чисто языковыми средствами, а не захардкожено в компиляторе.


                Не стесняйтесь обращаться по непонятным раст вопросам в комменты, ко мне в личку, или в гиттер сообщества https://gitter.im/ruRust/general. Тепло встретят, помогут, подскажут, разжуют, объяснят. Без смс и без регистрации =)


                1. Halt
                  07.03.2019 11:39
                  +2

                  Компиляторов уже два. Посмотрите на github.com/thepowersgang/mrustc, пару месяцев назад проскальзывала статья, как они забутстраппились.
                  Я бы еще добавил парсеры IntelliJ Rust и rust-analyzer, которые по уровню «понимания материала» постепенно приближаются к компиляторам. Разве-что, код генерировать не умеют, хотя последний, на минуточку, метит в сторону замены собой основного фронтенда языка, что как бы намекает.

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

                  Итого 4.


                  1. 0xtcnonr
                    07.03.2019 17:48
                    -3

                    А вот и пошла типичная подмена понятий, адепты выдумывают новые значения понятия «компилятор».

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

                    Один тезис нелепей другого. У нас есть 4 компилятора, каждый «сложнее» кодогена и оптимизатора, т.е. llvm«а, но почему-то без llvm»а никуда? Как же так? Неужели опять путаница в показаниях? Какая досада.

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

                    К тому же, мы тут видим очередную попытку врать и игнорировать контекст от адептов. О чём говорилось там? О кол-ве таргетов и о том, что у раста нет компилятора на расте и он зависит от С/С++ и в компилтайме и в рантайме.

                    Что же нам предлагают адепты?

                    IntelliJ Rust и rust-analyzer,

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

                    mrustc, rustc

                    Первый вообще целиком и полностью на С++ и имеет его© в качестве таргета, второй генерирует llvm-ir при помощи llvm-рантайма.

                    И того, кол-во реальных таргетов равно нулю. Количество компиляторов — равно нулю. Есть два транслятора — rust -> ir, rust -> С, к тому же второй не является полноценным(т.з. базовой методички, ведь (i.e. without borrow checking)).

                    Итого 4.

                    Главное верить, врать и плюсовать друг друга. В этом сила.


                    1. Halt
                      07.03.2019 17:57

                      С подобным отношением к собеседнику пройдите-ка, пожалуй, на ЛОР. У меня нет ни малейшего желания дискутировать.


                      1. 0xtcnonr
                        07.03.2019 18:22
                        -2

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

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


                      1. 0xtcnonr
                        07.03.2019 18:46
                        -2

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

                        Поэтому, мы видим адепта, который написал тотальное нелепую ахинею и получил 3 плюса от сектантов(только за то, что является адептом той же секты) и меня, который разоблачил его нелепую херню и получил минусы за это. А так же адепт съехал с темы, в жалких попытках оправдаться. Ведь за свой трёп он должен отвечать не мне, а себе. И абсолютно никого не должно волновать — что так и как себя кто-то ведёт.

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

                        Где же вы, герои? Придите и изобличите меня.


                        1. DistortNeo
                          07.03.2019 18:56
                          +1

                          Ну я поставил минус тупо за манеру общения и срач.


                    1. humbug
                      07.03.2019 19:16

                      А вот и пошла типичная подмена понятий, адепты выдумывают новые значения понятия «компилятор».

                      Я человек простой, clang — compiler front end для C++, а rustc — compiler front end для Rust. Не?


                      1. 0xtcnonr
                        07.03.2019 19:38
                        -1

                        Я человек простой, clang — compiler front end для C++, а rustc — compiler front end для Rust. Не?

                        Не, вопрос был в том, что «раст более портируемый» и как мы выяснили «фронтенд сложнее милд/бек-ендов». И то и то опровергается.

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

                        К тому же, куда подевался тот же gcc? А это топ1 компилятор.


                1. 0xtcnonr
                  07.03.2019 17:37

                  Компиляторов уже два. Посмотрите на github.com/thepowersgang/mrustc, пару месяцев назад проскальзывала статья, как они забутстраппились.

                  Я знаю про эту нелепую поделку — это не компилятор, т.к. он нерелевантен. Это очередная попытка врать выдавая неконкурентоспособную поделку за компилятор.

                  А вы уверены, что вы правильно поняли семантику Rust? В С++ время жизни — это рантаймовое свойство,

                  Это всегда рантаймовое свойство. Это базовая семантика стека и чего бы вы там не придумали — оно этого факта не изменит.

                  тогда как в Rust это статическое свойство, известное на этапе компиляции. Стораджей-ссылок нет.

                  Это не более чем манипуляция. Можно что угодно называть чем угодно, но это ничего не изменит. «Стораджей-ссылок» есть всегда.

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

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

                  И так как время жизни в Rust — это статическое свойство, известное на этапе компиляции, подсчет кол-ва мутабельных/иммутабельных ссылок стоит ровным ничего(прямо как С++ шаблоны)

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

                  компилятор может сделать вывод о том, будет ли объект, на который ссылается ссылка, жить достаточно

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

                  Они никогда не могут использовать ссылку, т.е. любой не-глобальный объект имеет непредсказуемое с т.з. замыкание/корутина/тред время жизни.

                  В Раст существует настоящая мув-семантика, например:

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

                  Это сделано специально, чтобы избежать неопределенного поведения, присущего С++:

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

                  std::vector<std::string> v;
                  std::string str = "example";
                  v.push_back(std::move(str)); // str is now valid but unspecified
                  str.back(); // undefined behavior if size() == 0: back() has a precondition !empty()

                  Ещё более нелепые манипуляции. На кого это рассчитано? Какое отношение эти попытки имеют к move? Да никакого.

                    std::string str;
                    str.back(); // undefined behavior if size() == 0: back() has a precondition !empty()<

                  Опять попытки обмануть выдавая дефолтное поведение строки за следствие move? Для протокола поясню — метод back() не возвращает никаких ошибок, поэтому он не может сообщить об ошибке. Так сделаано для потому, чтобы не городить синтаксический мусор из которого состоит обработка ошибок на расте.

                  Итак, у нас есть мув-семантика, следовательно объекты можно действительно перемещать.

                  Ну манёвры я уже понял — поясню читателям. Есть данные — они хранятся в неком «локальном сторедже»(т.е. время жизни привязано к потоку выполнения). Эти данные перемещать никуда нельзя — только копировать.

                  Так что же такое перемещение? В объекте могут быть данные хранящиеся в глобальном сторедже(т.е. там, где их время жизни ничем не ограничено) — это некие ресурсы. В том же raii время жизни этих ресурсов привязывает к времени жизни объекта — это владелец ресурса. В базовом виде владелец всегда один и move — это и есть передача владения.

                  Мало того, что это уже оверхед и не zero-cost, т.к. привязка одного к другому может быть менее эффективно, нежели отсутствие каких-либо привязок, а следовательно отсутствие вообще какой-либо проблемы «времени жизни».

                  Два основных тезисы — все объекты из локального стореджа копируются ВСЕГДА. Все проблемы связанные с временем жизни — вызваны raii.

                  При перемещении стековых объектов возможно фактическое перемещение объекта на другой адрес

                  Оверхед. Ссылка предполагает передачу без копирования. move — копирование. Никаких «фактическое», «перемещение» и прочих нелепых базвордов — не существует. Это всё про ресурсы, а не объекты в локальном сторедже(стеке).

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

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

                  Кстати, тут можно заметить — как человек игнорирует некий основной момент. Дело в том, что "(самоссылающиеся структуры)" — это не единственный кейс, в котором происходит «инвалидации этих ссылок». Любая ссылка на объект — это уже та самая "(самоссылающиеся структуры)" и любое «перемещение» объекта — вызовет инвалидацию всех ссылок на этот объект.

                  Именно поэтому там выше выдаётся убогость за плюс:

                  После перемещения обращаться к b переменной нельзя.

                  Из этого следует, что b уже ссылка, а не сторедж. В любом случае — это инвалидирует все ссылки на b. Ах да, как я могу забыть — мы же можешь жить в мире поней, где «ссылки иметь нельзя» и в этом мире всё нормально. Только это не более, чем убогие абстракции, которые никоим образом не являются zero-cost.

                  Если это самоссылающаяся структура на стеке, то ее нельзя перемещать.

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

                  Пользоваться такой корутиной можно, но локально.

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

                  Ее можно создать на стеке, но нельзя возвращать из функции и нельзя перекидывать в другую переменную по типу let a = b.


                  За этими нельзя следит компилятор без пенальти для рантайма, без UB, полностью zero-cost.

                  Опять какие-то нелепые манипуляции. Это типичная тактика — сражаться с соломенным чучелом. Кто и где говорил, что отслеживание подобного вообще кому-то интересно? Я об этом говорил? Нет. Сам придумал — сам опроверг, как говориться.

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

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

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


                  В Rust реализовали оба, пользуйся любым.

                  Опять же, тут видно явные подлоги. Адепт выдумывает какие-то два случая, которые существуют в рамках его фентейзиного мира, но при этом выдаёт их за реально — т.е. будто был ТОЛЬКО эти два случая существуют. На самом деле нет, и об этом я уже говорил выше.

                  Дак мало того, что два случая — вранье, дак ещё и каждый случай — враньё. На самом деле тут прослеживается типичная тактика, когда адепт какого-то учения говорит тезисами понятиями этого учения, которые непротиворечивы в рамках этого учения(этого понятийного аппарата). Но проблема в том, что мне как-то вообще не интересно это учение и эти понятия никак не соотносятся с реальным миром, и их «внутренняя корректность» никак и ничего не означает.

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

                  Почитайте статьи, это действительно увлекательное чтиво.

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

                  std::pin — это возможность дать компилятору инфу о том, можно ли перемещать объект или нет. Т.е. история с «переместить стековую корутину нельзя, а хиповую можно» было описано чисто языковыми средствами, а не захардкожено в компиляторе.

                  Тут мы видим опять какие-то глупые попытки манипулировать, выдавая убогость за плюс. Но я расшифрую это.

                  Мы просто запретили всё, но срочно понадобилось решение проблемы. Поэтому наделали unsafe-хаков, и везде раструбили о том, что «мы нашли решение» — на самом деле нет. Это значит только одно — начальная модель несостоятельна, раз требуется её взламывать. Но вера есть вера.

                  На самом деле это фундаментальная манипуляция на котором основан раст. Раст разделён на два языка — язык на котором НИЧЕГО НЕЛЬЗЯ НАПИСАТЬ(базовый), и язык на котором НАПИСАТЬ ЧТО_ТО МОЖНО(unsafe). Как дальше действуют адепты, т.к. на базовом языке ничего написать нельзя, то они пишут на unsafe-языке базовые примитивы, а далее выдают их корректность за корректность языка(на самом деле тут такой же подлог. Корректность модели — не означает корректность имплементации). Далее, путём компоновки этих примитивов уже пишется код на базовом языке.

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

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

                  Их модель не работает с исключениями? Зачем исключения — мы придумаем очередную мантру и будем в неё верить. Мы придумаем свои трактовки zero-cost, будем всегда врать и подменять понятия.

                  Тепло встретят, помогут, подскажут, разжуют, объяснят. Без смс и без регистрации =)

                  Это как? Будут минусовать неугодынх и плюсовать своих, которые засирают те темы, которые к ним никакого отношения не имеют? Плюсовать просто пофакту того, что «мы одной веры»? О да, всегда мечтал о таком.


                  1. humbug
                    07.03.2019 19:06

                    А что для вас zero-cost?


                    1. 0xtcnonr
                      07.03.2019 19:52

                      То, что следует из этого понятия. Это значит, что написать «в рамках абстракции» я могу так же эффективно, как «в обход абстракции». Любые ограничения, которые забирают у кода эффективность — не являются zero-cost. Даже крестовое raii не является zero-cost. И для поддержания хотя-бы минимальной эффективности нужно постоянно латать абстракции.

                      Очень часто что раст-адепты, что крестовые адепты определяют zero-cost как «если мы напишем такой же код, который обеспечивает нашу абстракцию, то он не будет быстрее».

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

                      Под абстракциями всё не так — я могу снести хоть весь хип. И никакой обратной операции вызывать не нужно. Это уже оверхед.

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

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

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

                      Но факт остаётся фактом — ты не можешь рассчитывать на это(как минимум тебе нужно знать все существующие оптимизации в stdlib, что уже почти невозможно сделать), это работает в самых примитивных с случаях и работает очень плохо.

                      Поэтому, как только кто-то пытается повторить на расте(и подобных «безопасных» изваяниях) реальный zero-cost, когда какой-то адепт будет перепащивать очередной сишный/крестовый код — он будет заниматься сплошным взломом абстракций, либо на уровне stdlib, либо на уровне своего кода.


                      1. humbug
                        07.03.2019 19:58

                        Очень часто что раст-адепты, что крестовые адепты определяют zero-cost как «если мы напишем такой же код, который обеспечивает нашу абстракцию, то он не будет быстрее».

                        Ну так трекать время жизни переменных для рантайма раста буквально zero-cost. Это ничего не стоит, так как это считается в момент компиляции и только для компиляции. Что с этим не так?


                        1. 0xtcnonr
                          07.03.2019 20:12

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

                          Это неверное утверждение. Как я уже говорил — эти конструкции и тезисы валидны ТОЛЬКО в рамках внутренней логики раста, которая сводится к «запрещаем множественные ссылки — нет проблем», «запрещаем отделять скоуп от потока выполнения — нет проблем».

                          Т.е., если попроще — этот тезис существует в рамках модели, которая накладывает множество ограничений со стороны возможностей. Это ограничения НЕ ПОЗВОЛЯЮТ РЕАЛИЗОВАТЬ что-то НАСТОЛЬКО ЖЕ ЭФФЕКТИВНО как в случае, КОГДА ЭТИХ ОГРАНИЧЕНИЙ НЕТ.

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

                          Это вообще типичная методика манипулирования. Когда мы выделяем какую-то подзадачу и говорим «ну дак время её выполнения не изменилось», постоянно всем этим тыча. Но, это никого не волнует, ведь нас не интересует время выполнения под-задачи — нас интересует время выполнения задачи. А ваше решение задачи усложняет(т.е. замедляет) все остальные(некоторые другие) подзадачи.

                          Таким образом, в рамках одно части задачи разницы нет, а в рамках всей задачи — разница есть.

                          Что с этим не так?

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

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


                          1. humbug
                            07.03.2019 20:33

                            «запрещаем отделять скоуп от потока выполнения — нет проблем»

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


                            Rust заставляет программиста придерживаться тех же правил, что и C++: не оставлять висячие ссылки, не вызывать рейс кондишны, не нарушать алиасинг… Он не делает это самостоятельно, он выполняет проверки и говорит:


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

                            Но вы это почему-то называете оверхедом. Почему?


                            1. 0xtcnonr
                              07.03.2019 21:20
                              -3

                              Но ведь Rust позволяет перекидывать замыкания между разными потоками

                              Враньё. Абсолютно насрать куда там и что позволять передавать раст, когда передаются копии объектов. С этим нигде и ни у кого проблем нет. Опять убогие манипуляции и подмена понятий.

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

                              Херня убогая — мне нахрен не нужен этот колхоз — мне нужно пошаренное состояние управляемое моими руками и так, как мне нужно.

                              Rust заставляет программиста придерживаться тех же правил, что и C++:

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

                              не оставлять висячие ссылки

                              Никаких «васячих» ссылок в крестах нет

                              не вызывать рейс кондишны

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

                              не нарушать алиасинг…

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

                              Он не делает это самостоятельно, он выполняет проверки и говорит:

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

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

                              Эта херня никогда не узнает когда умрёт мой объект. Это не вычисляется статически. На этом можно закончить.

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

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

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

                              И? В чём проблема?

                              Но вы это почему-то называете оверхедом. Почему?

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

                              Сообщаю ещё раз — вся эта херня НЕ РАБОТАЕТ В ОБЩЕМ СЛУЧАЕ, А РАБОТАЕТ В РАМКАХ МИЛЛИАРДОВ ОГРАНИЧЕНИЙ, КОТОРЫЕ И ВЫЗЫВАЮТ ОВЕРХЕД. Это ведь настолько очевидно.


                              1. PsyHaSTe
                                07.03.2019 22:01
                                +1

                                Враньё. Абсолютно насрать куда там и что позволять передавать раст, когда передаются копии объектов. С этим нигде и ни у кого проблем нет. Опять убогие манипуляции и подмена понятий.

                                Вам конечно не же составит труда конкретно указать, какое утверждение ложно?

                                Херня убогая

                                кормит дерьмом

                                Херня убогая, но это уже проблема крестов

                                это говно не нужно

                                нелепый мусор

                                Эта херня никогда не узнает когда умрёт мой объект

                                Ничего об ub этот мусор не знает


                                На это можно и закончить, действительно

                                Это не вычисляется статически.

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

                                Это ведь настолько очевидно.

                                Лучший аргумент, когда сказать нечего.


                                1. 0xtcnonr
                                  07.03.2019 22:38
                                  -1

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


                      1. humbug
                        07.03.2019 20:44

                        Любые ограничения, которые забирают у кода эффективность — не являются zero-cost. Даже крестовое raii не является zero-cost. И для поддержания хотя-бы минимальной эффективности нужно постоянно латать абстракции.

                        Верно. Но подсчет ссылок идет во время компиляции и не занимает ресурсов во время выполнения и не забирает у кода эффективности.


                        Вы следуете пути GIGO, так как не разбираетесь в матчасти.


                        1. 0xtcnonr
                          07.03.2019 21:09
                          -1

                          Но подсчет ссылок идет во время компиляции и не занимает ресурсов во время выполнения и не забирает у кода эффективности.

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

                          Ещё раз повторяю НИКАКОГО подсчёта ссылок ВО ВРЕМЯ компиляции НЕТ и быть НЕ МОЖЕТ. Вся эта херня работает только в фентезийном мире адептов и накладывает тонны ограничений на рантайм, не позволяя писать ЭФФЕКТИВНЫЙ КОД. Всё, меня одалело повторять одно и то же сектантам, которые не способны воспринимать ничего, кроме своих догматов.

                          Вы следуете пути GIGO, так как не разбираетесь в матчасти.

                          Какой матчасти? Фентезийных мирах адептов? Меня это не волнует. В реальной матчасти? Ну дак где эти герои, которые укажут мне на моё непонимание? Нету, ну на этом можно и закончить.

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


                          1. humbug
                            07.03.2019 21:20

                            Ещё раз повторяю НИКАКОГО подсчёта ссылок ВО ВРЕМЯ компиляции НЕТ и быть НЕ МОЖЕТ.

                            Почему не может? Это ваше внутреннее ощущение? Вам так подсказывает интуиция?


                            1. 0xtcnonr
                              07.03.2019 21:32

                              Почему не может? Это ваше внутреннее ощущение? Вам так подсказывает интуиция?

                              Меня удивляет эта нелепость и попытки строить из себя героев, а ведь я могу ответить так же?

                              struct obj_t {
                                int x;
                              };
                              
                              obj_t * p;
                              
                              void foo() {
                                obj_t obj;
                                p = &obj;
                                in_other_thread(&obj);
                                obj.x = 123;
                                bar();
                              }
                              


                              Подсчитайте время жизни obj и кол-во ссылок на него в момент после bar;


                              1. humbug
                                07.03.2019 21:37

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


                                1. 0xtcnonr
                                  07.03.2019 21:46
                                  -2

                                  Как я могу это сделать, если этот код неполон?

                                  Он полон.

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

                                  Враньё — на in_other_thread он сядет влужу, так же он обосрётся со скоупом функции. Так же, код, который написан в bar ему никак не поможет.

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

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

                                  К тому же, опять враньё:

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

                                  Никакой нелепый крейт ничего не изменит — функции находятся в разных крейтах. С чего вдруг вы решили, что они находятся в одних?


                                  1. humbug
                                    07.03.2019 21:55

                                    Ммм, теперь я понял.

                                    Вы путаете рантаймовое время жизни и лексическое. Это разные вещи.


                                    1. 0xtcnonr
                                      07.03.2019 22:00
                                      -3

                                      Вы путаете рантаймовое время жизни и лексическое. Это разные вещи.

                                      Вам дана задача — решайте её. Оправдания меня волнуют мало.

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

                                      Поэтому, данный сектант был помножен на ноль. Занавес.


                                      1. humbug
                                        07.03.2019 22:08

                                        Вычисление рантаймового времени жизни неразрешимо на машине Тьюринга, ибо проблема остановки. А лексическое можно вычислить. obj рождается в первой строчке foo, лексическое время жизни кончается в последней строчке foo. Элементарно же ж?


                                        1. 0xtcnonr
                                          07.03.2019 22:31

                                          Элементарно же ж?

                                          Я вам дал задачу, решайте. Все исходные вам даны — вперёд.

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

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

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

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

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

                                          Бороться же с методичкой, да и с базовой моделью очень просто. Дело в том, что все эти модели — убогая нелепость и не учитывает даже 5-10% реальных особенностей среды исполнения.

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

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

                                          Ведь в ситуации с подменой стека никакой остановки не произошло, но методичка опять сломалась? Как же так.

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

                                          И тут у сектанта два пути — он либо признаём, что у нас есть ограничений(а значит оверхед), либо не признаёт и он совсем поехавший.

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


                                1. KanuTaH
                                  07.03.2019 22:20

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

                                  Прошу прощения, но «свежо предание, да верится с трудом». Приведу гипотетический пример — у нас есть некая функция, в функции есть локальные переменные на стеке. Мы хотим в ней вызвать некий syscall, который по завершении вызывает callback. Мы определили этот callback локально в функции (скажем, в виде лямбды) и дали ему доступ к переменным (скажем, по ссылке — мы хотим по завершении syscall их поменять). Каким чудом компилятор Rust в compile-time с zero overhead узнает время жизни этого callback и ссылок на переменные, к которым он имеет доступ? Да и вообще хотя бы узнает, синхронный этот syscall или асинхронный? А ведь он запросто может быть как синхронным, так и асинхронным — в зависимости от неких настроек или внешних условий, которые могут быть просчитаны программистом, но никак не компилятором.


                                  1. PsyHaSTe
                                    07.03.2019 22:34

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

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

                                    Синхронность и асинхронность же рулятся трейтами Sync/Send, которые компилятор тоже отлично ловит. Как-то раз у меня не компилировалась программа, потому что в моей структуре был филд, у которой был филд, у которой был третий филд, у которой был свой филд, который было небезопасно передавать в асихнронный коллбек, и компилятор всё это дело подчеркнул со словами «вот этот филд исправьте, пожалуйста».

                                    Ну и да, если прям очень сильно хочется (например мы *точно* знаем, что сискол завершится до конца выполнения текущего метода), то вам в руки дается unsafe, где вы можете преобразовать данные в нужный формат. Unsafe точно такой же инструмент, как и все остальные. Не использовать unsafe не более умно, чем не использовать цикл for.


                                    1. KanuTaH
                                      07.03.2019 22:41
                                      +1

                                      Ну и да, если прям очень сильно хочется (например мы *точно* знаем, что сискол завершится до конца выполнения текущего метода)

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

                                      то вам в руки дается unsafe

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


                                      1. PsyHaSTe
                                        07.03.2019 22:50

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

                                        Ну у вас же два варианта. Либо вы выражаете все на уровне типов, и компилятор вас проверяет, либо вы не можете выразить это на уровне типов (например, это FFI), и тогда ансейф.


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


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


                                        Что уж говорить про более прикладной код. В том же actix-web, а это полноценный акторный веб-сервер с кучей логики, слово unsafe встречается 11 раз.


                                        То есть ограничения модели, конечно же, есть, но стоит взглянуть на то, насколько часто с ними придется сталкиваться. И практика показывает, что вообще не придется, покуда не пишешь супер-пупер эмбед в no_std режиме. Когда я писал бота для телеграма, unsafe мне не пригодился вообще ни разу. А там я, а на секундочку, делал и асинхронный многопоточный веб-сервер (чтобы не лонг поллить новые сообщения), и распознавание картинок, и многое другое.


                                        1. humbug
                                          07.03.2019 22:56

                                          Что уж говорить про более прикладной код. В том же actix-web, а это полноценный акторный веб-сервер с кучей логики, слово unsafe встречается 11 раз.

                                          А мы переписали ноду токса вообще без unsafe =)


                                          1. KanuTaH
                                            07.03.2019 23:05
                                            +1

                                            Я только хотел бы сказать, что «уменьшать количество unsafe ради уменьшения количества unsafe» — это как бы не самоцель, если ради этого приходится идти на прикручивание лишних костылей вместо простой, производительной, но «unsafe с точки зрения Rust» реализации. Не говоря уж о том, что в stdlib Rust'а уже и так наверняка просто дофигища unsafe кода (а как иначе работать с сисколлами и любыми системными библиотеками в системах, которые не написаны на Rust, верно?)


                                            1. PsyHaSTe
                                              07.03.2019 23:58

                                              Я же вот прям только что скинул сколько там ансейфа. посмотрите пожалуйста, rust-lang/rust/src/stdlib.

                                              если ради этого приходится идти на прикручивание лишних костылей вместо простой, производительной, но «unsafe с точки зрения Rust» реализации

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


                                              1. KanuTaH
                                                08.03.2019 00:12

                                                Я же вот прям только что скинул сколько там ансейфа

                                                Ну я посмотрел бегло по файликам из подкаталога libstd, порядочно там ансейфа.

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

                                                Вы имеете в виду «если документированный сисколл из синхронного внезапно превратится в асинхронный»? Ну тогда это будет ошибка в ядре ОС. Никакой safe код от ошибок в ОС не поможет, а городить городушки и писать заведомо неэффективный код на такой гипотетический случай — пустая затея. Fail fast, die young — лучший выбор в таких случаях.


                                  1. humbug
                                    07.03.2019 22:38

                                    Прошу прощения, но «свежо предание, да верится с трудом».

                                    В safe подмножестве все именно так.


                                    Каким чудом компилятор Rust в compile-time с zero overhead узнает время жизни этого callback и ссылок на переменные, к которым он имеет доступ?

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


                                    • Dereference a raw pointer
                                    • Call an unsafe function or method
                                    • Access or modify a mutable static variable
                                    • Implement an unsafe trait

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


                                    1. KanuTaH
                                      07.03.2019 22:44

                                      В safe подмножестве все именно так.

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


                                    1. 0xtcnonr
                                      07.03.2019 22:47

                                      Тут компилятор спотыкается, да. И для этого есть unsafe подмножество. Unsafe означает, что программист говорит компилятору: «мамой клянусь все будет безопасно».

                                      Тут видно манёвры сектанта, когда он увидел контр-тезис, сел в лужу и начал задвигать про unsafe. Он может обмануть человека, поэтому я отвечу на это.

                                      В чем штука, сектант подменил понятия. Т.е. когда он болтает о безопасности, zero-cost и прочей хернее — он имеет ввиду safe-rust. А далее, когда сектанта ловят на балабольстве — он переключается на unsafe-rust. И оппонент очень часто не замечает этой подмены, т.к. он воспринимает язык как нечто целое, в раст — это два языка.

                                      Дак вот, как множить и эти потуги на ноль. Дело в том, что здесь сектант признаёт, что zero overhead может быть только unsafe-rust, либо некий общий раст. А это значит, что unsafe-rust не является zero overhead и мы поймали сектанта на балабольстве и он сам это доказал.

                                      Там ниже сектант трепался про то, что «раст — это тоже zero-cost», но как мы видим — zero-cost только unsafe(+safe) раст, а значит по умолчанию все эти истории про безопасность не работают. Либо безопасность, либо zero-cost.

                                      Тут сектант может завести шарманку про «а ну дак С++ весь unsafe, а у нас комплекс» — во-первых трепло не доказало, что safe+unsafe раст может быть zero-cost, а во-вторых — это подлог.

                                      Безопасность в этой парадии нелепой берётся не из safe и не из rust, а берётся из stdlib. Поэтому множатся эти потуги на ноль так же просто — использование любой либы так же безопасно, либо как минимум является комплексом из опасных/безопасных частей кода.


                                    1. 0xtcnonr
                                      07.03.2019 23:11
                                      +3

                                      Кстати, линканул кто-то статью и я увидел знакомое место — когда будет аналог этого кода:

                                      Уже сколько времени прошло, а засирать С++-треды раст-пропагандой есть время, а написать код нет. Как же так?


                                      1. humbug
                                        07.03.2019 23:21

                                        Блин… =(


                                        1. 0xtcnonr
                                          07.03.2019 23:51

                                          Ну т.е. кода не будет? Даже с такой элементарной хернёй проблемы что-ли? О боже, какая конкуренция, какой zero-cost, какая системщина. Не знаю даже — плакать или смеяться. Ладно я больной и меня можно заминусовать, захаять за моё поведение, но неужели это первый пример, с которым вы сталкиваетесь? Вам их не показывают, вы их игнорируете?

                                          Там ведь ничего нет, просто ничего. Никаких хаков, никаких взломов абстракций, никакого лоулевел кода — это изи должно писать на safe-rust. Там же просто таблица из строк статичной длинны и конкатенация.


                                          1. humbug
                                            08.03.2019 00:00

                                            Даже с такой элементарной хернёй проблемы что-ли?

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


                                            1. 0xtcnonr
                                              08.03.2019 00:06

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

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

                                              К тому же, какая разница что делает код? Вам просто нужно написать эквивалент. И абсолютно неважно как он там работает.

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


                                              1. humbug
                                                08.03.2019 00:14

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

                                                Правильно. Именно это и называется тестами. Бенчить бинарники не имеет смысла, если бинарники вместо реального вычисления занимаются… чем-то еще, а то и вообще ничем.


                                                1. 0xtcnonr
                                                  08.03.2019 00:20

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

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

                                                  Сектанту всегда хорошо, когда брат сектант показывает «силу секты», а когда прижали так всё — уже брат сектант плохой и тесты его говно и код говно. Как же так?

                                                  Ну дак что, я увижу от вас аналог этого кода или и дальше буду слушать нелепые оправдания?


                                                  1. humbug
                                                    08.03.2019 00:31

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


                                                    1. 0xtcnonr
                                                      08.03.2019 01:37
                                                      +1

                                                      Всё это есть у автора статьи. Расчёт на то, что я не буду тратить своё время на эту херню, и уж тем более не буду писать на расте. Но я не поленился и напишу вам мануал.

                                                      У автора есть его бенчмарк генерирует тестовый файлы и сам замеряет время.

                                                      //у автора есть файлик main.cpp(в моём случае) и файлик с данными(inp_hi).
                                                      //я иду, копирую файлик main.cpp в main_new.cpp и заменяю там код.
                                                      //собираю файлик в main_new_cpp и запускаю так:
                                                      
                                                      ./rust-vs-cpp-bench/huffman_encoding $ ./main_new_cpp < inp_hi > new_cpp_out
                                                      ./rust-vs-cpp-bench/huffman_encoding $ ./main_cpp < inp_hi > cpp_out
                                                      
                                                      //получаю два файла, сгенерированные двумя имплементациями - оригинальной и патченной.
                                                      //сравниваю их друг с другом
                                                      $ diff cpp_out new_cpp_out 
                                                      
                                                      $ echo $?
                                                      0//файлы идентичны - победа.
                                                      
                                                      //то же самое можно сделать и с растом:
                                                      ./rust-vs-cpp-bench/huffman_encoding $ ./main_new_cpp < inp_hi > new_cpp_out
                                                      0.094140056
                                                      ./rust-vs-cpp-bench/huffman_encoding $ ./main_rust < inp_hi > rust_out
                                                      0.509164872
                                                      $ diff new_cpp_out rust_out 
                                                      $ echo $?
                                                      0
                                                      
                                                      //здесь нужно только закомментировать 
                                                      //     codec.printTable(std::cout);// в крестах и 
                                                      
                                                      //    for (letter, code) in &table {// в расте
                                                      //        println!("{}: {}", letter, code);
                                                      //    }
                                                      
                                                      //т.к. они дают разный результат - там разный порядок.
                                                      
                                                       // 4. Encode message
                                                      Тот код заменяет именно этот этап, в расте:
                                                      for c in sentence.chars() {
                                                                      code_string.push_str(table.get(&c).unwrap());
                                                                  }
                                                      


                                                      И никаких проблем. Автор, конечно, там всё поменял и измеряет время теперь не только encode, а то было слишком уж позорно. В любом случае — хотя-бы так.


                                                      1. humbug
                                                        08.03.2019 01:57

                                                        0//файлы идентичны — победа.

                                                        Теперь вижу, что тайминги пишет в std::cerr, а результаты в std::cout.


                                                        Я энкодер накидал на строках и массивах фиксированного размера.


                                                        use std::collections::HashMap;
                                                        use std::string::String as StdString;
                                                        use heapless::{Vec, String};
                                                        use heapless::consts::{U32, U256};
                                                        
                                                        type FixedString = String<U32>;
                                                        type FixedVec    = Vec<FixedString, U256>;
                                                        
                                                        #[derive(Default)]
                                                        pub struct Encoder {
                                                            m: FixedVec,
                                                        }
                                                        
                                                        impl Encoder {
                                                            pub fn new(mut table: HashMap<u8, StdString>) -> Self {
                                                                let mut encoder = Self::default();
                                                                encoder.m.resize_default(256).unwrap();
                                                                for i in 0..=255 {
                                                                    let kv = table.entry(i).or_insert( "".into() );
                                                                    encoder.m[i as usize] = FixedString::from(&*kv.as_str());
                                                                }
                                                                encoder
                                                            }
                                                            fn encode_byte(&self, byte: u8) -> &str {
                                                                self.m[byte as usize].as_str()
                                                            }
                                                            pub fn encode(&self, s: &str) -> StdString {
                                                                let mut out = StdString::with_capacity(s.len());
                                                                s.as_bytes().iter().for_each(|byte| {
                                                                    out.push_str( self.encode_byte(*byte) );
                                                                });
                                                                out
                                                            }
                                                        }

                                                        Сделайте готовый .cpp по решению от phponelove (https://habr.com/ru/post/344282/:/#comment_10563198), чтобы можно было бенчить.


                                                        1. 0xtcnonr
                                                          08.03.2019 02:10

                                                          use heapless::{Vec, String};
                                                          use heapless::consts::{U32, U256};

                                                          Такое не катит. Только stdlib.

                                                          unwrap()

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

                                                          Сделайте готовый .cpp

                                                          pastebin.com/raw/297KrNHi


                                                          1. humbug
                                                            08.03.2019 02:17

                                                            Такое не катит. Только stdlib.

                                                            Почему?


                                                            1. 0xtcnonr
                                                              08.03.2019 02:32

                                                              Почему?

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

                                                              К тому же, в данном случае все кишки(которых в С++ нету, std::array ничего не делает и может спокойно быть заменён на обычный массив) и все проблемы выносятся в отдельную либу.

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

                                                              К тому же, там прячется много всяких интересных вещей на тему растострок. Зачем это прятать от зрителя?

                                                              Именно поэтому у нас есть код на голых крестах и нам нужен аналогичный код на голом расте, пусть даже и не на голом, а на stdlib.


                                                              1. humbug
                                                                08.03.2019 06:30
                                                                +1

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

                                                                Ок, держите: https://gist.github.com/kpp/1217e694b6beeb08db6b72ebc3e8b9a8


                                                                Test huffman_encoding
                                                                
                                                                Compiling programs..
                                                                Generate test data..
                                                                Measuring performance..
                                                                ../common/compare_performance.sh
                                                                Averaging performance of 10 runs..
                                                                ./main_cpp:
                                                                  test inp_low: runtime .00275 sec, core .00043 sec
                                                                  test inp_mid: runtime .01919 sec, core .01623 sec
                                                                  test inp_hi: runtime .16228 sec, core .14221 sec
                                                                
                                                                ./main_rust:
                                                                  test inp_low: runtime .00090 sec, core .00009 sec
                                                                  test inp_mid: runtime .00951 sec, core .00710 sec
                                                                  test inp_hi: runtime .08171 sec, core .06475 sec


                                                                1. 0xtcnonr
                                                                  08.03.2019 15:37

                                                                  Ок, держите:

                                                                  И кого вы пытались обмануть?

                                                                  ./main_rust < inp_hi > rust_out
                                                                  0.049385411
                                                                  
                                                                  ./main_new_cpp < inp_hi > new_cpp_out
                                                                  0.041475691
                                                                  

                                                                  m[i as usize] = table[&i].as_ref();
                                                                  

                                                                  Кого вы тут пытались обмануть? Кто вам сказал, что мапу можно трогать и на её элементы брать ссылки?

                                                                  Вы трогали код автора, а значит возвращайте измерение ТОЛЬКО изменённого участка кода:

                                                                      measure_and_print(||
                                                                          {
                                                                  
                                                                              // 4. Encode message
                                                                              let encoder = Encoder::new(&mut table);
                                                                              code_string = encoder.encode(&sentence);
                                                                          });
                                                                  
                                                                  //и так
                                                                  
                                                                      measure_and_print([&codec, &str, &code] ()
                                                                          {
                                                                              encoder enc(codec.table());
                                                                              code = enc.encode(str);
                                                                          });



                                                                  1. humbug
                                                                    08.03.2019 16:23

                                                                    Кто вам сказал, что мапу можно трогать и на её элементы брать ссылки?

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


                                                                    Я предоставил код, который быстрее С++. Чего вы еще от меня хотите, "Царь"?


                                                                    1. 0xtcnonr
                                                                      08.03.2019 16:50
                                                                      -1

                                                                      Я предоставил код, который быстрее С++.

                                                                      Где? Код дан выше — С++ быстрее.

                                                                      Кстати, расскажу что пытается сделать этот сектант. Дело в том, что бенчмарк измеряет одновременно код автора и код мой. Я не менял код автора и изменил только четвёртый этап(а всего измеряемых этапа три).

                                                                      Дак вот, что сделал этот сектант — он пошел и изменил код автора(который я не трогал) и выдал это за победу.

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


                                                                    1. 0xtcnonr
                                                                      08.03.2019 21:52

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


                                                            1. 0xtcnonr
                                                              08.03.2019 04:00

                                                              Кстати, вспомнил тут недавние портянки — может ли так раст:

                                                              auto init() {
                                                                struct {
                                                                  
                                                                } data;
                                                                return data;
                                                              }
                                                              
                                                              auto next_step(decltype(init()) data) {
                                                                struct: decltype(data) {
                                                                  int field0 = 123;
                                                                } new_data ;
                                                                return new_data;
                                                              }
                                                              
                                                              auto next_step2(decltype(next_step(init())) data) {
                                                                struct: decltype(data) {
                                                                  int field1 = 123;
                                                                } new_data ;
                                                                return new_data;
                                                              }
                                                              
                                                              
                                                              struct data_t {
                                                                auto next() {
                                                                  struct next_t: data_t {
                                                                    int field0 = 123;
                                                                    auto next() {
                                                                      struct next1_t: next_t {
                                                                        int field1 = 124;
                                                                      };
                                                                      return next1_t{};
                                                                    }
                                                                  };
                                                                  return next_t{};
                                                                }
                                                              };
                                                              
                                                              template<class... Ts> struct overloaded: Ts... { using Ts::operator()...; };
                                                              template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
                                                              
                                                              struct foo {};
                                                              struct bar {};
                                                              
                                                              
                                                              struct op{};
                                                              
                                                              struct pipe{};
                                                              
                                                              pipe operator|(op, op) {return {};}
                                                              
                                                              struct {} l; 
                                                              
                                                              struct: op {
                                                                auto & operator-(decltype(l) l) {
                                                                  return *this;
                                                                } 
                                                              } wc;
                                                              
                                                              
                                                              struct: op {} cat;
                                                              
                                                              
                                                              
                                                              int main() {
                                                                cat | wc -l;//привет баш
                                                                
                                                                overloaded{//композиация лямбд/функторов
                                                                  [](foo) {},
                                                                  [](bar) {}
                                                                }(foo{});//статический диспатч.
                                                                
                                                                
                                                                {
                                                                  auto data = next_step2(next_step(init()));
                                                                  data.field1 + data.field0;
                                                                }
                                                                {
                                                                  auto data = data_t{}.next().next();
                                                                  data.field1 + data.field0;    
                                                                }
                                                              }


                                                              Про всякие constexpr-генерации подобных структур(aka boost::hana) я и говорить не буду — оно не умеет в это даже близко. Там какие-то крохи появились, но это уровень совсем примитивный.

                                                              То, что раст ничего не может по части лоулевела — мы уже выяснили, да и очевидно это было. Какие-то крохи в unsafe оно может, но это детский сад.

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

                                                              Сейчас в С++ эта тема стала достаточно популярно и описание можно посмотреть в синопсисе упомянутой выше boost::hana.

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

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

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

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


                                                              1. humbug
                                                                08.03.2019 06:34

                                                                А boost::hana такое умеет? https://github.com/llogiq/overflower/


                                                                1. 0xtcnonr
                                                                  08.03.2019 16:30
                                                                  -1

                                                                  A Rust compiler plugin and support library to annotate overflow behavior

                                                                  Кого вы пытались обмануть? В каком месте оно на расте? Это плагин к компилятору.

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

                                                                  // $ clang++ main.cpp -fsanitize=signed-integer-overflow
                                                                  // $ ./a.out 
                                                                  // main.cpp:11:17: runtime error: signed integer overflow: 2147483646 + 1073741823 cannot be represented in type 'int'
                                                                  // -1073741827
                                                                  //с этим оно будет падать -fno-sanitize-recover=signed-integer-overflow на первой ошибке
                                                                  
                                                                  //Да и вообще, если мне нужна проверка на переполнение - я пишу что-то типа:
                                                                  
                                                                  template<typename T> struct wrap {
                                                                    wrap(T x): x(x) {}
                                                                    operator T() {return x;}
                                                                    T x;
                                                                  };
                                                                  
                                                                  template<typename T> std::enable_if_t<std::is_integral_v<T> && std::is_signed_v<T>, wrap<T>> operator+(wrap<T> a, wrap<T>  b) {
                                                                    T x;
                                                                    if(__builtin_add_overflow((T)a, (T)b, &x)) throw std::runtime_error{"overflow"};
                                                                    return x;
                                                                  }
                                                                  
                                                                  //далее заменяю все signed integral T на wrap<signed integral T> 


                                                                  В конечном итоге это всё в 10раз лучше упомянутой поделки. Хотя я на эти глупые попытки врать отвечать не должен, но я ответил.

                                                                  К тому же — данная поделка helloworld — там ничего сложного.


                                                              1. TargetSan
                                                                08.03.2019 15:24
                                                                +2

                                                                Вас не затруднит пояснить, как вы планируете отлаживать ошибки в приведённом шаблонном коде?


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


                                                                1. 0xtcnonr
                                                                  08.03.2019 16:39
                                                                  -2

                                                                  Вас не затруднит пояснить, как вы планируете отлаживать ошибки в приведённом шаблонном коде?

                                                                  И? В чём проблема?

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

                                                                  Меня как-то мало волнуют эти мусорные лозунги.

                                                                  Это прочитает какой-нибудь джун.

                                                                  Его проблемы.

                                                                  И ему придётся потом долго объяснять, что так нормальные люди не пишут.

                                                                  Будут объяснять такие же джуны? Меня это мало волнуют. Нормальные люди пишут код именно так — так написан весь код, везде. А то что там происходит в подсобках ваятелей двадцать пятого эшелона — меня как-то волнует мало.

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

                                                                  С чего вдруг? Потому что кто-то не осилил? Потому-что кто-то сказал? Так написан любой более-менее серьёзный статический крестовый код и сложного там ничего нет.

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

                                                                  А скорее очень даже минус.

                                                                  Ну дак для подобных ценителей есть пхп и иже с ним. Зачем вы приходите в этом язык, чтобы ныть? Используйте то, что подходит вам.

                                                                  Или ваш идеал — Perl?

                                                                  Вы все перепутали. Проблема кастомизации, которая описана в вашей методичке — она происходит из проблем кастомизации ДИНАМИЧЕСКИХ языков. Т.е. когда попросту невозможно разобраться в коде не запуская её.

                                                                  В С++ же другая ситуация и все операции статически описаны, т.е. вы можете мышкой навести на любую закорючку в вашей ide и она покажет — что эта закорючка значит. А так же, компилятор(и та же ide) проверит валидность всех преобразований на стадии тайпчека. И если вы всё написали правильно — никаких ошибок в принципе быть не может.


                                                              1. DistortNeo
                                                                08.03.2019 17:08
                                                                +1

                                                                Кстати, вспомнил тут недавние портянки — может ли так раст:

                                                                Что это за дичь? Я понимаю, что C++ — прямо идеальный язык для разминки мозгов, но за подобную хрень в продакше обычно ломают пальцы.


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


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

                                                                C++ изначально разрабатывался, как совместимый c С.
                                                                Почти любая программа на C является корректной программой на C++, и это круто. Убрать C из C++ попросту невозможно, проще создать новый язык.


                                                                1. 0xtcnonr
                                                                  08.03.2019 17:39
                                                                  -3

                                                                  Что это за дичь? Я понимаю, что C++ — прямо идеальный язык для разминки мозгов, но за подобную хрень в продакше обычно ломают пальцы.

                                                                  А что там непонятного? Допустим, в первом примере — это opaque type, когда только функция может создать определённый тип. Далее мы этот тип расширяем, добавляя в него всё новые поля/методы и т.д.

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

                                                                  Композиция лямбд/функторов — это тоже достаточно нужная и популярная вещь, как и статический диспатч. Его можно заменить на динамический при помощи std::variant.

                                                                  Это тот самый паттерн-матчинг(по типам), только в 10раз мощнее и удобнее.

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

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

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

                                                                  C++ изначально разрабатывался, как совместимый c С.

                                                                  Нет, С++ — это си.

                                                                  Почти любая программа на C является корректной программой на C++, и это круто.

                                                                  Невозможно на С++ писать как на си — си «динамический язык», а кресты статический. И несмотря на то, что в какой-то мере си не сильно ограничили, но без того же void * писать почти невозможно.

                                                                  Убрать C из C++ попросту невозможно

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

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

                                                                  В си функции, вернее их имена — это просто символы. А символы это просто какой-то кусок объектника — это не типы, ни что-либо ещё.

                                                                  Дак вот, С++ ломает abi си и подобные вещи уже не си. Там уже совершенно другие символы, но они остаются символами. godbolt.org/z/nzYVnY — этот пример демонстрирует тему.

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

                                                                  А теперь вопрос — зачем нам функции из си? И в С++ столкнулись с подобной проблемой — и пришлось колхозить функторы. И таких примеров масса.

                                                                  проще создать новый язык.

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

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


                                                                  1. DistortNeo
                                                                    08.03.2019 18:04

                                                                    А что там непонятного? Допустим, в первом примере — это opaque type, когда только функция может создать определённый тип. Далее мы этот тип расширяем, добавляя в него всё новые поля/методы и т.д.

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


                                                                    но всё это просто раздувание кейвордов у компилятора.

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


                                                                    Многословнее от этого код точно не станет. А вот понятнее и читаемее — в разы.


                                                                    А теперь вопрос — зачем нам функции из си?

                                                                    Чтобы делать системные вызовы.


                                                                    1. 0xtcnonr
                                                                      08.03.2019 18:27
                                                                      -1

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

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

                                                                      Он стал более компактным, но не стал более простым, его тяжело читать.

                                                                      И что же там тяжёлого? Определение типа в функции? auto? decltype?

                                                                      Лично я — за раздувание кейвордов,

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

                                                                      Поэтому все переходят с кейвордов на символы и язык превращается в убогое дерьмо c ?' и прочей хернёй — привет раст.

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

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

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

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

                                                                      Многословнее от этого код точно не станет.

                                                                      Станет.

                                                                      А вот понятнее и читаемее — в разы.

                                                                      Нет, но вы можете показать альтернативу на кейвордах. Я же не против.

                                                                      К тому же, вы до сих пор не понимаете сути. Все эти | -l — это такие же кейворды, decltype — кейворд, auto кейворд. Только на С++ я могу сам определить для себя кейворд, в этом суть — кейворд и будет кейвордом.

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

                                                                      Чтобы делать системные вызовы.

                                                                      Какая глупость. Причём тут системные вызовы?


                                                                      1. DistortNeo
                                                                        08.03.2019 23:59

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

                                                                        Шаблоны и макросы — наше всё. Никаких анонимных функций. Принцип "явное лучше неявного" и сюда применим.


                                                                        template <typename T>
                                                                        struct N : T
                                                                        {
                                                                            int field0 = 123;
                                                                        };
                                                                        
                                                                        template <typename T>
                                                                        Next<T> next_step(T data)
                                                                        {
                                                                            return Next<T> {};
                                                                        }

                                                                        И что же там тяжёлого? Определение типа в функции? auto? decltype?

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


                                                                        Поэтому все переходят с кейвордов на символы и язык превращается в убогое дерьмо c ?' и прочей хернёй — привет раст.

                                                                        Согласен, это убожество. И C++ такое тоже есть. Например, вот это:


                                                                        {[](){}();}

                                                                        вполне валидный код.


                                                                        Правда пока совсем колхозно, но что поделать.

                                                                        Конечно, колхозно, ибо приходиться страдать из-за совместимости с legacy кодом.


                                                                        Станет.

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


                                                                        А под многословностью я понимаю конструкции, которые не нужны. Например, в том же C# лямбды объявляются очень лаконично:


                                                                        ...Select((x, y) => x + y)...

                                                                        В C++ же нужно писать:


                                                                        ...Select([](auto x, auto y) { return x + y; })

                                                                        Видите, насколько более многословный вариант получается? Скобочки [], auto — это всё мусор.


                                                                        C#, конечно, тоже не фонтан: все эти public async override Task тоже немного напрягают.


                                                                        Нет, но вы можете показать альтернативу на кейвордах. Я же не против.

                                                                        В случае pipe:


                                                                        pipe(cat, wc - l);

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


                                                                        Pattern matching:


                                                                        match (foo{})
                                                                        {
                                                                           foo => {},
                                                                           bar => {}
                                                                        }

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

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


                                                                        1. 0xtcnonr
                                                                          09.03.2019 01:29

                                                                          Шаблоны и макросы — наше всё. Никаких анонимных функций.

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

                                                                          Принцип «явное лучше неявного» и сюда применим.

                                                                          Во-первых именно вы нарушаете этот принцип, да и принципа того нет — это всё необоснованные попытки оправдать говно.

                                                                          Ну вообще-то да. Это неожиданные конструкции в неожиданных местах.

                                                                          Почему это она неожиданная? Она вполне ожидаема.

                                                                          Нормальный программист пишет код не для себя, а для других.

                                                                          Это нелепые байки, которые никому не интересны. Вы пытаетесь какие-то нишевые реалии натянуть на «всех».

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

                                                                          И этих людей должно волновать только одно — какой им интерфейс дали дяди. А как там дяди что-то сделали — их волновать не должно, да и не волнует.

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


                                                                          И чем проще код, тем лучше.

                                                                          Именно этот код проще. Убожество — это не проще.

                                                                          Согласен, это убожество. И C++ такое тоже есть. Например, вот это:

                                                                          И что же здесь убогого? Здесь нет синтаксического мусора. Вернее он есть, но просто этот код писал человек не знающий С++.

                                                                          Правильно он выглядит так:

                                                                          []{}();


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

                                                                          Так же, тут есть абсолютно ничем не обусловленные скобочки. С таким успехом можно в любой языке со скобочками написать {{{{{{{{}}}}}}}}} и сказать «какое же говно, азаза».

                                                                          Конечно, колхозно, ибо приходиться страдать из-за совместимости с legacy кодом.

                                                                          Неверно. Никакого отношение указанные мною «колхозности» к легаси и совместимости с ним не имеют.

                                                                          Нет, потому что вам, во-первых, не придётся где-то реализовывать сам функционал.

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

                                                                          А во-вторых, кейворды улучшают читаемость.

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

                                                                          Конечно, код с одними спецсимволами будет короче в байтах, но менее читаемым.

                                                                          Ещё раз, — спецсимволы — это не про С++, причём очень даже не про С++. Это про мейнстрим. Не всегда и не везде можно сделать кейворд.

                                                                          Все языки засраны всяким?… .? — потому что никакие кейворды тут не сделать.

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

                                                                          Именно вы и предлагали многословные конструкции, а «малословные» критиковали за непонятки.

                                                                          Например, в том же C# лямбды объявляются очень лаконично:

                                                                          Вам не надоело эту херню каждый раз писать? Сообщаю новость, шарп по сравнению с С++ — это пхп. И это лямбды не из шарпа, а тупорылая копипаста.

                                                                          А теперь — почему они говно. Во-первых — это фундаментальная проблема подобных языков-помоек, в которые пихают что угодно.

                                                                          Суть — у нас есть сигнатура функции — это () {}. Дак вот, язык помойка не придерживается сигнатур, каких-то правил — это просто помойка, в котором есть такие функции () {}, есть такие () => {}, есть такие () => x и тонны неведомого говна.

                                                                          Именно это является синтаксическим мусором, именно это является помойным говном. Когда в языке нет строгости и нет ничего.

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

                                                                          Как мне написать выводимый тип в этом говне? Как мне описать capture? Куда мне записать атрибуты? Куда мне написать template? Ну ладно, с теплейтами там ещё можно приколхозить скобочки с боку и будет <>() => {} — ой, какой говно получилось. А как мне написать {return obj{};}? Ой, опять не получилось. Да что же такой, а методичка такой хорошей была.

                                                                          Видите, насколько более многословный вариант получается? Скобочки [], auto — это всё мусор.

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

                                                                          Ну и что-бы вы пошли мне придумывать новый пример — я добью этот:
                                                                          ...Select(std::plus{})...

                                                                          Какая досада.

                                                                          Терпеть не люблю

                                                                          Ваши религиозные проблемы.

                                                                          , когда переопределяют операторы, меняя их изначальные функции (побитовое или).

                                                                          Нельзя менять их начальное поведение. Вы бы хоть тему изучили. Во-первых тут: (wc — l) — вы уже переопределили оператор, но опустим это. Можно написать wc{l}.

                                                                          Во-вторых, это получается дристня убогая, а не красиво. Я хочу красиво. Пацаны хотят красиво. Нахрен мне это говно?

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

                                                                          Pattern matching:

                                                                          И? Зачем мне нужен этот мусор? У меня всё само матчится, а подобная дристня нужна для всяких пхп.

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

                                                                          Дав вот, синтаксически и семантически pm должен является перечислением функций. И если его сравнивать с теми же спащенными лябмдами foo => {} — это синтаксис аналогичный. Но вот во всяких помойках -это не так.

                                                                          Поэтому именно в С++ правильный match, а это дристня. К тому же, вы можете сюда поставить какую-нибудь функцию? Допустим, у меня уже есть функция для foo — я хочу просто добавить функцию для bar? Ой, опять убого говно ничего не смогло. Ну бывает.

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

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

                                                                          К тому же, как я уже говорил, глобальная семантика — говно. Очень мало кейсов, где глобальная семантика применима. В 90% случаев она просто валяется и не может быть применена в конкретном случае. Допустим, та же самантика оператора |. Она определена для интегральных типов, но для всего остального нет и определить её на уровне стандарта нельзя.

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

                                                                          В это вся суть вашего подхода — ноль понимания, ноль последовательности, но всего и много всяких тупых тезисов.

                                                                          Приходится сначала врубаться в код, чтобы понять, что автор наворотил.

                                                                          Да ты чё, а в pipe(a, b) врубаться не нужно. Вот в operator|() врубаться нужно, а в pipe() — нет. И там и там функций, но методички разные. Гениально.

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

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

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

                                                                          Кстати, а чего так? Зачем вам перегрузка? Неявно же, ну дак зачем такие сложности — даёшь to_string_int, to_string_double — круто чё, надёжно.

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


                                                                          1. DistortNeo
                                                                            09.03.2019 02:37

                                                                            Думал пойти спать, ан нет, ввязался в спор — придётся продолжать.


                                                                            Почему это она неожиданная? Она вполне ожидаема.

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


                                                                            Суть — у нас есть сигнатура функции — это () {}. Дак вот, язык помойка не придерживается сигнатур, каких-то правил — это просто помойка, в котором есть такие функции () {}, есть такие () => {}, есть такие () => x и тонны неведомого говна. Именно это является синтаксическим мусором, именно это является помойным говном. Когда в языке нет строгости и нет ничего.

                                                                            Странно слышать подобное от адепта C++. Два вида скобочек для инициализации объектов. Два ключевых слова для создания типа: struct, class. Два ключевых слова для шаблонных аргументов: typename, class. auto vs decltype(auto). Trailing return type для функций — когда возвращаемый тип указывается после круглых скобок (template <class T, class U> auto add(T t, U u) -> decltype(t + u)). Слабая типизация — неявное преобразование к bool.


                                                                            Достаточно? Я убедил вас, что в C++ строгостью и не пахнет?


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

                                                                            Зато шарп умеет то, что не умеет C++: представлять лямбду в виде Expression Tree. Просто назначение у лямбд немного другое.


                                                                            Как мне написать выводимый тип в этом говне? Как мне описать capture? Куда мне записать атрибуты? Куда мне написать template?

                                                                            А вам зачем?


                                                                            Ну и что-бы вы пошли мне придумывать новый пример — я добью этот:

                                                                            Вот же постарались. А если (x, y) => 2 * x + 3 * y, то что? А ещё этот дурацкий префикс std::. Можно как-то без него?


                                                                            Ваши религиозные проблемы.

                                                                            Есть такое.


                                                                            Используешь нативную семантику в С++ — говно, используешь не нативную — говно. Всё говно.

                                                                            Верно.


                                                                            Да ты чё, а в pipe(a, b) врубаться не нужно. Вот в operator|() врубаться нужно, а в pipe() — нет.

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


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

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


                                                                            1. 0xtcnonr
                                                                              09.03.2019 03:21

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

                                                                              Это тот случай, но и опять же — аргументируйте. Что за аргументы вида «не хочу — плохо»?

                                                                              Странно слышать подобное от адепта C++.

                                                                              Во-первых я не адепт С++.

                                                                              Два вида скобочек для инициализации объектов.

                                                                              И? Да и нету там двух видов скобочек — второй вид скобочек какраз-таки появился для «красиво». А был он таким ранее, когда семантика была более слабой и () там были потому, что это вызов конструктора.

                                                                              Два ключевых слова для создания типа: struct, class.

                                                                              Они разные, struct там всегда было, а класс — более дефолтный алиас для адептов. В чём проблема? Где разночтения?

                                                                              Два ключевых слова для шаблонных аргументов: typename, class.

                                                                              Опять же, не актуально. В алиасах нет ничего плохого, к тому же class уже почти сдох.

                                                                              auto vs decltype(auto).

                                                                              Вообще мимо — семантика абсолютно разная.

                                                                              Trailing return type для функций — когда возвращаемый тип указывается после круглых скобок (template <class T, class U> auto add(T t, U u) -> decltype(t + u)).

                                                                              И? В чём проблема? Это не изменение сигнатуры, а дополнение. Опять мимо.

                                                                              Слабая типизация — неявное преобразование к bool.

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

                                                                              Достаточно? Я убедил вас, что в C++ строгостью и не пахнет?

                                                                              Ни одно примера. Сообщаю вам новость, ваша методичка опять протухла. Строгость это не тогда, когда вы пишите говно — строгость это тогда, когда всё подчиняется определённым правилами и всё поведение описывается. А то, о чём вы говорите — это днище убогое.

                                                                              А вам зачем?

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

                                                                              А если (x, y) => 2 * x + 3 * y, то что?

                                                                              Ещё раз — это пример дерьма, абсолютно нерелевантный. К тому же, почему вы игнорируете мои вопросы?

                                                                              А ещё этот дурацкий префикс std::. Можно как-то без него?

                                                                              Это не префикс, а неймспейс. В шарпе тоже есть крестовые наймспейсы. Это позволят писать как человек vasya::plus, а не страдать со всякими VasyaPlus и прочим дерьмом.

                                                                              Верно.

                                                                              Т.е. все ваши претензии вызваны вашей локальной нетерпимостью, а не объективными факторами? Так и запишем.

                                                                              pipe — это функция с вполне говорящим названием


                                                                              оператор | — да хрен его знает, что там наворотили,

                                                                              Там наворотили то, что должны. Я не вижу гневных тирад в адрес баша с его пайпами через |. Любому понимающему в теме человеку понятно что значит | в контексте cat и wc.

                                                                              только лишние клики мышкой делать.

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

                                                                              В точку.

                                                                              Как жаль, что такие потихоньку бегут из С++.

                                                                              Не дай бог попадётся такой программист в продакшне — всё, проект можно закрывать.

                                                                              Как там, кресты закрылись? Реальность с методичкой не соотносится.

                                                                              Вы опять позиционируете C++ не как язык для разработки

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

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

                                                                              а как язык для разминки мозгов. Не надо так.

                                                                              Это не разминка мозгов — это обыденность. Просто ваши мозги привыкли к другому и у вас своё видение.

                                                                              Это вы пытаетесь исходя из своих низменных желаний/синдрома утёнка затянуть язык обратно в ту помойку из которой он вот-вот начал выбираться. Ваш подход — гиря на ноге С++, который пытается всплыть.

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


                                                                        1. 0xtcnonr
                                                                          09.03.2019 02:49

                                                                          Я даже не поленился, а то вдруг люди действительно в пещере живут. Вот самое доступное и простое ide, вот указанный код и пример из stdlib:


                                                                          Картинки



                                                                          1. DistortNeo
                                                                            09.03.2019 03:22

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

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


                                                                            Плюс поиск по оператору не всегда работает, если мы имеем дело не с конкретным типом, а выводимым (decltype, auto). Добавьте сложности — и всё, приехали. Поиск по имени имеет хотя бы шанс выдать что-то адекватное.


                                                                            1. 0xtcnonr
                                                                              09.03.2019 03:38

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

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

                                                                              Плюс поиск по оператору не всегда работает

                                                                              Всегда, если это не блокнот.

                                                                              если мы имеем дело не с конкретным типом, а выводимым (decltype, auto).

                                                                              Я же вас сказал — ваша информация устарела(лет на 10). Показанный мною код выводится идеально, а по поводу auto — у меня остался старый пример:

                                                                              И заодно покажу пример с кодом выше:

                                                                              Картинка





                                                                            1. 0xtcnonr
                                                                              09.03.2019 03:44

                                                                              Кстати, в одном из примеров вам дан ответ — как я буду передавать лямбду в Select((a, b) => a + b); — допустим, вот так: Select(_ + _).


                                                                1. Antervis
                                                                  08.03.2019 20:19
                                                                  +1

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

                                                                  по-вашему именно поэтому в язык попадают именно те фичи для написания практического кода, которые пользователи языка так просят?


                          1. TargetSan
                            08.03.2019 15:37

                            Escape Analysis
                            ADA SPARK


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


                            1. 0xtcnonr
                              08.03.2019 17:00
                              -1

                              То, что С++ вынужден опираться на крайне убогую и примитивную систему типов Си

                              Нелепая методичка — выкиньте её на помойку.

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

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


                1. KanuTaH
                  07.03.2019 18:07

                  После перемещения обращаться к b переменной нельзя. Она исчезла, переместилась, ее больше нет. Это сделано специально, чтобы избежать неопределенного поведения, присущего С++:

                  Прошу прощения, но здесь вы все-таки немножко передергиваете. В приведенном вами примере неопределенное поведение связано все-таки не с реализацией move-семантики в C++ («настоящая/не настоящая»), а с реализацией std::string. Точно это же самое неопределенное поведение можно вызвать и без всякой move-семантики, например:

                  std::string str;
                  str.back();
                  

                  C++ Core Guidelines рекомендуют оставлять moved-from объект в состоянии «default value of the type», что довольно разумно.


                  1. humbug
                    07.03.2019 19:05

                    В приведенном вами примере неопределенное поведение связано все-таки не с реализацией move-семантики в C++ («настоящая/не настоящая»), а с реализацией std::string.

                    Я считаю, что это связано именно с реализацией move-семантики. C++ не может позволить себе трекать ссылки на объект во время компиляции (время жизни — рантаймовое свойство), следовательно нельзя фактически перемещать объекты, ибо ссылки будут указывать на невалидную область памяти. Поэтому предполагается оставлять moved-from объект в состоянии «default value of the type», чтобы ссылки хоть на что-то ссылались. И возникновение UB из-за реализация std::string — это все уже следствие семантики.


                    1. antoshkka Автор
                      07.03.2019 19:13
                      +1

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

                      Решение ищется, но в ближайшее время вряд ли появится.


                      1. humbug
                        07.03.2019 19:20

                        Спасибо=)


                        А почему сразу не добавили разрушающий мув?


                        1. KanuTaH
                          07.03.2019 19:27

                          У меня есть такое понимание, что изначально задача стояла более узкая — оптимизировать работу с rvalue, где все и так разрушабельно практически сразу.


                        1. antoshkka Автор
                          07.03.2019 19:34
                          +1

                          В историю вопроса не вдавался, есть только догадка: на тот момент казалось что возможность «вымувливать» ресурсы из переменной переданной по lvalue даст больше профита чем уничтожающий move. Так неуничтожающий move проще интегрировать с legacy code: если есть неподконтрольная вам функция foo(T& value, F а), вызывающая f(value), то можно сделать f принимающую параметр по lvalue ref, а внутри уже сделать std::move.


                          1. freecoder_xx
                            07.03.2019 22:55

                            То есть, сделали так из-за legacy, а теперь и само это решение переходит в legacy, с которым нужно считаться! В Rust, кстати, предвидя подобные проблемы своевременно внедрили механизм редакций.


                            1. antoshkka Автор
                              07.03.2019 23:05

                              Имеющийся механизм хорош для своих целей. Деструктивные перемещения хороши для других целей. Механизмы друг друга не заменяют, legacy не маячит на горизонте.


                    1. 0xtcnonr
                      07.03.2019 19:57
                      -2

                      Я считаю, что это связано именно с реализацией move-семантики.

                      Неверно. Это никак не связано. К тому же, move-семантика реализована в крестах правильно. Даже если там будет другая move-семантика — это не изменит поведение back() — ведь этот пример враньё и подлог.

                      Поэтому предполагается оставлять moved-from объект в состоянии «default value of the type», чтобы ссылки хоть на что-то ссылались.

                      Вы нихрена не понимаете в семантике матчасти и крестов. Нет никакого перемещения — есть копирование. Семантика на то и семантика, что это левая в отношении языка семантика. Эти вызваны все ваши проблемы и ошибки в комменте выше.

                      Поэтому, сообщаю вам новость — начальный объект остаётся объектом, копия есть копия. Внутренние данные(которые ресурсы) перемещаются, т.е. передаётся владение. От сюда взялось это поведение и оно ВСЕГДА будет — это объективная реальность и от этого никуда не уйти.

                      И возникновение UB из-за реализация std::string — это все уже следствие семантики.

                      Неверно. ub там было ещё до move и прочей херни. И оно всегда та будет. Либо ub, либо ошибка — третьего не дано.


                      1. KanuTaH
                        07.03.2019 20:09

                        Ну да, есть некое непонимание того, что move семантика в C++ — это не «перемещение ссылки на объект в другое место», а передача владения некими ресурсами, которыми владеет один объект, в другой объект. Само по себе это не вызывает UB, это начинает вызывать UB, если ты не понимаешь, как это работает, и начинаешь пытаться дергать ресурсы из того объекта, в котором их уже нет. А изначально это вообще, насколько я понимаю, задумывалась как оптимизация работы с rvalue, то есть с кодом типа такого:

                        ClassType v = f();
                        

                        чтобы вместо copy constructor / copy assignment была возможность вызвать move constructor / move assignment, который может быть реализован заведомо более оптимально для данного случая. Что после этого будет с rvalue-результатом вызова f() — не столь важно, потому что он все равно сразу же будет уничтожен.


                        1. humbug
                          07.03.2019 20:20

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

                          Даже понимание не уберегает от случайной ошибки. Все мы люди. И мне было бы приятнее, если бы компилятор сказал: "слушай, эту переменную не дергай, а то получишь UB". И я, и ты, и 0xtcnonr умеем писать хороший безопасный С++ код, но мы не боги, и мы иногда, чуточку, совершаем ошибки(неумышленные), верно?


                          1. KanuTaH
                            07.03.2019 20:24
                            +2

                            С одной стороны это так, с другой — при правильном подходе «трогать» moved-from переменную можно и нужно, потому что ее переиспользование, например, может убрать лишние вызовы конструкторов, которые бы требовались в случае ее пересоздания «с нуля». В общем, это вопрос такой… дискуссионный :)


                        1. 0xtcnonr
                          07.03.2019 20:31
                          -2

                          Если проще. Проблема тут заключается в том, что есть си и уровень машины — там есть только копирование. Изначально(да и сейчас по умолчанию) любое копирование объектов — копирование. Но — это изменилось тогда, когда появилось raii и когда копирование перестало быть копирование — к нему добавилась левая, внешняя raii-семантика. Т.е. не просто копирование данных/объекта — как в си(и как по умолчанию в С++), а ещё и копирование ресурсов(которым владеет объект).

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

                          Соответственно — move то же самое копирование каким оно было всегда и каким оно есть по дефолту. Это на базовом уровне. Далее к этому добавилась уже raii-семантика и мы не копируем ресурсы и перемещаем, т.е. забираем владение и ресурс.

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

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

                          Это проблема. И тут может быть только одно решение. Если логика объекта завязана на обращении с ресурсом, то мы либо должны создать какой-то «дефолтный» ресурсы, либо добавить состояние «ресурса нет».

                          чтобы вместо конструктора копирования была возможность вызвать конструктор перемещения

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

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


                      1. humbug
                        07.03.2019 20:17
                        +1

                        Вы н… на не понимаете в семантике матчасти и крестов. Нет никакого перемещения — есть копирование. Семантика на то и семантика, что это левая в отношении языка семантика. Эти вызваны все ваши проблемы и ошибки в комменте выше.
                        Поэтому, сообщаю вам новость — начальный объект остаётся объектом, копия есть копия. Внутренние данные(которые ресурсы) перемещаются, т.е. передаётся владение. От сюда взялось это поведение и оно ВСЕГДА будет — это объективная реальность и от этого никуда не уйти.

                        Что вы сказали верно для С++. Для Rust мув семантика другая. Вот пример:


                        struct X {}
                        impl Drop for X {
                            fn drop(&mut self) { println!("drop"); }
                        }
                        
                        fn main() {
                            let x1 = X{};
                            let x2 = x1;
                            let x3 = x2;
                            let x4 = x3;
                            let _ = x4;
                        }

                        Поиграться онлайн https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f2faaa4dc6c0ea78f8a0416d68a21941


                        То есть будет создан один инстанс структуры X и этот инстанс будет передаваться по x1 -> x2 -> x3 -> x4, а затем разрушится, т.к. закончится время жизни.


                        Поэтому если мы в Rust перемещаем объект, то ссылки на него должны были бы инвалидироваться, если бы не отслеживание времени жизни и борроу чекер.


                        Вы говорите правильные вещи, и делаете правильные выводы, но исходите из неправильных предпосылок. Вы не принимаете во внимание, что некоторые вещи в Rust могут быть сделаны отличным(иным) образом.


                        1. 0xtcnonr
                          07.03.2019 21:02
                          -1

                          Что вы сказали верно для С++.

                          Неверно — это верно ДЛЯ ВСЕГО. А верно для С++ оно не потому, что «С++ такой особенной», а потому что он использует базовую модель — не абстрагируясь от неё.

                          Для Rust мув семантика другая. Вот пример:

                          Это не мув — это внешний интерфейс. А он никому не интересен — мы не в мире пхп.

                          То есть будет создан один инстанс структуры X и этот инстанс будет передаваться по x1 -> x2 -> x3 -> x4, а затем разрушится, т.к. закончится время жизни.

                          Ещё раз, это убогая абстракция, которая кому-то интересна только в мире пхп. У нас тут как-бы zero-cost, системщина и вся фигня.

                          Поэтому если мы в Rust перемещаем объект, то ссылки на него должны были бы инвалидироваться, если бы не отслеживание времени жизни и борроу чекер.

                          Ну что же так сложно всё. Мы не можете перемещать объекты — вы можете их только копировать. Если вы копируете — это инвалидирует ссылки на x1. Поэтому, ваша имплементация либо не позволит брать ссылки на x1, либо всё переменные будут ссылками.

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

                          Да, тут можно накостылять какой-то херни, которая либо даст возможность брать ссылки, либо мувать. Но любая имплементация этого СТАТИЧЕСКИ накладывает ГИГАНТСКИЕ ограничения на рантайм.

                          Поэтому если мы в Rust перемещаем объект, то ссылки на него должны были бы инвалидироваться, если бы не отслеживание времени жизни и борроу чекер.

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

                          Ещё раз повторю. Есть базовые вещи на базе которых работает железяка, тот же llvm и никуда вы от них не уйдёте. И это НЕ ИМЕЕТ НИКАКОГО ОТНОШЕНИЯ К С++ — это лишь случайность(вернее закономерность), что эти реалии просачиваются на уровень языка.

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

                          И ещё раз повторю. Да нету никаких других предпосылок. Вы просто пытаетесь выдать одно за другое. Принципы матчасти вы пытаетесь выдать за принципы С++ и делать вид, что будто бы раст их может как-то изменить — нет, он их изменить никак не может. Это аксиома и её нельзя нарушить. Низ диктует условия верху и никак иначе.

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

                          Я всё понимаю, я понимаю, что можно построить такую модель, в рамках которой всё, что вы описываете — будет работать. И судя по всему она действительно существует и работает, но меня это НЕ ИНТЕРЕСУЕТ — это интересует вас.

                          Меня интересует именно ВОЗМОЖНОСТИ НАПИСАТЬ ТО, что мне нужно. И я понимаю, что эта модель НЕ ДАСТ этого сделать и вы сами это подтверждаете.

                          И я спорю не с растом — мне абсолютно неважно. Я не люблю С++ не меньше, чем раст. Я спорю с тем, что вы(по крайней мере адепты раста в целом, и ваши тезисы очень подоходят) пытаются выдать эту ФЕНТЕЗИЙНУЮ МОДЕЛЬ за АНАЛОГ БАЗОВОЙ(т.е. крестовой модели) и сообщить, что ОНА МОЖЕТ ВСЁ, ЧТО МОЖЕТ БАЗОВАЯ, НО ЛУЧШЕ.

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

                          ВСЕГДА МОЖНО СОЗДАТЬ ТАКУЮ МОДЕЛЬ, в которой НЕ БУДЕТ каких-то ПРОБЛЕМ, но НИКОГДА нельзя это сделать БЕСПЛАТНО. Всегда всё это будет ПОКУПАТЬСЯ за ОВЕРХЕД любых ПОРЯДКОВ.

                          Именно поэтому раст состоит на 90% из синтакического мусора и ограничений. И предпринимает постоянные попытки выдать ГОВНО за РЕШЕНИЕ. Нелепые попытки оправдать отсутствие исключений, присутствия мусора, нагромождения рандомных символов в синтаксисе, неконсистентность синтаксиса — когда везде и всюду в язык просто запихивают любую херню не беспокоясь ни о чём — лишь бы было. Просто помойка.

                          Постоянные подмены понятий, какой-то pattern matching, Result, сумтипы и прочая херня. Попытки выдать это за какие-то «супер-необходимые вещи», но реально это просто убогие костыли для решение проблем с синтаксическим мусором.

                          Кто-то принёс в язык очередной херню типа ?(перепастим очередную херню из пхп) — постоянные попытки бежать и всем рассказывать об этом мусоре, о том как это круто. МНЕ НАСРАТЬ. Это убогая херня, которая мне не нужна. Я хочу и буду писать код так, чтобы в нём не было мусора и меня абсолютно не должна волновать вера каких-то там студентов-героев.

                          Я не хочу набегов сектантов на темы с крестами, постоянные попытки везде и всюду сообщить о расте — мне насрать. Это клоуны вместо того, чтобы бегать везде и орать — сделали бы хоть что-то. Где хоть один уникальный конкурентоспособный проект? Дохлое серво? А может уже и openssl есть? Я помню эти оры и крики.


                          1. humbug
                            07.03.2019 21:17
                            +2

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

                            Не копирование, а перемещение. И ссылки не инвалидируются, так как невозможно переместить объект, на который есть живые ссылки. Отслеживание чудесно решает проблему. Если ссылка может пережить объект — то это неправильный код даже по меркам C++. Тот же gcc уже умеет трекать возврат ссылки на локальную переменную из функции. Подобная логика и у компилятора Rust'a, только информации о времени жизни переменных гораздо больше.


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

                            А зачем вам уметь сохранять ссылку на дохлый объект в глобальном скоупе? Обращение к ней является UB.


                            По количеству капслока и истерии можно понять, что клиент готов)


                            1. 0xtcnonr
                              07.03.2019 21:40
                              -2

                              Не копирование, а перемещение.

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

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

                              Вам пример в другом сообщение дали — я думаю, что вы там мне подсчитаете ссылки.

                              Если ссылка может пережить объект — то это неправильный код даже по меркам C++.

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

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

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

                              А зачем вам уметь сохранять ссылку на дохлый объект в глобальном скоупе? Обращение к ней является UB.

                              С чего вдруг он долхый? Дохлый он только в ваших фантазиях.

                              По количеству капслока и истерии можно понять, что клиент готов)

                              О да, это так привычно для адепта раста — путать реальность и свои фантазии.


                              1. humbug
                                07.03.2019 21:50
                                +1

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

                                Математика. Хотите с ней поспорить?


                                Копирование, я уже сообщил, что никакого перемещение на уровне имплементации нет. Это аксиома.

                                Это ошибочное допущение. Опять же если вы хотите поспорить с логикой и математикой, пишите в спортлото в Max Planck Institute for Software Systems, именно они написали пейпер и формально доказали корректность системы типов Раста.


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


                                1. 0xtcnonr
                                  07.03.2019 21:55
                                  -1

                                  Математика. Хотите с ней поспорить?

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

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

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


                                  1. humbug
                                    07.03.2019 21:57
                                    +1

                                    А чего тут гуглить? Читайте people.mpi-sws.org/~dreyer/papers/rustbelt/paper.pdf и пишите в спортлото Max Planck Institute for Software Systems. +1 ревью не повредит.


                                    1. 0xtcnonr
                                      07.03.2019 22:09
                                      -2

                                      А чего тут гуглить?

                                      А, адепт уже погуглил?

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

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


                              1. freecoder_xx
                                07.03.2019 23:14

                                Так вы наверное пользуетесь только языками, в которых есть goto. Ведь его выпиливание накладывает на программиста ограничения и заставляет писать «синтаксический мусор», верно? Да еще и не бесплатно это! Так что в топку структурное программирование, так?


                                1. 0xtcnonr
                                  07.03.2019 23:24

                                  К чему написана эта нелепая ахинея?

                                  Так вы наверное пользуетесь только языками, в которых есть goto

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

                                  И какой же синтаксический мусор заставляет писать goto? В вашей методичке написано? Или как всегда — нет?
                                  Да еще и не бесплатно это!

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

                                  Поэтому, если есть какой-то «язык» без goto — он может быть кем угодно и никто его трогать не будет. Но если адепты этого «языка» придут ко мне и начнут мне рассказывать о том, что их «язык без goto» может всё то же, что может goto так же эффективно — они будут посланы туда, куда и должны быть посланы.

                                  Попытка неудачная — повторите ещё раз.


                          1. KanuTaH
                            07.03.2019 21:19

                            Не могу сказать, что согласен с вашей формой подачи мысли, но с общим посылом я скорее согласен. Мой личный опыт показывает, что ЛЮБЫЕ абстракции класса «видеонаблюдение в туалете работает для вашей безопасности» либо ограничивают возможности по написанию эффективного кода, либо «протекают» на нижестоящие уровни (привет, unsafe), либо (что чаще всего) делают и то, и другое. Ничего не бывает бесплатно, а те, кто рассказывает про «zero cost» таких абстракций обычно либо чего-то не понимают, либо чего-то не договаривают.


                            1. humbug
                              07.03.2019 21:25

                              Ничего не бывает бесплатно.

                              Не бывает бесплатной свободы С++: люди платят за нее багами. Не бывает бесплатной безопасности Rust: люди платят за нее сложным кодом.


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


                              1. KanuTaH
                                07.03.2019 21:30

                                Идеология C++ заключается в том, что «ты не платишь за то, что не используешь». Идеология Rust — «железной рукой загоним человечество к счастью». Кому-то, может быть, и «железной рукой» годится, но не всегда и не везде.


                                1. humbug
                                  07.03.2019 21:34

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

                                  Да, кому-то подходит одно, кому-то подходит другое. Но это не повод к переходу на фекально-эльфийский капслок =)


                                1. PsyHaSTe
                                  07.03.2019 22:16

                                  У раста ровно та же идеология. В расте не надо платить за то, чем не пользуешься.

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

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


                                1. freecoder_xx
                                  07.03.2019 23:20

                                  Идеология C++ заключается в том, что «ты не платишь за то, что не используешь».

                                  Ага, зато постоянно платишь трудноуловимыми багами за то, что используешь =)


                                  1. KanuTaH
                                    07.03.2019 23:27

                                    Ага, зато постоянно платишь трудноуловимыми багами за то, что используешь =)

                                    Не «постоянно», но бывает. Впрочем, как и в других языках. Рассчитывать, что язык сам по себе спасет тебя от «трудноуловимых багов» несколько наивно, ко всему надо прикладывать голову.


                                1. TargetSan
                                  07.03.2019 23:48

                                  «ты не платишь за то, что не используешь»

                                  К сожалению, это относится только к затратам времени выполнения, да и то не полностью (см. исключения). Когнитивные затраты на ручной lifetime management в голове не регламентированы никак.


        1. domix32
          07.03.2019 12:14
          +1

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


    1. TargetSan
      06.03.2019 13:26
      +3

      Увы, все вкусняшки мира не спасут от тонн легаси. Так что всё равно попробуйте.


  1. Elsedar
    06.03.2019 12:24
    +2

    А можно ли будет использовать std::flat_* структуры с, например, std::array, если мы точно знаем макс. количество элементов и не хотим динамической аллокации?


    1. antoshkka Автор
      06.03.2019 12:46
      +1

      У std::array нет методов insert, но вот с static_vactor использовать можно будет.


  1. rsashka
    06.03.2019 12:33
    +3

    Добавьте в опрос пункт «Ничего не пригодится», а то он какой-то однобокий получается


    1. antoshkka Автор
      06.03.2019 13:01
      +5

      У меня лично была проблема выбрать что-то одно, а не всё сразу :)


  1. Antervis
    06.03.2019 12:45
    +3

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


    1. antoshkka Автор
      06.03.2019 12:50

      format сделали прям шикарным. Лучше чем в fmtlib, за счёт того что отвязали функции форматирования от медленного std::locale.


      1. TargetSan
        06.03.2019 12:54
        +2

        std::locale в частности и iostreams вообще надо бы по хорошему закопать нафиг и больше не трогать.


        1. antoshkka Автор
          06.03.2019 12:56

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


          1. TargetSan
            06.03.2019 13:17

            Не могу не согласиться. И это вдвойне грустно.


      1. nitrofox
        06.03.2019 13:45

        А в стандарт попадет что-то типа print и println с нормальным форматированием?


        1. antoshkka Автор
          06.03.2019 13:50
          +1

          std::format + любой метод вывода покрывают функционал print и println:

          std::cout << std::format("Hello {} {} times\n", "world", 42);


          1. myxo
            06.03.2019 20:55

            Но согласитесь, это как-то не очень =/
            Я думаю многим эта фича будет нужна именно для вывода на экран. Ну что ж… будем наблюдать шаблонную my_print в каждом втором проекте =)


          1. nitrofox
            07.03.2019 10:48

            Я думал что вся fmtlib перекочует в стандарт. Жаль. Удобная библиотека.


          1. TargetSan
            08.03.2019 17:33

            Т.е. он не будет уметь zero allocation из коробки?


            1. antoshkka Автор
              08.03.2019 20:39

              std::format умеет форматировать в подставленный пользователем буффер и в этом случае не делает динамических аллокаций (разве что вы попросите его форматировать с использованием std::locale).


  1. TargetSan
    06.03.2019 12:57

    Возможность эффективно извлекать строки из std::*stringstream и передавать во владение пользовательские строки P0408

    Наконец-то! Впрочем, с появлением std::format этот архаизм можно выкинуть на помойку — что ещё лучше.


  1. QtRoS
    06.03.2019 13:06
    -7

    А это нормально теперь на Хабре вместо полезного названия использовать кликбейт?.. Что дальше будет? "С С++20 ОНИ СДЕЛАЛИ ЭТО..."?


    1. antoshkka Автор
      06.03.2019 13:41
      +1

      Заменил «Приняли ли Modules b Coroutines» на «Coroutines, Modules и прочее». Надеюсь так стало лучше.


  1. TargetSan
    06.03.2019 13:13
    +2

    Где-то можно почитать о том, как предполагается использовать модули, со всеми их партишенами и другой эзотерикой? Неясно даже, единицу чего представляет модуль.


    1. antoshkka Автор
      06.03.2019 14:04

      На эту тему готовится отдельный документ от комитета «C++ Ecosystem Technical Report». Об этом есть немного вот тут, и ответы 3 на самых частых вопроса вот тут.


  1. graninas
    06.03.2019 13:46
    +2

    Лично меня радует, что из четырех мажорных фич две пришли из мира ФП и/или из Haskell.

    Concepts
    Coroutines
    Modules
    Ranges


    Предлагаю аббревиатуру:
    CoCoMoRa


    1. antoshkka Автор
      06.03.2019 13:52
      +1

      Там ещё и монадические интерфейсы к std::optional обсуждаются, чтобы порадовать любителей ФП.


      1. 0xd34df00d
        06.03.2019 19:45

        Их же через корутины легко выразить (а вот для Either у меня не получилось).


        1. antoshkka Автор
          06.03.2019 19:48

          Да, но хочется готовое изкоробочное решение


      1. humbug
        06.03.2019 19:58

        Мне кажется, важной фичей для std::optional должны быть как раз таки pattern matching, потому что для optional::operator* сказано:


        This operator does not check whether the optional contains a value! You can do so manually by using has_value() or simply operator bool(). Alternatively, if checked access is needed, value() or value_or() may be used.

        То есть при его использовании возможно возникновение неопределенного поведения.


        Конечно можно возразить, что надо использовать вот так:


        if (opt.has_value()) {
            auto... value = *opt;
        }

        И что есть optional::value, которое проверяет наличие и возбуждает исключение при отсутствии значения. Но ЁКЛМН, люди ошибаются, опечатываются, неужели вам нужна экономия на спичках, которая приводит к UB? Что быстрее напечатать, *opt или opt.value()? Что будет сильнее бросаться в глаза, *opt или opt.value_unsafe_unchecked(), если уж экономите один бранч на проверке наличия значения?


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


        1. zuko3d
          07.03.2019 08:28

          Я не знаю наверняка, но выглядит так, будто это сделано чтобы воссоздать поведение boost::optional.
          Люди уже привыкли таким образом использовать optional в бусте и не могут проект одним махом перевести с boost::optional на std::optional. Разный принцип работы operator* и ::value() внутри одного большого проекта создаст гораздо больше проблем.


    1. mayorovp
      06.03.2019 15:23
      -4

      Какие именно?

      Concepts — давно уже существовали в документации к библиотекам.
      Coroutines пришли из C#
      Modules — давно уже есть во всех нормальных языках программирования кроме Си и С++
      Ranges — слишком очевидны чтобы приходить откуда-то…


  1. Amomum
    06.03.2019 14:27
    +5

    Скажите пожалуйста, а войдет ли в С++20 P0631 (Math constants)? Дождемся ли мы наконец-то числа Пи в стандарте? Или так и будем atan(1)*4?


    1. Antervis
      06.03.2019 14:57
      +2

      Или так и будем atan(1)*4?

      лучше acos(-1) )


      1. Amomum
        06.03.2019 15:10
        +3

        Т_Т


    1. Dima_Sharihin
      06.03.2019 15:14

      Можете пользоваться <cmath>, там есть M_PI,
      upd: а, блин, это же нестандартное расширение GNU Libc


      1. Amomum
        06.03.2019 15:16

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


      1. Antervis
        06.03.2019 15:17

        в стандарте нет M_PI


    1. antoshkka Автор
      06.03.2019 15:24

      Их дизайн утверждён для принятия в C++20, но у LWG много вопросов по этому предложению. Так что может и не успеют попасть в C++20.


      1. Amomum
        06.03.2019 15:55
        +8

        Спасибо. Буду держать кулаки -_-'

        Я до сих пор не понимаю, как в С++11 умудрились пропихнуть столько нетривиальной математики, вроде вихрей Мерсенна, эрмитовых сплайнов и распределений Коши, но при этом не заюзать константы вроде Пи и е.


      1. Biga
        06.03.2019 17:52
        +3

        Не могут решить, чему равно PI в военное время?


        1. antoshkka Автор
          06.03.2019 18:19
          +1

          Непонятно, должны эти константы находиться в namespace std::math, или же это просто цифры, не обязательно относящиеся к математике. Непонятно, писать их шаблонными переменными типа X или шаблонными переменными типа X const& (в этом случае для редких кейсов получается экономия по месту). Непонятно, как разрешить пользователям кастомизировать эти переменные для своих типов, если до этого кастомизация шаблонных переменных не особенно была разрешена (можно ли добавлять свои переменные в namespace std?). Ну и возникли вопросы про денормализованные числа с плавающей запятой и их использование для подобных констант.


          1. DistortNeo
            06.03.2019 18:59
            +1

            Непонятно, должны эти константы находиться в namespace std::math, или же это просто цифры, не обязательно относящиеся к математике.

            Это как раз логично: эти константы должны находиться вместе с функциями, которые с этими константами работают (sin, exp), то есть в std, а не std::math.


            Непонятно, писать их шаблонными переменными типа X или шаблонными переменными типа X const& (в этом случае для редких кейсов получается экономия по месту)

            constexpr, не?


            Непонятно, как разрешить пользователям кастомизировать эти переменные для своих типов, если до этого кастомизация шаблонных переменных не особенно была разрешена

            А зачем эти константы вообще шаблонизировать?


            1. antoshkka Автор
              06.03.2019 19:13

              то есть в std, а не std::math

              Сейчас они в std::math

              constexpr, не?

              Это не панацея, например вот тут https://godbolt.org/z/Le22qh без использования ссылок появляются в коде дублирующиеся данные.

              А зачем эти константы вообще шаблонизировать?

              У пользователей могут быть (и есть!) свои числовые типы. Пользователи языка пишут свои шаблонные числовые алгоритмы:
              template <class Num>
              auto perim(Num r) {
                  return 2 * std::math::pi<Num> * r;
              }
              

              Без кастомизации пользователю придётся писать этот алгоритм ещё раз, для типов чисел для которых не специализирован std::math::pi. Если у вас сотня таких алгоритмов, использующих pi — ваша жизнь превратится в боль, а разработка в копипасту.


              1. DistortNeo
                06.03.2019 19:38

                Сейчас они в std::math

                Ну я вообще приверженец #include <math.h>, там всё в глобальном пространстве, просто вот тут написано, что в std, а не std::math.


                Это не панацея, например вот тут https://godbolt.org/z/Le22qh без использования ссылок появляются в коде дублирующиеся данные.

                Да, на существующих архитектурах нельзя загружать float/double как immediate value. Поэтому эта константа должна лежать где-то в памяти. Но константа pi абсолютно ничем не отличается от той же константы 1.0. Мы спокойно пишем в коде 1.0, не задумываясь, куда её положит компилятор. Если же вдруг нужно указать явно ссылку (например, при использовании SSE интринсиков), то тут не сложно положить константу куда-нибудь, где нам удобно, либо написать функцию-обёртку, отдав всё на откуп компилятору.


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


                У пользователей могут быть (и есть!) свои числовые типы. Пользователи языка пишут свои шаблонные числовые алгоритмы:

                Понимаю эту проблему, но в 99.99% случаев всё покрывается стандартными типами float, double и long double из стандарта IEEE-754. Достаточно ограничиться константами для этих трёх фундаментальных типов.


                Если же пользовать хочет использовать что-то своё, то флаг ему в руки, пусть пишет свой шаблонизированный вариант этой константы.


  1. vladimirkotik
    06.03.2019 18:35

    constexpr контейнеры и constexpr динамический полиморфизм

    Их уже приняли (std::string и std::vector)?


    1. antoshkka Автор
      06.03.2019 18:35

      Они одобрены для включения в C++20, но еще не прошли подгруппы Core и Library.


      1. vladimirkotik
        06.03.2019 18:37
        +1

        Спасибо.


  1. dev96
    07.03.2019 00:23

    Как раз на выходных занимался свои проектом и допиливал логгер на базе fmtlib и потихоньку начал прикручивать тот самый календарь (date) под MSVC из репозитория автора.
    Так вот, у меня созрел вопрос: как обстоят дела с часовыми поясами? Я не до конца разобрался в этом вопросе, но меня уже волнует вопрос быстродействия. Поскольку там парсится база часовых поясов и прям вшивается в runtime-api. Далее, насколько я понимаю, current_time_zone не инициализируется при запуске, как делается в либах C, а постоянно запрашивается и через строчный идентификатор возвращает объект date::time_zone. Просто как-бы если вовремя работы поменять часовой пояс, то сишный localtime вернет время по старому часовом поясу…
    У кого-нибудь есть не столь поверхностные познания об этих вещах? И проверял ли кто-нибудь быстродействие std::chrono + date в этом вопросе?

    P.S. Поюзал денек этот календарь и чет он не особо удобным показался, хотя я был рад его анонсу. А fmtlib в std очень рад. Теперь жду концепты и полноценную поддержку C++20.
    P.S.S. constexpr math — вот теперь заживем...)