Примечание переводчика: в текущий момент я подготавливаю материалы для обещанной статьи по монадам. К сожалению, это занимает довольно много времени, не говоря о том, что я всё же должен заниматься основной работой и уделять время семье, но процесс идёт. А пока представляю вам перевод небольшой свежей заметки от замечательного товарища Mark Seemann'а, которая мне показалась любопытной.


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


Церемонность


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


Церемония — это то, что вы делаете до того, как начнете делать то, что вы действительно собирались сделать.

Venkat Subramaniam

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


Это привело меня к мысли о том, что существует злосчастная Зона Церемонности:



Конечно же, эта диаграмма всего лишь упрощение, но я надеюсь, что она демонстрирует суть. C++, Java и C? — языки, которые требуют церемонности. Справа от них находятся языки, которые мы могли бы назвать транс-церемониальными, включая F? и Haskell.


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


Малое количество церемоний в JavaScript


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


> consume ([1,2,3], 1);
[ 2, 3 ]
> consume ([1,2,3], 2);
[ 3 ]
> consume ([1,2,3], 3);
[ 3 ]
> consume ([1,2,3], 4);
[]

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


В JavaScript эта функция могла бы быть реализована примерно так:



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


Большое количество церемоний в C?


Давайте сравним пример на JavaScript с кодом на C?. Та же самая функция на C? могла бы выглядеть так:



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


Но на самом деле всё еще хуже. Код выше работает только с int массивами. А что, если мы хотим использовать long?


Нам придется написать еще одну перегрузку:



Вам нужна поддержка shortов? Еще одна перегрузка. decimal? Еще одна. byte? Еще одна.


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


Малое количество церемоний в F?


Ту же самую функцию в F? можно написать так:



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


quantity: ^a -> (seq< ^b> -> seq< ^b>)
  when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^a) and
        ^a : (static member get_Zero : ->  ^a) and  ^a : comparison

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


> consume 2 [1;2;3];;
val it : seq<int> = seq [3]

> consume 2m [1m;2m;3m];;
val it : seq<decimal> = seq [3M]

Статическая типизация означает только то, что вы не можете вызвать её с произвольными значениями. Выражение вроде consume "foo" [true;false;true] просто не скомпилируется.


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


Малое количество церемоний в Haskell


Аналогично вы можете написать эту функцию в Haskell:



И снова вам не нужно указывать никаких типов. Компилятор просто их выведет. Вы даже можете спросить у GHCi о типе функции, и он вам выдаст:


> :t consume
consume :: (Foldable t, Ord a, Num a) => a -> t a -> [a]

Оно выглядит чуть более компактно чем выведенный в F? тип, но суть остается той же. Оно скомпилируется для любого Foldable контейнера (В том числе и об этом в следующей статье, прим. пер), и для любого типа, принадлежащему тайпклассам Ord и Num. Num поддерживает сложение, а Ord — сравнение.


Как вы можете видеть, в F? и Haskell требуется довольно мало церемоний, однако оба языка остаются статически типизированными. Более того, их система типов мощнее, чем у C? или Java. Они могут выражать такие взаимоотношения между типами, которые эти языки не могут.


Резюмируя


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


Но дело лишь в том, что мейнстримные статически типизированные языки просто занимают Зону Церемонности.


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

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


  1. A-Stahl
    04.01.2020 17:17
    +3

    А с чего это «небольшое количество церемоний» (т.е. отсутствие явного и внятного указания типа) — хорошо?
    Представьте себе магазин в котором все продукты хранятся в одинаковых непрозрачных коробках. Да, в коробку всегда можно загянуть. Да, на качество и суть самих продуктов это не влияет. Но это обычно неудобно. Разумеется если стоит задача забросить в выгребную яму 5 кубометров товаров, то такой подход совсем не мешает. Вот только… Хм. Да ну вас… Ок, не «церемоньтесь». Не очень-то и нужно. Бросайте свои данные в выгребную яму. Всё равно ваш ЯваСкрипт только для этого и используется. Хм…


    1. PsyHaSTe Автор
      04.01.2020 17:33
      +5

      Не понял, при чем тут коробки и всё остальное. Типы никуда не делись, просто их писать необязательно. Про то, что вывод типов удобнее чем их явное написание спросите у сишарпистов. Я помню как Java-разработчики запрещали в шарповых проектах var, потому что неочевидно.


      Лично я, конечно, за то, чтобы фиксировать типы в топ-декларациях, это в принципе считается правилом хорошего тона:


      consume :: (Foldable t, Ord a, Num a) => a -> t a -> [a]
      consume quantity = reverse . snd . foldl go (0, [])
        where
          go (acc, ys) x = if quantity <= acc then (acc, x:ys) else (acc + x, ys)

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


    1. Alexmaru
      04.01.2020 17:37
      +6

      просто это выглядит плачевно на некоторых случаев. Если ты указал, что i = 0, не трудно бы догадаться, что вероятнее всего там будет int. И эти догадки чаще облегчают жизнь.


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


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


      1. Nalivai
        05.01.2020 15:56

        не трудно бы догадаться, что вероятнее всего там будет int

        или uint, или string но ты кавычки забыл


        1. YemSalat
          05.01.2020 19:24
          +1

          или string но ты кавычки забыл

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

          или uint

          А вот такое вообще должно остаться только в языках «близких» к железу, вроде С/С++


        1. DarthVictor
          06.01.2020 13:37

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


  1. excoder
    04.01.2020 17:30
    +3

    А какие в С++ церемонии именно касательно типов? Auto и шаблоны уже давно к услугам автора. Имхо на С++ вполне себе можно писать в питоник-стиле.


    1. PsyHaSTe Автор
      04.01.2020 17:38
      +1

      Ну на самом деле на плюсах довольно вербозно. Например, возьмем функтор списка:


      class Functor f where
        fmap :: (a -> b) -> f a -> f b
      
      instance Functor [a] where
        fmap f (x:xs) = (f x) : (fmap f xs)

      и плюсы


      template<template<class> F, class A, class B>
      F<B> fmap(std::function<B(A)>, F<A>);
      
      template<class A, class B>
      std::vector<B> fmap(std::function<B(A)> f, std::vector<A> v) {
        std::vector<B> w;
        std::transform( std::begin(v)
          , std::end(v)
          , std::back_inserter(w)
          , f);
        return w;
      }

      Но вообще плюсы да, наверное чуть попроще в чем-то. Но в чем-то наоборот сложнее.


      1. excoder
        04.01.2020 18:54

        В моих проектах более-менее давно используются элементарные альтернативы грядущим ranges. Я обычно именую такую библиотеку pythonic или pt. Записать код выше более-менее симпатично без старой вербозной идиоматики итераторов вполне возможно. Да, нет одной стандартной замены. Это немного удручает.


        1. excoder
          04.01.2020 18:57

          И с std:: function так не стоит. Компилятор не соптимизирует, будет неоправданное замедление.


        1. PsyHaSTe Автор
          04.01.2020 19:05
          +1

          Ну, с новым стилем главное тоже не упороться :)


          И с std:: function так не стоит. Компилятор не соптимизирует, будет неоправданное замедление.

          К сожалению, я не очень близко знаком с плюсами. Буду иметь в виду, спасибо.


          1. excoder
            04.01.2020 20:26

            Да, это точно. Я потому и избегаю ranges по Ниблеру, так как куда-то это не туда зашло. :) Это бич С++, что в итоге все пишут какую-то свою метабиблиотеку, которая у всех примерно об одном, но в стандарте её нет. Зато есть всякое другое, иногда сломанное.


          1. selrorener
            04.01.2020 23:57

            К сожалению, я не очень близко знаком с плюсами. Буду иметь в виду, спасибо.

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


            Все остальные аннотации типов в 95% случаев несут только dx-назначение — поднять ошибки подстановки выше.


      1. selrorener
        04.01.2020 23:37

        и плюсы

        Вот плюсы:


        auto fmap(auto f, auto v) {
          return v | transform(f) | to<std::vector>();
        }

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


        1. 0xd34df00d
          04.01.2020 23:56
          +1

          auto fmap(auto f, auto v)

          Ух ты, C++20.


          И да, вы потеряли ограничение, что v должно быть вектором с элементами типа T, а f — функция из этого же T в некий U. Опционально можно указать, что возвращается вектор с элементами типа U.


          В плюсах все интерфейсы созданы из расчёта производительности.

          Ага, например, интерфейс std::unordered_map с доступом к конкретным корзинам (который, по факту, запрещает реализацию ряда куда более эффективных вариантов реализации хешмапы).


          1. selrorener
            05.01.2020 00:07

            Ух ты, C++20.

            Он там не особо нужен — после fmap можно добавить = [] и будет не С++20. Да и в чем проблема с С++20?


            Ага, например, интерфейс std::unordered_map с доступом к конкретным корзинам (который, по факту, запрещает реализацию ряда куда более эффективных вариантов реализации хешмапы).

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


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


            1. 0xd34df00d
              05.01.2020 00:29
              +1

              Он там не особо нужен — после fmap можно добавить = [] и будет не С++20.

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


              Да и в чем проблема с С++20?

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


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


              Попытка оптимизации одного приведёт к ограничению других оптимизаций.

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


              1. selrorener
                05.01.2020 00:53

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

                Я об писал выше. Это не выглядит плохо — это не выглядит сильным аргументом. Покажите для начала альтернативы приведённого функционала в F#/hs.


                К тому же, сами тезисы не очень верные. Перегрузку добавить можно композицией. Более точные указания типов добавить можно(это тоже С++20, но это не концепты — это уже давно есть). sfinae — покажите в других языках альтернативы.


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

                Не вышел стандарт? Поделитесь стандартом упомянутых автором перевода hs/scala/rust/F#? Либо хотя-бы F#/hs.


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


                Отсылки к продакшену так же не засчитываются. Потому как используется уже много где. Да и отсылки к продакшену на фоне F#/hs так же несостоятельны. Продакшена на актуальном компиляторе не меньше, чем того же продакшена на
                F#/hs.


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

                Это проблемы этого продакшена. Нас они волновать при сравнении не должны. К тому же, существует много продекшена на чём угодно. Другое дело, что у С++ продакшена тупо больше. А какого-нибудь F#/rust легаси вообще нет.


                Во-первых, ваш же исходный тезис был, гм, немного другим.

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


                Во-вторых, что именно оптимизирует вытаскивание некоторых кишок std::unordered_map наружу, да ещё и не очень удачных? Я, наверное, ни разу не видел проекта, где этим бы пользовались (или, вернее, где это было бы необходимо).

                Я не совсем понимаю. Вы ссылаетесь на то, что вы(или кто-то ещё) хотел написать более оптимальную хешмапу для stl, но она оказалась не совместима с интерфейсом? Зачем эта более оптимальная хешмапа в stl? Её можно использовать без проблем без каких-либо проблем — это С++.


                К тому же, не большая проблема задепрекетить api, которым никто не пользуется. Осталось только доказать, что это мешает. Здесь уже я не видел подобных работ.


                1. 0xd34df00d
                  05.01.2020 01:05
                  +1

                  Покажите для начала альтернативы приведённого функционала в F#/hs.

                  Какого именно? auto auto auto или рейнджей?


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

                  Как? Чтобы fmap работал и с optional, и с определённым в сторонней библиотеке типом, например, бинарного дерева. Или хешмапы (только по значениям, естественно).


                  sfinae — покажите в других языках альтернативы.

                  Они там не нужны. Туда завезли, например, тайпклассы.


                  Не вышел стандарт? Поделитесь стандартом упомянутых автором перевода hs/scala/rust/F#? Либо хотя-бы F#/hs.

                  Мне не нужен факт наличия шильдика ISO самого по себе, мне нужно знать, могу ли я рассчитывать на то, что эту фичу в обозримом будущем не сломают. Отсутствие зарелиженного стандарта эквивалентно непринятому пропозалу в hs-коммьюнити, например.


                  Поддерживающий компилятор есть.

                  Как он называется? А то ни кланг, ни гцц не поддерживают C++20.


                  Отсылки к продакшену так же не засчитываются. Потому как используется уже много где. Да и отсылки к продакшену на фоне F#/hs так же несостоятельны.

                  Делюсь исключительно личным опытом. В месте, где в проде в 2016-м году только перешли на C++11 (прописью: одиннадцать), и при этом в том же 2016-м был в том же проде хаскель, я работал. В месте, где в 2019-м году в проде был gcc 6.1, не поддерживающий C++17, из какой-то там центоси, я тоже работал. Хаскель и свежайшая версия питона там тоже были.


                  Это проблемы этого продакшена. Нас они волновать при сравнении не должны.

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


                  А какого-нибудь F#/rust легаси вообще нет.

                  ну вот забавно, что плюсы у вас легаси.


                  Вы ссылаетесь на то, что вы(или кто-то ещё) хотел написать более оптимальную хешмапу для stl, но она оказалась не совместима с интерфейсом? Зачем эта более оптимальная хешмапа в stl? Её можно использовать без проблем без каких-либо проблем — это С++.

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


                  И вы так и не сказали, на компромисс с какой именно характеристикой (кроме невнимательности, конечно же) идёт текущая реализация.


                  К тому же, не большая проблема задепрекетить api, которым никто не пользуется. Осталось только доказать, что это мешает. Здесь уже я не видел подобных работ.

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


                  1. selrorener
                    05.01.2020 01:23

                    Какого именно? auto auto auto или рейнджей?

                    Того, на который вы ссылались. sfinae/перегрузку/decltype


                    Как? Чтобы fmap работал и с optional, и с определённым в сторонней библиотеке типом, например, бинарного дерева. Или хешмапы (только по значениям, естественно).

                    В чём проблема? Лямбда — это просто оператор(). Композиция лямбд — композиция этих операторов. Всё так же как и просто с перегрузкой оператора().


                    Они там не нужны. Туда завезли, например, тайпклассы.

                    Покажите пример того, о чём говорили. Допустим, перегрузка по decltype.


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

                    Раз шильдик неважен — не говорите о нём.


                    Отсутствие зарелиженного стандарта эквивалентно непринятому пропозалу в hs-коммьюнити, например.

                    Основания.


                    Как он называется? А то ни кланг, ни гцц не поддерживают C++20.

                    Никакого С++20 теймплейты в лямбдах не требуют. Я ссылался на p0428r2 и по вашей ссылке он реализован, причём реализован очень давно.


                    Делюсь исключительно личным опытом.

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


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


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

                    Это не проблема не языка, а тех, кто даёт такое. С таким же успехом можно хаять скалу/котлин за то, что на 95% прода дадут жаву.


                    ну вот забавно, что плюсы у вас легаси.

                    Для меня легаси не плюсы. Я нигде такого не говорил. Для меня легаси — это легаси. А на плюсах оно или на пхп — мне без разницы.


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

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


                    И вы так и не сказали, на компромисс с какой именно характеристикой (кроме невнимательности, конечно же) идёт текущая реализация.

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


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

                    Какие ваши доказательства?


                    1. 0xd34df00d
                      05.01.2020 02:51
                      +2

                      sfinae/перегрузку

                      Реализуется через тайпклассы.


                      decltype

                      Не нужно в виду неявной типизации.


                      В чём проблема? Лямбда — это просто оператор(). Композиция лямбд — композиция этих операторов. Всё так же как и просто с перегрузкой оператора().

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


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


                      Покажите пример того, о чём говорили. Допустим, перегрузка по decltype.

                      Я не знаю, что вы имеете в виду под перегрузкой по decltype, потому что общепринятого такого термина нет.


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


                      Если вы имели в виду SFINAE и проверку на соответствие какому-то концепту, то вместо ad-hoc-костылей вы, ну, просто пишете тайпкласс.


                      Раз шильдик неважен — не говорите о нём.

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


                      Основания.

                      Да.


                      Никакого С++20 теймплейты в лямбдах не требуют.

                      Это кусок C++20. Значит, темплейты в лямбдах требуют C++20.


                      Можно доказать это ещё более формально, но не хочу быть занудой.


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

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


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

                      Я вот прям вчера дёргал библиотеку, которая возвращает std::unordered_map из чего-то в чего-то. Правда, её название вам вряд ли о чём-то скажет.


                      Или вот та же nlohmann/json умеет работать с std::unordered_map, а не с аналогами от folly, abseil или чего там.


                      Какие ваши доказательства?

                      Титусовское вообще легко гуглится: вот.


                      Ресёрч на тему совместимости какой-нибудь там open addressing пополам с cuckoo hashing с unordered_map гуглится чуть сложнее, но их несовместимость — это уровень фольклора (в математическом смысле), не надо писать статьи, чтобы показать, что 2+2 ? 5.


                      1. selrorener
                        05.01.2020 03:44
                        -1

                        Реализуется через тайпклассы.

                        Покажите.


                        Не нужно в виду неявной типизации.

                        Т.е. нельзя? Никакая явная типизация не может, потому как она не сможет в такое decltype(a + b)


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

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


                        Зачем что-то утверждать не имея представления о предмете.


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

                        Если мне нужно передать имя — я заюзаю лямбду/типа. Точно так же я могу передать его через лямбду. [](auto ... args) { return f(args...); } — так.


                        Я не знаю, что вы имеете в виду под перегрузкой по decltype, потому что общепринятого такого термина нет.

                        (auto a, auto b) -> decltype(f(a, b)) перегрузка для случая, когда тип данного выражения выводится. Т.е. функция есть и оно возвращает значение какого-либо типа. Реализуйте тоже самое "не на костылях".


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

                        Нет, это не основной документ. Это просто то, что есть у С++ и чего нет у раста/хаскеля и прочего. Нет смысла ссылаться на стандарт в ситуации, когда у оппонента его нет.


                        Да.

                        Оснований нет, хорошо. Зачем о чём-то пытаться рассуждать, если оснований нет?


                        Это кусок C++20. Значит, темплейты в лямбдах требуют C++20.

                        Никто не измеряет стандарты в компиляторах какими-то С++20. Зачем вы, опять же, рассуждаете о том, в чём не разбираетесь? Там половина компиляторов вообще никакой стандарт "полностью" не поддерживает.


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


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

                        У меня другой опыт. Какой смысл ссылаться на чей-то опыт?


                        Я вот прям вчера дёргал библиотеку, которая возвращает std::unordered_map из чего-то в чего-то. Правда, её название вам вряд ли о чём-то скажет.

                        И что?


                        Или вот та же nlohmann/json умеет работать с std::unordered_map, а не с аналогами от folly, abseil или чего там.

                        json особенно nlohmann — это прикладуха. Какой смысл ссылаться на nlohmann, который вообще не имеет никакого отношения к производительности?


                        Титусовское вообще легко гуглится: вот.

                        И что? Это документ 2 месячной давности. Очевидно, что никто там за 2 месяца ничего и нигде не изменит.


                        К тому же, этот документ про abi. И там даже явно написано


                        API-compatible unordered_map

                        Т.е. он вообще противоречит вашим тезисам.


                        Ресёрч на тему совместимости какой-нибудь там open addressing пополам с cuckoo hashing с unordered_map гуглится чуть сложнее, но их несовместимость — это уровень фольклора (в математическом смысле), не надо писать статьи, чтобы показать, что 2+2 ? 5.

                        2+2 != 5 гуглится просто. К тому же, нужны конкретные предложения и конкретные сравнения. Всё остальное — не говорит о какой-то проблеме в смене api.


                        1. 0xd34df00d
                          05.01.2020 08:02
                          +3

                          Покажите.

                          Я ж писал уже — просто пишете инстанс Functor для другого типа, а fmap выбирается уже согласно типу в точке вызова.


                          Т.е. нельзя? Никакая явная типизация не может, потому как она не сможет в такое decltype(a + b)

                          А зачем это надо?


                          Вот получили вы тип результата выражения. А дальше-то что вы с ним делаете?


                          С чего вдруг?

                          С определения понятия перегрузки функции?


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


                          Если мне нужно передать имя — я заюзаю лямбду/типа. Точно так же я могу передать его через лямбду.

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


                          [](auto… args) { return f(args...); } — так.

                          Неверно.
                          [](auto&&... args) -> decltype(auto) { return f(std::forward<decltype(args)>(args)...); }.


                          Написал и прям ощутил мощь системы типов языка.


                          (auto a, auto b) -> decltype(f(a, b)) перегрузка для случая, когда тип данного выражения выводится. Т.е. функция есть и оно возвращает значение какого-либо типа. Реализуйте тоже самое "не на костылях".

                          Зачем? Что вы дальше с этой функцией делать будете? Вы ведь не пишете код с той лишь целью, чтобы написать вот такую сигнатуру?


                          decltype здесь — кусок SFINAE, костыль поверх отсутствующего механизма адекватной спецификации требований к типам (и их проверки).


                          Размахивать костылями «а у вас таких нет» — ну такое.


                          Оснований нет, хорошо. Зачем о чём-то пытаться рассуждать, если оснований нет?

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


                          Нет, это не основной документ.

                          Вау.


                          А какой основной документ? Куда вы идёте, когда компилятор ведёт себя не так, как вы ожидаете от него, например?


                          Никто не измеряет стандарты в компиляторах какими-то С++20. Зачем вы, опять же, рассуждаете о том, в чём не разбираетесь?

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


                          Никто не сидит и не реализует какой-то там "весь стандарт".

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


                          И что?

                          Универсальный ответ. Возьму на вооружение.


                          json особенно nlohmann — это прикладуха. Какой смысл ссылаться на nlohmann, который вообще не имеет никакого отношения к производительности?

                          Удобно, ненастоящий шотландец.


                          Хорошо хоть не скриптуха.


                          И что? Это документ 2 месячной давности. Очевидно, что никто там за 2 месяца ничего и нигде не изменит.

                          Этот документ подытоживает многолетний опыт работы в комитете (ну работы и на позиции одного из главных по поддержке кучи легаси в компании с одной из крупнейших в мире кодовых баз, наверное).


                          К тому же, этот документ про abi.

                          Если тяжело поменять ABI, то API тем более тяжело поменять.


                          Т.е. он вообще противоречит вашим тезисам.

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


                          Инвертируйте утверждения правильно.


                          1. selrorener
                            05.01.2020 12:20
                            -2

                            Я ж писал уже — просто пишете инстанс Functor для другого типа, а fmap выбирается уже согласно типу в точке вызова.

                            Напишите.


                            А зачем это надо?
                            Вот получили вы тип результата выражения. А дальше-то что вы с ним делаете?

                            С ним что-то делает в момент вычисления типа. Я объяснил что выше.


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

                            Зачем вы продолжаете писать глупости? Вам сообщили про композицию лямбд — там работает перегрузка. Всё.


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

                            Если мне нужно имя — я пишу структуру/лямбду. Я ни на что не надеюсь.


                            Неверно.

                            Верно, а ваша перепаста к теме отношения не имеет. Потому как никакого форварда в хаскеле нет. А значит и в С++ нет. Либо показывайся pf/ссылки и прочее в хаскеле.


                            Зачем? Что вы дальше с этой функцией делать будете? Вы ведь не пишете код с той лишь целью, чтобы написать вот такую сигнатуру?

                            Зачем вы съезжаете с темы? Я пишу код для того, что-бы у меня была перегрузка. Показывайте на хаскеле аналогичный функционал. Мне нужно при наличии f() — один вызов, а при наличии, допустим, x() — другой.


                            decltype здесь — кусок SFINAE, костыль поверх отсутствующего механизма адекватной спецификации требований к типам (и их проверки).

                            Нет, очевидно. Это не кусок sfinae


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

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


                            А какой основной документ?

                            А какой основной документ у хаскеля?


                            Куда вы идёте, когда компилятор ведёт себя не так, как вы ожидаете от него, например?

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


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

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


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

                            А, ну т.е. всё, аргументация кончилась?


                            Универсальный ответ. Возьму на вооружение.

                            Ответ достойный глупостям, что были написаны выше. Какому какое дело до того, что вы там дёргали? Вы выдвигали тезис "везде в С++", а после ссылались на "я". Очевидно, что это позор.


                            Удобно, ненастоящий шотландец.

                            Аргументов опять нет? Так и запишем. Или мне бенчмарки доставать? Хотя уже всё забенчено за меня.


                            Этот документ подытоживает многолетний опыт работы в комитете (ну работы и на позиции одного из главных по поддержке кучи легаси в компании с одной из крупнейших в мире кодовых баз, наверное).

                            Пруфы.


                            Если тяжело поменять ABI, то API тем более тяжело поменять.

                            Нет, очевидно. Т.е. вы засыпались с примеров, выдавая его не за то, о чём говорили? А теперь уже пошли отговорки вида "да abi/api — какая разница". А чего же так?


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

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


        1. PsyHaSTe Автор
          04.01.2020 23:56
          +2

          Вот плюсы:

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


          пример явно манипулятивный.

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




          Тем более, что в мире остается 99.999% кода, написанного в ином стиле, и это надо учитывать. Я вот очень сомневаюсь, что если завтра вам понадобится написать в рабочем коде такую функцию, то вы её вот таким однострочником запишете.


          1. selrorener
            05.01.2020 00:20

            Насколько я понимаю, этот синтаксис буквально вот-вот появился.

            Нет, из нового там только auto, но в данном случае функция тут ненужна — её можно заменить на лямбду добавлением двух символов. auto там уже давно есть.


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


            А пример, который я взял, я взял из книжки 2017 года. Поэтому ваше утверждение что

            Ну это явно не 17 год, даже если книжка 17 года.


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

            Манипулятивный не в этом смысле. Это базовый пример из fp-букваря с откусыванием элемента списка. В С++ просто нету таких интерфейсов и не потому, что их нельзя сделать — нет. Просто они не пользуются спросом.


            Тоже самое и с fmap. Здесь создаётся новый список, что в языка типа С++ не приемлемо, поту как очень медленно. Поэтому там и реализовать transform с такой семантикой — он призван в основном для мутаций, но не только.


            Допустим, я вынужден был написать to<vector>(), который там не нужен. Так же я вынужден был принять вектор "по значению", что так же не оптимально.


            Так же, в С++ вообще контейнеры как таковые кого-то мало волнуют. Поэтому и принимаются итераторы.


            Т.е. данный код целиком и полностью противоречит принятым в С++ подходам. Но он целиком и полностью соответствует паттернам принятым в хаскеле. Он и взят из хаскель-букваря.


            В этом и заключается манипуляция, на мой взгляд.


            1. 0xd34df00d
              05.01.2020 00:33
              +1

              Тоже самое и с fmap. Здесь создаётся новый список, что в языка типа С++ не приемлемо, поту как очень медленно.

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


              И да, воспринимайте ФП-шный список как такой итератор на стероидах, а не как структуру данных.


              1. selrorener
                05.01.2020 00:57

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

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


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

                Только вот в данном коде ничего не рассказывается. А никакие оптимизации на "авось" не полагаются. Предсказуемость — это база любой оптимизации.


                И да, воспринимайте ФП-шный список как такой итератор на стероидах, а не как структуру данных.

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


                1. 0xd34df00d
                  05.01.2020 01:08
                  +1

                  Это просто оптимизация находящая за рамками семантики. Она ни о чём не говорит.

                  И не в C++ ее сделать проще, потому что компилятору о коде рассуждать проще.


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

                  Это типа на race condition'ы намёк? Спасибо, оценил.


                  Только вот в данном коде ничего не рассказывается. А никакие оптимизации на "авось" не полагаются. Предсказуемость — это база любой оптимизации.

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


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

                  Примерно потому же, почему я не умножаю матрицы на итераторах.


                  1. selrorener
                    05.01.2020 01:31

                    И не в C++ ее сделать проще, потому что компилятору о коде рассуждать проще.

                    В С++ её ненужно делать — она уже сделана на уровне семантики.


                    Это типа на race condition'ы намёк? Спасибо, оценил.

                    Нет, это намёк на что угодно. Самое интересное тут то, что вы сами выше ссылаетесь на то, что компилятор в кишках заменяет(чисто на уровне тезисов и даже на уровне них — исходя из фазы луны) всё на мутельные структуры данных. А теперь уже это race condition'ы?


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


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

                    Ещё раз — это ничего не значит. Нет никаких гарантий. К тому же, копия как минимум одна да будет. В случае с С++ её не будет.


                    Примерно потому же, почему я не умножаю матрицы на итераторах.

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


                    Почему ваши тезисы расходятся с действиями?


                    1. 0xd34df00d
                      05.01.2020 03:03

                      В С++ её ненужно делать — она уже сделана на уровне семантики.

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


                      Везде, где производительность — везде мутации. Именно поэтому вы идёте и используете массивы.

                      Да, и?


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


                      Каждой задаче свой инструмент.


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

                      Ага. Вы правда не надеетесь, что компилятор развернёт все ваши итераторы и слои шаблонов? На NRVO и copy elision не надеетесь? Не надеетесь, что компилятор соптимизирует memcpy для копирования представления объекта без type punning'а? Если писать на плюсах аккуратно, как нужно, без UB, то плясок и пританцовываний будет куда больше, чем, гм, в среднем коде.


                      И если вы не надеетесь на компилятор, то собирайте код с -O0, в конце концов. В производительности не потеряете, не так ли?


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


                      К тому же, копия как минимум одна да будет.

                      Откуда?


                      В случае с С++ её не будет.

                      Какая там нынче актуальная рекомендация для передачи параметров? Pass-by-value и всегда иметь как минимум один мув (привет ммммаксимальной производительности)? Или делать везде perfect forwarding, вынося весь код в хедер? Что, кстати, тоже не гарантирует максимальной производительности, но соответствующий пример будет сконструировать уже чуть сложнее.


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

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


                      Нужно прочитать построчно файл и что-то с ним сделать — делаете unlines <$> readFile path и обрабатываете, лениво и в O(1), прям как с итераторами (только без необходимости писать итераторы и весь код делать зависящим от конкретного типа итератора или выносить в шаблоны).
                      Нужно дробить числа и что-то хитрое делать — перегоняете список в массив и работаете с ним. Чисто, или нет, или через repa или accelerate какой — вообще десятый разговор.


                      Выкидываете иммутабельность?

                      Причём тут иммутабельность-то?


                      1. selrorener
                        05.01.2020 04:08

                        C++ это не специфицирует на уровне семантики. Он требует, чтобы программист не делал ошибок, но никаких гарантий или безопасности сам при этом не даёт

                        Это лозунги. Конкретика. Очевидно, что язык с лоулевел доступом даёт больше возможностей, но увеличивает вероятность ошибок. Именно поэтому вы идёте в очередных сравнения С++/hs используете unsafe. Почему?


                        (и не может давать, система типов не позволяет).

                        Основания предоставьте.


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

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


                        Ага. Вы правда не надеетесь, что компилятор развернёт все ваши итераторы и слои шаблонов? На NRVO и copy elision не надеетесь? Не надеетесь, что компилятор соптимизирует memcpy для копирования представления объекта без type punning'а? Если писать на плюсах аккуратно, как нужно, без UB, то плясок и пританцовываний будет куда больше, чем, гм, в среднем коде.

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


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


                        И если вы не надеетесь на компилятор, то собирайте код с -O0, в конце концов. В производительности не потеряете, не так ли?

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


                        Во-вторых, я не отказываюсь от компилятора. Проблема ваша не в том, что вы надеетесь на компилятор — проблема в том, что вы надеетесь ТОЛЬКО на компилятор. Потому как семантически ваш код не оптимален.


                        Откуда?

                        Если я буду использовать старый список одновременно с новым. Семантически в С++ это можно быть один и тот же "список", а в hs нет.


                        Какая там нынче актуальная рекомендация для передачи параметров? Pass-by-value и всегда иметь как минимум один мув (привет ммммаксимальной производительности)?

                        Понятия не имею. Мув — это базовая семантика копирования из си. Копирование не является проблемой.


                        Или делать везде perfect forwarding, вынося весь код в хедер?

                        pf вообще ненужен, если нету raii. Я не являюсь адептом raii и его у меня почти нигде нет. Поэтому мне вообще без разницы.


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


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

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


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

                        Для списка вообще нет задач. Это почти всегда мёртвая структура данных.


                        Нужно прочитать построчно файл и что-то с ним сделать — делаете unlines <$> readFile path и обрабатываете, лениво и в O(1), прям как с итераторами (только без необходимости писать итераторы и весь код делать зависящим от конкретного типа итератора или выносить в шаблоны).

                        Мне вообще ничего ненужно читать — у меня есть mmap. И я не пишу какие-то итераторы и прочие базворды.


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

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


                        Причём тут иммутабельность-то?

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


                        Копирования — это уже следствие этой семантики.


                        1. 0xd34df00d
                          05.01.2020 08:17
                          +3

                          Именно поэтому вы идёте в очередных сравнения С++/hs используете unsafe. Почему?

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


                          Основания предоставьте.

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


                          Может, в скалке что-то есть ещё, конечно, но я скалу знаю недостаточно.


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

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


                          Вы же там сами говорили, что С++ код проще оптимизируется.

                          Где? Тыкните плиз.


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


                          Компилятор в принципе не заточен на то, что-бы генерировать код без оптимизаций.

                          Основания.


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

                          И что?


                          Простите, не мог себе отказать в удовольствии.


                          Во-вторых, я не отказываюсь от компилятора.
                          Без наивной надежды на компилятор.

                          Ясно.


                          Проблема ваша не в том, что вы надеетесь на компилятор — проблема в том, что вы надеетесь ТОЛЬКО на компилятор. Потому как семантически ваш код не оптимален.

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


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

                          У вас не получится это делать. Если вы мутировали список, то старую копию вы потеряли, всё, нет её.


                          И он в хедерах у любого, кто может и умеет писать на С++

                          Ну и что, что один TU компилируется 10 минут после малейшего изменения, а clangd жрёт 20 гигов памяти.


                          потому как иначе нельзя.

                          А мужики и не знали.


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

                          И как вы реализуете эти гарантии?


                          Для списка вообще нет задач. Это почти всегда мёртвая структура данных.

                          Структура данных — да. Сколько раз мне повторить, что список в ФП — это управляющая структура?


                          Мне вообще ничего ненужно читать — у меня есть mmap. И я не пишу какие-то итераторы и прочие базворды.

                          И руками находите \n, руками нуль-терминируете строку, чтобы передать её в какое-нибудь легаси (всего-то двухлетнее), которое ждёт std::string, а не std::string_view (которым тоже прикольно стрелять себе в ноги)?


                          Очень модульно и тестируемо, скажем, ага.


                          Т.е. вы признаете, что fmap несостоятелен?

                          Лол. fmap к спискам имеет околонулевое отношение. Он точно так же радостно выполнит вашу функцию по какому-нибудь вектору. Привет перегрузкам.


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

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


                          1. selrorener
                            05.01.2020 12:43
                            -1

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

                            Ну т.е. у вас ничего нет, никаких оптимизаций нет. Но С++ плохой, потому что там безопасности нет? Это настолько нелепо.


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

                            Не, это не основания. Это "я не знаю". Основания должны звучать так. "Это невозможно потому-то — вот пруфы". К тому же, зависимых типов в хаскеле нет.


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

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


                            Основания.

                            Я написал основания. Основания для игнорирования.


                            И что?

                            И то, что понятия "без оптимизаций" в принципе нет. А -O0 к нему никакого отношения не имеет.


                            Простите, не мог себе отказать в удовольствии.

                            Не засчитывается.


                            Ясно.

                            А теперь полные цитаты.


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

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


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


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


                            У вас не получится это делать. Если вы мутировали список, то старую копию вы потеряли, всё, нет её.

                            В С++ я ничего не теряю.


                            Ну и что, что один TU компилируется 10 минут после малейшего изменения

                            Полная чушь.


                            а clangd жрёт 20 гигов памяти.

                            Нет, очевидно. Он её столько не жрёт. А даже если бы жрал — это не проблема. Эта память ничего не стоит.


                            А мужики и не знали.

                            Ну теперь знают.


                            И как вы реализуете эти гарантии?

                            Руками. Если компилятор собрал код нужным образом — он его соберёт.


                            Структура данных — да. Сколько раз мне повторить, что список в ФП — это управляющая структура?

                            А, ну значит вы мне покажите fmap описанный мною ранее.


                            И руками находите \n, руками нуль-терминируете строку,

                            Я ничего не нуль-терминирую. Нахожу руками. А могу и не руками.


                            чтобы передать её в какое-нибудь легаси (всего-то двухлетнее),

                            Я не пишу прикладуху. А даже если бы писал — это не проблема.


                            которое ждёт std::string, а не std::string_view (которым тоже прикольно стрелять себе в ноги)?

                            Ждёт std::string — это прикладу. И это её проблемы. К тому же, всё это без проблем конвертируется автоматически.


                            Очень модульно и тестируемо, скажем, ага.

                            Опять какие-то лозунги.


                            Лол. fmap к спискам имеет околонулевое отношение. Он точно так же радостно выполнит вашу функцию по какому-нибудь вектору. Привет перегрузкам.

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


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

                            Это неважно. Просто записать в /dev/null. Хорошо, а теперь это нужно проверить. Реализуйте задачу выше на списках, а я на массиве. Сравним.


            1. PsyHaSTe Автор
              05.01.2020 00:37
              +1

              Допустим, я вынужден был написать to&ltvector>(), который там не нужен. Так же я вынужден был принять вектор «по значению», что так же не оптимально.
              ак же, в С++ вообще контейнеры как таковые кого-то мало волнуют. Поэтому и принимаются итераторы.

              Т.е. данный код целиком и полностью противоречит принятым в С++ подходам. Но он целиком и полностью соответствует паттернам принятым в хаскеле. Он и взят из хаскель-букваря.

              В этом и заключается манипуляция, на мой взгляд.


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

              fn fmap<A, B>(f: impl FnMut(A) -> B, xs: impl Iterator<Item=A>) -> 
              impl Iterator<Item=B> {
                  xs.map(f)
              }


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


              1. selrorener
                05.01.2020 01:02

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

                Какая версия раста нужна что-бы это собрать?


                Нужно понимать, что списки — это больше итераторы

                Если это итератор и так xs.map(f) можно, то функция реализуется так: auto fmap = transform. Да даже если не итератор — эта реализация так же пойдёт.


                1. PsyHaSTe Автор
                  05.01.2020 01:06
                  +1

                  Какая версия раста нужна что-бы это собрать?

                  Конкретно этот — 1.26, когда impl Trait стабилизировали. Но это непринципиально, вот так:


                  pub fn fmap<A, B, F: FnMut(A) -> B, TA: Iterator<Item=A>>(f: F, xs: TA) 
                  -> std::iter::Map<TA, F> {
                      xs.map(f)
                  }

                  Соберется на 1.0


                  Если это итератор и так xs.map(f) можно, то функция реализуется так: auto fmap = transform. Да даже если не итератор — эта реализация так же пойдёт.

                  Ну выше мы объявляем все же не функцию, а тип на которой эта функция реализована. Но вообще интересно, да.


                  1. selrorener
                    05.01.2020 01:39

                    Конкретно этот — 1.26, когда impl Trait стабилизировали.

                    Ну в это время гцц уже мог во всех используемые мною фичи.


                    Ну выше мы объявляем все же не функцию, а тип на которой эта функция реализована. Но вообще интересно, да.

                    А в С++ ненужно ничего объявлять. В этом суть С++. Вы в расте определяте все эти типы потому, что раст стирает типы. Если вы уберёте аннотации у типов — у вас всё поломается.


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


                    1. PsyHaSTe Автор
                      05.01.2020 01:43
                      +1

                      Ну в это время гцц уже мог во всех используемые мною фичи.

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


                      А в С++ ненужно ничего объявлять. В этом суть С++. Вы в расте определяте все эти типы потому, что раст стирает типы. Если вы уберёте аннотации у типов — у вас всё поломается.

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


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

                      Ни шаблоны ни генерики ничего не стирают, вопрос в инстанцировании в момент вызова или в момент объявления. Лично я предпочитаю второе, потому что во-первых ошибки намного понятнее, во-вторых понятно какие требования к типу. Лично мне проще понять constraint T : Foo + Bar is not satisfied чем какой-нибудь couldn't apply operator &>>< to operands "MyDuper" and "MySuper".


                      1. selrorener
                        05.01.2020 01:58
                        -1

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

                        Если на прод затащили раст — затащат и актуальные плюсы. А туда, где легаси — туда и раст не попадёт, как и F#. Как максимум там будет хаскель, но и то крайне сомнительно.


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

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


                        Ни шаблоны ни генерики ничего не стирают

                        Стираю. Попробуйте запустить эту функцию без аннотаций. Либо получить оригинальный тип. Вы не сделаете ни того ни другому. Потому как тип стёрт внутри функции.


                        вопрос в инстанцировании в момент вызова или в момент объявления.

                        Это уже следствие. А первый вопрос — стирать или не стирать типы. Если стирать типы — можно не инстанцировать для каждого типа и проверять только сигнатуру. А далее уже сгрузить подстановку типа на кодоген, хотя семантически там vtable.


                        Лично я предпочитаю второе, потому что во-первых ошибки намного понятнее, во-вторых понятно какие требования к типу.

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


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


                        Лично мне проще понять constraint T: Foo + Bar is not satisfied чем какой-нибудь couldn't apply operator &>>< to operands "MyDuper" and "MySuper".

                        А мне проще читать второе — это не аргумент.


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


                        К тому же, в С++ уже есть и подход с аннотациями. Который, к тому же, не затирает типы.


                        1. 0xd34df00d
                          05.01.2020 03:20

                          Типы нужны для того, что-бы код валидировался. Если он валидируется без аннотаций — аннотации ненужны.

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


                          Либо получить оригинальный тип. Вы не сделаете ни того ни другому. Потому как тип стёрт внутри функции.

                          {-# LANGUAGE ScopedTypeVariables #-}
                          
                          bottom :: forall a. a
                          bottom = undefined :: a -- вот он, оригинальный тип

                          или чуть более адекватный реальности пример, на второй строчке, где Proxy a:


                          readEither' :: forall a. (Typeable a, Read a) => Either String a
                          readEither' = first (\err -> [i|Error parsing #{str} as #{typeRep (Proxy :: Proxy a)}: #{err}, expected type: #{value cfg}|]) $ readEither str

                          Или вот (но тут, скорее, Хиндли с Милнером слишком натянули, и у них унификатор порвался, пришлось писать явную аннотацию).
                          Или вот.


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


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

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


                          1. selrorener
                            05.01.2020 04:37

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

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


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

                            Я не вижу там полей. К тому же в С++ ничего ограничивать ненужно. Повторяю — вы что-то там ограничиваете лишь потому, что у вас затираются типы. И вы не можете иначе.


                            В С++ это ненужно. Единственное для чего в С++ существуют концепты — это для перегрузки, потому как перегрузка "не смотрит" в тело.


                            А так в С++ было с его рождения. https://godbolt.org/z/As4NVC — по модному так, а по старому — как угодно. Правило простое — от поля должна как-то зависеть сигнатура.


                            template<typename T, typename = decltype(T{}.name)> void f(T) {}

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


                            Даже факториал считать. https://godbolt.org/z/SBS4VA — вообще что угодно.


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

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


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


                            1. 0xd34df00d
                              05.01.2020 08:24
                              +3

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

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


                              Ну серьёзно, перестаньте так воевать с другими языками. Попробуйте их. Ваши навыки в C++ от этого не пропадут и не испортятся.


                              Я не вижу там полей.

                              Они там в соседней функции, не конкретно в тех строках, на которые я сослался.


                              К тому же в С++ ничего ограничивать ненужно. Повторяю — вы что-то там ограничиваете лишь потому, что у вас затираются типы. И вы не можете иначе.

                              Не затираются, я ж вам пример показал. Это даже несерьёзно.


                              А ограничиваю я потому, что я пишу модульный код. Я хочу выразить констрейнт «функция может работать с любым объектом-конфигом, покуда у него есть поле (с произвольным именем) с заданным типом». Ближайший костыль — ограничиться, скажем, std::tuple и проверять, что std::get<T> — well-formed.


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

                              Прочитайте вопрос внимательнее. Он про наличие поля с заданным типом, а не именем.


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


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

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


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

                              Вот же он — a, во всех случаях. Чем он вас не устраивает?


                              1. selrorener
                                05.01.2020 13:24
                                -1

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

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


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


                                Ну серьёзно, перестаньте так воевать с другими языками. Попробуйте их. Ваши навыки в C++ от этого не пропадут и не испортятся.

                                Я не воюю с языками.


                                Они там в соседней функции, не конкретно в тех строках, на которые я сослался.

                                Ну приведите весь контент.


                                Не затираются, я ж вам пример показал. Это даже несерьёзно.

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


                                А ограничиваю я потому, что я пишу модульный код. Я хочу выразить констрейнт «функция может работать с любым объектом-конфигом, покуда у него есть поле (с произвольным именем) с заданным типом». Ближайший костыль — ограничиться, скажем, std::tuple и проверять, что std::get<T> — well-formed.

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


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


                                Прочитайте вопрос внимательнее. Он про наличие поля с заданным типом, а не именем.

                                Я не понимаю — зачем? Зачем вы задаёте такие нелепые вопросы. Любой тип проверяется. Любыми проверками. https://godbolt.org/z/CtUg9r


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

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


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


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


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

                                Нет, у вас нет типов — у вас есть аннотации. Это и есть типы. Те типы, которые вы передаёте — в тайпчеке не участвуют. Если бы участвовали — нужно было бы тайпчекать каждый инстанс, как это делает С++.


                                Если проще у вас типизация как жава. f(base_class arg) и далее вы тайпчекаете с arg как с этим типом. А уже то, что туда передаёте тип g — вы не чекаете. Он просто затирается, как в жаве.


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


                                Вот же он — a, во всех случаях. Чем он вас не устраивает?

                                Тем, что у меня доступен тип. Тип именно аргумента(ну там после всякое сишной дристни типа decay). В этом фундаментальная разница.


                              1. selrorener
                                05.01.2020 13:49
                                -1

                                Вот с поиском типа в тапле. А вообще меня удивляют эти вопрос, повторю. Какие-то крайне наивные представления о С++, фанатизм и прочее.


                                template<typename Ttuple, typename T> concept with_type = requires(Ttuple tuple) {
                                  to_set(transform(tuple, decltype_))[type_c<T>];//я могу тут любую логику писать
                                };
                                
                                void f(with_type<int> auto) {}
                                
                                int main() {
                                  f(std::tuple{10});
                                }

                                Повторю ещё раз. Система типов С++ тюринг-полная( и не один раз). Сигнатура любой функции так же. Т.е. можно производить какие угодно вычисления. Их можно производить и через перегрузку и через базовую логику и через decltype().


                                Поэтому вопрос уровня "может ли С++ что-то там найти в типах" — несостоятелен. Скорее что-то иное чего-то не найдёт, но не С++.


                                Единственное чего нет в С++ — это интроспекции и рефлексии. Т.е. получить список полей структуры, либо ещё что-то — нельзя. Так же нельзя сгенерировать функции или прочее.


                                Но реализация рефлексии уже есть. Плюс есть clang — прикрутить рефлексию уровня "как в расте" — можно за пол дня. Да что угодно можно.


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


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


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


                                1. 0xd34df00d
                                  06.01.2020 19:59
                                  +1

                                  Поэтому вопрос уровня "может ли С++ что-то там найти в типах" — несостоятелен.

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


                                  Единственное чего нет в С++ — это интроспекции и рефлексии. Т.е. получить список полей структуры, либо ещё что-то — нельзя. Так же нельзя сгенерировать функции или прочее.

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


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

                                  Есть. От TH и Generics в хаскеле (тут они подойдут лучше) до всяких растовских макросов.


                                  Так и здесь. "у С++ слабая система типов, а вот у хаскеля".

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


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

                                  Я и сразу говорю, что их там нету. Зачем вы врёте?


                                  1. selrorener
                                    06.01.2020 20:22
                                    -5

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

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


                                    Ну вы сами и ответили, тащем.

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


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

                                    Там всё объясняно.


                                    Есть. От TH и Generics в хаскеле (тут они подойдут лучше) до всяких растовских макросов.

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


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


                                    Хотя зачем я что-то объясняю — пусть позорник сам пруфцует всю эту чушь нелепую.


                                    1. Cerberuser
                                      07.01.2020 09:01
                                      +4

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

                                      И много Вы видели "вживую" плагинов для компилятора в Rust? Я так навскидку могу назвать разве что стандартные вещи типа clippy, и то с натяжкой (потому что это отдельная программа, которая использует компилятор как обычную библиотеку). Или Вам просто не нравится название "процедурные макросы"?


                                      1. selrorener
                                        07.01.2020 15:52
                                        -2

                                        И много Вы видели "вживую" плагинов для компилятора в Rust?

                                        Плагин это не только:


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

                                        Это что угодно, что предоставлять/использует внутренней/внутреннюю логике/логику компилятора.


                                        Или Вам просто не нравится название "процедурные макросы"?

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


                                        1. Cerberuser
                                          08.01.2020 08:15
                                          +1

                                          А можно было сразу прямо сказать, что Вы не согласны с официально принятой в соответствующей среде терминологией (и поэтому procedural macros в Rust — это для Вас не макросы)? Ну и вообще в аналогичных случаях сразу раскрывать свою мысль. Меньше же потом объяснять придётся.


                                          1. selrorener
                                            08.01.2020 08:32
                                            -2

                                            А можно было сразу прямо сказать, что Вы не согласны с официально принятой в соответствующей среде терминологией (и поэтому procedural macros в Rust — это для Вас не макросы)?

                                            Очередной адепт скриптухи начал отождествлять себя с какой-то официальной принятой терминологией.


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


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


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


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

                                            Читать нужно — "я сел в лужу и попытался нелепо оправдаться", типа "я сразу не понял, что ты дурак, но ты дурак".


                                            1. Cerberuser
                                              08.01.2020 12:54
                                              +1

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


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


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



                          1. technic93
                            05.01.2020 18:45

                            Во первых у вас (множественное число) в комментах смешался хаскель и раст. Как раз судя по статье в хаскеле не обязательно (поправьте если что я хаскель не знаю) указывать ограничение на типы аргументов функций и он может вывести их в некоторых случаях сам, а в раст обязательно. Допустим в статье хаскель понял что аргумент должен быть Foldable + Ord + Num.


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


                            1. 0xd34df00d
                              05.01.2020 20:05

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

                              Ограничения вроде Foldable или Num там на практике не сильно сложнее.


                              лучше иметь функционал авто вывода этих ограничений, разве не так?

                              Иметь неплохо, но можно формально показать, что это неразрешимая задача.


                              1. technic93
                                06.01.2020 01:34

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


                                1. 0xd34df00d
                                  06.01.2020 01:40
                                  +1

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


                                  1. technic93
                                    06.01.2020 01:46

                                    Ну я пишу в определении внешней функции тип B или тип C, или их общий тип А, а то из дискуссий не понятно как она работает, буду рад для общей картины чуть подробнее увидеть пример.


                                    1. 0xd34df00d
                                      06.01.2020 02:33
                                      +2

                                      Вы пишете что-то вроде


                                      class HasFooFunc a where
                                        foo :: smth -> a -> smthElse
                                      
                                      instance HasFooFunc B where
                                        foo = ...
                                      
                                      instance HasFooFunc C where
                                        foo = ...
                                      
                                      outerFunc :: HasFooFunc h => h -> ...
                                      outerFunc someH = ... тут зовёте foo на someH ...

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


                                      1. PsyHaSTe Автор
                                        06.01.2020 02:39

                                        А как работают orphan rules/специализации? В расте с этим знаю есть определенные сложности.


                                        1. 0xd34df00d
                                          06.01.2020 04:05

                                          Компилятор выдаёт ворнинг (который можно сделать error'ом).


                                          Если в одном модуле выбрались два подходящих инстанса, то компилятор в любом случае ругнётся, независимо от того, orphan'ы они или нет.


                                          1. technic93
                                            06.01.2020 12:24

                                            А если это const generics? в расте к сожалению перегрузка по ним не работает.


                                            1. 0xd34df00d
                                              06.01.2020 17:25

                                              В хаскеле нет const (вернее нет не const), поэтому не думаю, что вопрос можно вот прям так перенести.


                                              1. technic93
                                                06.01.2020 18:30

                                                Т.е. перегрузка не только по типу но и по какому-то значению типа factorial(3) сработает?


                                                1. PsyHaSTe Автор
                                                  06.01.2020 18:37
                                                  +1

                                                  В расте ведь точно так же реализовано. into() и parse() например по результирующему типу подхватывают нужную функцию.


                                                  1. technic93
                                                    06.01.2020 18:49

                                                    А при чем тут это? Если я имел ввиду константные темплейт аргументы fn f<{3}>() { ... }


                                                1. 0xd34df00d
                                                  06.01.2020 18:40

                                                  Я не понял вопрос (вернее, не смог связать его с контекстом).


                                                  1. technic93
                                                    06.01.2020 18:54

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


                                                    Upd; даже не так, а еще для остальных n определить рекурсивно через 3 и 10 (например).


                                                    1. 0xd34df00d
                                                      06.01.2020 19:53
                                                      +2

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


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


                                      1. selrorener
                                        06.01.2020 04:18
                                        -1

                                        Простая задача, самый базовый вариант https://godbolt.org/z/5F5mt9 — повторите.


                                        1. 0xd34df00d
                                          06.01.2020 04:30
                                          +5

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


                                          1. selrorener
                                            06.01.2020 04:39
                                            -5

                                            Сорь, у вас там UB, поэтому эта программа может делать всё, что угодно, включая ничего.

                                            Где? Почему лозунги я слышу, а оснований нет?


                                            Так что я выбираю «ничего».

                                            Читаю как "я не могу даже распарсить это, не что повторить". Я правильно прочитал?


                                            1. 0xd34df00d
                                              06.01.2020 04:46
                                              +6

                                              Где? Почему лозунги я слышу, а оснований нет?

                                              Никаких лозунгов, констатация факта.


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


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


                                              Читаю как "я не могу даже распарсить это, не что повторить". Я правильно прочитал?

                                              Основания.


                                              1. selrorener
                                                06.01.2020 04:52
                                                -5

                                                Никаких лозунгов, констатация факта.

                                                Нету пруфов — нету факта.


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

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


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

                                                Очевидно. Но до этого даже не дойдёт. Для тех кто не понимает. Пациент тянет время. Он даже не понял задачи. У него есть только один вариант — нести херню.


                                                Задача в следующем — спровоцировать меня, нагнать табун адептов. Заминусовать меня. И не дать мне ответить. Потом попросту спамить хернёй, когда я смогу отвечать раз в день.


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


                                                Основания.

                                                Не показал — не смог.


                                                1. 0xd34df00d
                                                  06.01.2020 04:55
                                                  +3

                                                  На слабо брать — ну такое.


                                                  1. selrorener
                                                    06.01.2020 05:06
                                                    -4

                                                    Какое слабо? Воспроизведём ситуацию. Эксперт вбрасывает тезис "всё круто — всё заинлайнится", далее прихожу я предлагаю простую проверку, которая пишется за 5 минут.


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


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


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


                                                    Но всё это неважно, мы видим уровень. Уровень данного эксперта.


                                                    1. 0xd34df00d
                                                      06.01.2020 05:09
                                                      +1

                                                      Осталось понять, какое отношение предложенный вами код имеет к тому коду, что я написал выше по ветке (хинт: никакого).


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


                                                      1. selrorener
                                                        06.01.2020 05:18
                                                        -1

                                                        Осталось понять, какое отношение предложенный вами код имеет к тому коду, что я написал выше по ветке (хинт: никакого).

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


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

                                                        Эти нелепые заходы. Здесь мы видим, как пациент находясь в плачевном положении пытается играть в утешение. Он не понимает почему проиграл, он не понимает — почему ничего не может ответить.


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


                                                        Что он мне что-то может предложить и что это что-то изменит. Эта зелёная наивность.


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


                                                        1. 0xd34df00d
                                                          06.01.2020 06:10
                                                          +1

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

                                                          У меня спросили, как сделать что-то, я описал, как сделать что-то. Этот код отвечает, как это сделать (перегрузку функций, и так далее, что там спросил technic93). Ваш код к этому имеет околонулевое отношение (ну, кроме того, что вы среагировали на слово «инлайнинг», вестимо).


                                                          Если честно, это уже начинает немного раздражать.


                                                          Что он мне что-то может предложить и что это что-то изменит. Эта зелёная наивность.

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


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

                                                          Интересная проекция, гм.


                                                          1. selrorener
                                                            06.01.2020 06:22
                                                            -4

                                                            У меня спросили, как сделать что-то, я описал, как сделать что-то. Этот код отвечает, как это сделать (перегрузку функций, и так далее, что там спросил technic93). Ваш код к этому имеет околонулевое отношение (ну, кроме того, что вы среагировали на слово «инлайнинг», вестимо).

                                                            Он не отвечает. Ключевое было "инлайнит" и прочее. Мой код отвечает — ваш нет.


                                                            Кстати, а чего методичка та поменялась? Куда пропало УБ? Начались какие-то совершенно иные мазы.


                                                            Ну в целом в очередной раз очевидно, что болтовня есть, а дела нет.


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

                                                            Это чушь. Код будет таким же читаемым — это же не скриптуха. К тому же, хана далека от читаемости — она устарела уже. Но всё так же есть в бусте и удобно с нею примеры писать.


                                                            А по поводу "внутрянка". Такого мусора как во внутрянке хаскеля — нету нигде. Я не вижу причитаний от вас на этот счёт?


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


                                                            К тому же, даже хана подтирается стандартом. _с


                                                            Если честно, это уже начинает немного раздражать.

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


                                                            Интересная проекция, гм.

                                                            Она очевидна. Методичка одна на всех.


                                                            1. 0xd34df00d
                                                              06.01.2020 08:27
                                                              +3

                                                              Ключевое было "инлайнит" и прочее. Мой код отвечает — ваш нет.

                                                              Выдумывать вопросы за оппонентов и на них же отвечать — это ещё интереснее, да.


                                                              Куда пропало УБ?

                                                              Никуда оно не пропало, вы его так и не нашли.


                                                              Такого мусора как во внутрянке хаскеля — нету нигде.

                                                              Какого, например?


                                              1. Cerberuser
                                                06.01.2020 08:51
                                                +5

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

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


                                                1. 0xd34df00d
                                                  06.01.2020 09:00
                                                  +4

                                                  Давайте рассмотрим, какой тип лежит по указателям in/out на самом деле.


                                                  1. Это uint16_t. Тогда сдвигать in на один байт на строке 14 нельзя: он либо до этого, либо после этого будет указывать не на объект типа uint16_t, а в его середину. Разыменовывать такой указатель нельзя.
                                                  2. Это не uint16_t. Тогда тут уже всеми любимый алиасинг.

                                                  Ещё могут быть дополнительные спецэффекты из-за того, что uint8_t не является char и поэтому не алиасит всё подряд, но предыдущих двух пунктов достаточно, а за проверкой этого придётся лезть в стандарт.


                                                  1. Cerberuser
                                                    06.01.2020 09:05
                                                    +1

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


                                                    upd: перечитал — кажется, дошло: по идее, если там на самом деле char — мы не можем его читать как uint16_t (но можно было бы наоборот).


                                                    1. 0xd34df00d
                                                      06.01.2020 09:21
                                                      +1

                                                      В этом случае тоже алиасинг помешает? char * же, насколько я помню, алиасить как раз можно с чем угодно?

                                                      Upd правильный, но все же напишу. char, signed char и unsigned char — три разных типа, и алиасить может только первый.


                                                      по идее, если там на самом деле char — мы не можем его читать как uint16_t (но можно было бы наоборот).

                                                      Абсолютно верно.


                                                      1. selrorener
                                                        06.01.2020 15:00
                                                        -4

                                                        правильный, но все же напишу. char, signed char и unsigned char — три разных типа, и алиасить может только первый.


                                                        Сходил тут недавно в цирк. Что-то меня накрыли флешбеки с клоунам, не знаю почему. Вроде тут их нет. А вдруг?

                                                        If a program attempts to access the stored value of an object through a glvalue of other than one of the
                                                        following types the behavior is undefined:58
                                                        (11.1)
                                                        — the dynamic type of the object,
                                                        (11.2)
                                                        — a cv-qualified version of the dynamic type of the object,
                                                        (11.3)
                                                        — a type similar (as defined in 7.3.5) to the dynamic type of the object,
                                                        (11.4)
                                                        — a type that is the signed or unsigned type corresponding to the dynamic type of the object,
                                                        (11.5)
                                                        — a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type
                                                        of the object,
                                                        (11.6)
                                                        — an aggregate or union type that includes one of the aforementioned types among its elements or non-
                                                        static data members (including, recursively, an element or non-static data member of a subaggregate or
                                                        contained union),
                                                        (11.7)
                                                        — a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
                                                        (11.8)
                                                        — a char, unsigned char, or std::byte type.


                                                        — a char, unsigned char, or std::byte type.

                                                        Ой, поломалось что-то? Ну бывает.

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

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


                                                        1. Cerberuser
                                                          06.01.2020 16:24
                                                          +1

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

                                                          Оправданий не будет. Но благодарю за доставленное приятное удивление, предыдущие Ваши высказывания формировали существенно худшее мнение о Вас.


                                                          1. selrorener
                                                            06.01.2020 16:46
                                                            -1

                                                            Ну я и не просил оправданий — я просил меньше веры (возможно?)братьям по вере.


                                                            А так я нашел терминальный пруф: enum class byte : unsigned char {}; На этом можно закончить с историей. Я и забыл про него. В целом и люди, которые работают с байтами и люди, которые пишут стандарт — знают как байты должны выглядеть. Наши мнения сошлись.


                                                            1. 0xd34df00d
                                                              06.01.2020 17:28

                                                              А так я нашел терминальный пруф: enum class byte: unsigned char {};

                                                              Терминальный пруф чего?


                                                              enum class U : T порождает тип, отличный от T, к слову.


                                                        1. mayorovp
                                                          06.01.2020 17:19
                                                          +1

                                                          А на вторую часть (по идее, если там на самом деле char — мы не можем его читать как uint16_t (но можно было бы наоборот)) ответ будет?


                                                          1. selrorener
                                                            06.01.2020 17:40
                                                            -4

                                                            С чего он должен быть? Это задача балабола — пруфцевать свои истории, а не мои. Балабол уже засыпался и опозорился.


                                                        1. 0xd34df00d
                                                          06.01.2020 17:27
                                                          +3

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


                                                          Впрочем, если в комментарий с описанием причин UB подставить «char или uchar» вместо «char», то ничего не изменится.


                                                          1. selrorener
                                                            06.01.2020 18:00
                                                            -5

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

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


                                                            А так, очевидно, мне на него насрать. А всякие клоуны ссылаются на стандарт только потому, что 1) ничего о нём не знают и надеяться на то, что никто там ничего искать не будет. И обычно никто не ищет, да и я бы не пошел искать. 2) ничего более ответить не могут.


                                                            Я дал задание — адепт не смог. Начались мазы. Адепт даже с мазами сел в лужу. Ничего нового.


                                                            Я не умею разрешимо пруфать наличие UB кодом, извините.

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


                                                            А УБ нужно пруфцевать стандартом и обоснованием, каким образом данный пример соотносится с процитированным(которого нет).


                                                            enum class U: T порождает тип, отличный от T, к слову.

                                                            Нет, в целом даже эти нелепые потуги не работают. Потому как стандарт явно декларирует эквивалетность std::byte и unsigned char.


                                                            К тому же, опять адепт позорится. Тип и тип данных — разные вещи. Опять же рассуждения того, кто ничего не понимает ни в матчасти, ни к крестах.


                                                            Ну и что-бы окончательно похоронить эту клоунаду:


                                                            For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the
                                                            underlying type

                                                            Значение енума с типом unsigned char являются значением типа unsigned char по стандарту.


                                                            1. 0xd34df00d
                                                              06.01.2020 18:17

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

                                                              Вы, похоже, запутались, что вам нужно пруфцевать.


                                                              Потому как стандарт явно декларирует эквивалетность std::byte и unsigned char.

                                                              #include <iostream>
                                                              #include <type_traits>
                                                              
                                                              int main()
                                                              {
                                                                  std::cout << std::is_same_v<std::byte, unsigned char> << std::endl;
                                                              }

                                                              Что выведет эта программа?


                                                              1. selrorener
                                                                06.01.2020 18:30
                                                                -1

                                                                Вы, похоже, запутались, что вам нужно пруфцевать.

                                                                С чего вдруг?


                                                                Что выведет эта программа?

                                                                Зачем вы позоритесь? Я дал цитату из стандарта, где написано тоже, что говорю. А то, что вы нагуглили is_same — ничего не значит. Это разные категории типов. Советую почитать букварь по С++.


                                                                const int и int — тоже разные типы, но тип данных один. Тоже самое с, допустим, volatile.


                                                                1. 0xd34df00d
                                                                  06.01.2020 19:47

                                                                  Я дал цитату из стандарта, где написано тоже, что говорю.

                                                                  То, что я процитировал из вашего сообщения, отличается по смыслу от того, что написано в стандарте.


                                                                  1. selrorener
                                                                    06.01.2020 19:54
                                                                    -1

                                                                    То, что я процитировал из вашего сообщения, отличается по смыслу от того, что написано в стандарте.

                                                                    Я жду основания этой чуши. Кстати, чего же балабол забыл про is_same и позор с ним? Что там с методичкой? Опять засыпался? Я не вижу оправданий на unsigned char?


                                                                    1. 0xd34df00d
                                                                      06.01.2020 19:55

                                                                      Кстати, чего же балабол забыл про is_same и позор с ним?

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


                                                                      1. selrorener
                                                                        06.01.2020 20:00
                                                                        -1

                                                                        Ну дак где же? Опять балабольство? Я могу позор показать и не один. Где мой-то позор? Опять методичка поломалась?


                                                                        1. 0xd34df00d
                                                                          06.01.2020 20:07

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


                                                                          Это если о языке и ваших «познаниях» в нём говорить.


                                                                          1. selrorener
                                                                            06.01.2020 20:28
                                                                            -2

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

                                                                            Опять трепло несёт херню. Никакого UB там нет, трепло село в лужу с UB.


                                                                            копипаста примеров из доков по хане

                                                                            Трепло, пруфы потугам предоставьте.


                                                                            1. 0xd34df00d
                                                                              06.01.2020 21:10
                                                                              +3

                                                                              Первый раз вижу «вы все врете» в треде о ЯП, если честно.


                                                                              1. selrorener
                                                                                06.01.2020 21:30
                                                                                -4

                                                                                Первый раз вижу «вы все врете» в треде о ЯП, если честно.

                                                                                Где там врёте? Это призыв ответить за необоснованные обвинения. С таким же успехом я тоже могу врубить и повторять манутру "там нету УБ", как это делаете вы.


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


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


                                                                                Хотя, как я уже говорил, наличие/отсутствие там УБ — ни на что не влияет. Это не освобождает вас от ответа. А УБ — это то, о чём бежит сообщать каждый зелёный джун услышавший что-то о С++.


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


                                                      1. technic93
                                                        06.01.2020 18:21

                                                        А вот это странно, что aliasing не симметричный. Т.е. что угодно можно читать как char* но char* нельзя читать как что то другое. Скорее всего так сделано потому что не только алиасинг но еще и выравнивание. Хотя выравнивание зависит от платформы так что это неким общим документом боюсь не опишешь. Иначе у меня вопрос как писать SSE инструкции? Это скорее всего исключения типа char*.


                                                        1. 0xd34df00d
                                                          06.01.2020 19:54
                                                          +1

                                                          Т.е. что угодно можно читать как char но char нельзя читать как что то другое.

                                                          Кстати, если это формулировать вот прям так, то понятно, почему этого нет: потому что тогда что угодно вы можете читать как что угодно (сначала читаете как char*, а потом как другое что угодно).


                                                          1. technic93
                                                            06.01.2020 20:01

                                                            Нет отрицание этого выражение это то что char* можно читать как что то другое (но не что угодно)


                                                            1. 0xd34df00d
                                                              06.01.2020 20:04

                                                              А, ну если там квантор существования, то тогда да.


                                                              1. technic93
                                                                06.01.2020 20:57

                                                                Ну да потому что если в том буфере char* на самом деле лежит T то можно делать reinterpert_cast к T* и дальше работать с ним. т.е. ваш первый пункт из сообщения про UB, в документации без поллитра не разберешься.


                                                  1. selrorener
                                                    06.01.2020 14:42
                                                    -5

                                                    Где пруфы, балабол? Где код?


                                                    1. 0xd34df00d
                                                      06.01.2020 17:29
                                                      +1

                                                      Я не умею разрешимо пруфать наличие UB кодом, извините.


                        1. mayorovp
                          05.01.2020 10:08
                          +1

                          Стираю. Попробуйте запустить эту функцию без аннотаций. Либо получить оригинальный тип. Вы не сделаете ни того ни другому. Потому как тип стёрт внутри функции.

                          Пожалуйста, используйте термины по назначению.


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


                      1. technic93
                        05.01.2020 02:28

                        Давайте отделять мух от котлет т.е. прод от технологий и брать последний релиз компилятора за общий знаменатель.


        1. gBear
          06.01.2020 21:59
          +1

          auto fmap(auto f, auto v) {
          return v | transform(f) | to<std::vector>();
          }

          Так и все же… какой тип-то будет у этой ф-ции? Что-то отличное от: any -> any -> any или этим все и ограничивается?


          1. selrorener
            06.01.2020 22:33
            -2

            Так и все же… какой тип-то будет у этой ф-ции? Что-то отличное от: any -> any -> any или этим все и ограничивается?

            У этой функции нет типа. Это множество функции, которые существуют только для типов удовлетворяющих её телу. Её не описать такими any -> any -> any примитивными сигнатурами. Этого недостаточно для выражения системы типов С++.


            Каждая функция из множества сохраняет типы переданных в неё параметров(там есть кое какие нюансы, но это издержки лоулевел работы с памятью(и не только). Чего в том же хаскеле/f# и прочем — нет).


            Допустим, в случае в случае https://godbolt.org/z/MAGPqV


            Тип будет примерно следующим:


            auto fmap(f:auto, v:auto) [
            f:auto = boost::hana::placeholder_detail::plus_right<int>,
            v:auto = ranges::experimental::shared_view<std::vector<int, std::allocator<int>>>
            ]

            Возвращаемое значение там не написано, но оно будет std::vector.

            Это можно проверить так: https://godbolt.org/z/EnfTRJ


            Если убрать конвертацию в вектор — будет так: https://godbolt.org/z/Bj9wca


            void f(auto:16) [with auto:16 = ranges::transform_view<ranges::experimental::shared_view<std::vector<int> >, boost::hana::placeholder_detail::plus_right<int> >]
            

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


            Каждый тип — это отдельная программа с уникальной логикой.


            1. gBear
              06.01.2020 23:33
              +3

              У этой функции нет типа. Это множество функции, которые существуют только для типов удовлетворяющих её телу. Её не описать такими any -> any -> any примитивными сигнатурами. Этого недостаточно для выражения системы типов С++.
              :-))) Честно говоря, я даже не знаю, что вам на это ответить. Вы просто не понимаете, о чем рассуждаете, или это просто такой тонкий троллинг? Не надо так…

              Предположу, что вы просто не знакомы со «стрелочной нотацией». Так вот… «примитивный» тип any -> any -> any — ко всему прочему — включает в себя и любую ф-цию двух аргументов — внезапно, это тоже «множество» :-)

              И тип этой fmap — в любом случае — можно описать как any -> any -> any. Вопрос в том, можно ли его описать, скажем так, чуть строже? :-)

              P.S. Яж правильно понимаю, что «удовлетворяют её телу» наши аргументы или нет, можно узнать только на этапе компиляции?


              1. selrorener
                06.01.2020 23:56
                -5

                :-))) Честно говоря, я даже не знаю, что вам на это ответить. Вы просто не понимаете, о чем рассуждаете, или это просто такой тонкий троллинг? Не надо так…

                :-))) Честно говоря, я даже не знаю, что вам на это ответить. Вы просто не понимаете, о чем рассуждаете, или это просто такой тонкий троллинг? Не надо так…


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

                Там нечему быть знаком. Это примитивщина из скриптухи.


                Так вот… «примитивный» тип any -> any -> any — ко всему прочему — включает в себя и любую ф-цию двух аргументов — внезапно, это тоже «множество» :-)

                И что? То, что оно включает всё — потому оно и примитивное.


                И тип этой fmap — в любом случае — можно описать как any -> any -> any.

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


                Вопрос в том, можно ли его описать, скажем так, чуть строже? :-)

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


                P.S. Яж правильно понимаю, что «удовлетворяют её телу» наши аргументы или нет, можно узнать только на этапе компиляции?

                Очевидно. Не на этапе компиляции — это скриптуха. Это значит, что какие-либо осмысленные типы статические не присутствуют, а значит вопрос "какой тип" несостоятелен — он неизвестен.


                К тому же, назвать any любым типом — невероятная глупость. Это не любой тип — это общий тип. Здесь нужно объяснять так же, как я объяснял ниже — для начальной школы. Есть тип кошка, есть тип собачка. Ограничим этими типами множество. Таким образом any — это будет или кошка или собака одновременно, но не кошка и не собака в отдельности. any не будет обладать свойствами кошки, либо свойствами собаки. Он будет обладать лишь общими свойствами для всего множества возможных типов.


                В C++ T — это не any и прочая примитивная херня из скриптухи. Это любой конкретный тип, обладающий всеми свойствами каждого отдельного типа.


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


                1. gBear
                  07.01.2020 01:16
                  +5

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

                  Даже так?! Я, похоже что-то пропустил… не подскажете, как давно типизированное лямбда-исчисление стало считаться «примитивной хернёй»? :-)

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

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

                  Ааа… не. Не в этом смысле. Просто типизация, этож один из этапов. Чисто с проф. точки зрения стало интересно. Одно дело, если это именно на типизации упадет (причем, на типизации именно fmap, а не, например, transform), и другое, если где-то «ниже»… хотя и то, и другое будет на этапе компиляции, но разница таки есть. Сорри за не точность.

                  К тому же, назвать any любым типом — невероятная глупость. Это не любой тип — это общий тип.
                  Не не не… any тут, это именно любой конкретный тип.

                  Таким образом any — это будет или кошка или собака одновременно, но не кошка и не собака в отдельности.
                  any — это т.н. ?-тип. В данном конкретном случае, экземпляром этого типа будет либо кошка, либо собака. Что есть ваше «или кошка или собака одновременно» — я вообще не могу представить.

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


                  1. selrorener
                    07.01.2020 01:38
                    -3

                    Даже так?! Я, похоже что-то пропустил… не подскажете, как давно типизированное лямбда-исчисление стало считаться «примитивной хернёй»? :-)

                    Всегда было, а типизации там нет.


                    Я, честно, не знаю, что есть «скриптуха»… но, предположу, что сильно вряд ли вы имеете ввиду математику. Просто не хочется про такое думать :-)

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


                    Ааа… не. Не в этом смысле. Просто типизация, этож один из этапов. Чисто с проф. точки зрения стало интересно. Одно дело, если это именно на типизации упадет (причем, на типизации именно fmap, а не, например, transform), и другое, если где-то «ниже»… хотя и то, и другое будет на этапе компиляции, но разница таки есть. Сорри за не точность.

                    Эта какие-то совсем наивные заходы из скриптуха-методички. Упадёт оно там, где семантически должно.


                    Не не не… any тут, это именно любой конкретный тип.

                    Нет, очевидно.


                    any — это т.н. ?-тип.

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


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

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


                    Что есть ваше «или кошка или собака одновременно» — я вообще не могу представить.

                    То и значит. Если там кошка — тип должен быть кошка. Если собака — собака. Типа "или" не существует и существовать не может.


                    Вот честно… читать про эти ваши постоянные «скриптухи» — не интересно.

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


                    А я вам объясняю, что нет. Мне она ненужна. И у меня не она.


                    Не понятно, чего вы этими постоянными упоминаниями хотите добиться.

                    Что значит чего? Отделения скриптухи от не скриптухи.


                    Типизация в C++ — в любом случае — нужна.

                    Она там есть. В С++ ненужна скриптуха-типизация, а не типизация. Не нужно путать. Опять сведения частного к общему.


                    1. gBear
                      07.01.2020 16:18
                      +2

                      Всегда было, а типизации там нет.
                      ?! Как раз ничего, кроме типизации там и нет, по большому счету.

                      Никакой математики нет, отсылка на математику говорил лишь о том, что говорящий ничего не знает о математике.
                      Это в смысле, что в типизации «математики нет»?! Или что?

                      Упадёт оно там, где семантически должно.
                      И где — по вашему мнению — оно «семантически должно» упасть?

                      Нет, такого быть не может.
                      ?! Да любое перечисление может быть представлено как ?-тип. Иногда это удобно, иногда нет. В любом случае, дизъюнктное объединение — как тип, вполне себе есть. Просто нет причин, по которым бы ему не быть.

                      То и значит. Если там кошка — тип должен быть кошка. Если собака — собака.
                      Ну это, собственно, и называют типом-суммой (?-типом). :-)

                      А мне не интересно читать про скриптуху. Вы задали вопрос и начали спорить.
                      Я еще даже не начинал «спорить»… вы — судя по всему — просто не поняли вопроса. Попробую совсем «на пальцах».

                      Есть контекст Г0 — в котором у нас определен не явно типизированный терм — fmap;
                      Есть контекст Г1 — в котором fmap явно типизируется как — допустим — long[] -> int -> long[];
                      Есть контекст Г2 — в котором fmap явно типизируется как — допустим — int[] -> long -> int[].

                      Вопрос: Как терм fmap будет (и будет ли) представлен в результирующей программе?

                      Т.е., грубо говоря, будет ли fmap *типизирован*? Например, как long[] -> long -> long[] (допустим, у нас нет проблем с ковариантностью массивов). И в программе у нас будет единственное представление терма fmap.

                      Или на fmap мы «забьем» и в результате в программе будут — условные — fmap:: Г1 и fmap:: Г2? Которые, вообще говоря, между собой могут вообще не иметь ничего общего.


                      1. selrorener
                        07.01.2020 18:47
                        -4

                        ?! Как раз ничего, кроме типизации там и нет, по большому счету.

                        Там ничего нет, в том числе нету и типизации.


                        Это в смысле, что в типизации «математики нет»?! Или что?

                        Это в смысле глупой методички. Когда кто-либо слаб — он начинает апеллировать к мы, а не к я. Тут тоже самое. Здесь проще объяснить на примере.


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


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


                        И где — по вашему мнению — оно «семантически должно» упасть?

                        Там, где требования к тип не соответствует предъявляемых к нему требованиям.


                        ?! Да любое перечисление может быть представлено как ?-тип. Иногда это удобно, иногда нет. В любом случае, дизъюнктное объединение — как тип, вполне себе есть. Просто нет причин, по которым бы ему не быть.

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


                        Ну это, собственно, и называют типом-суммой (?-типом). :-)

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


                        В скриптухи нету типов, а то что там называется типами — типами не является. Тип — это набор свойство некоего объекта.


                        Я еще даже не начинал «спорить»… вы — судя по всему — просто не поняли вопроса. Попробую совсем «на пальцах».

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


                        Есть контекст Г0 — в котором у нас определен не явно типизированный терм — fmap;

                        Меня не интересуют базворды скриптухи. Никакого "не явно" не существует.


                        Есть контекст Г1 — в котором fmap явно типизируется как — допустим — long[] -> int -> long[];

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


                        Вопрос: Как терм fmap будет (и будет ли) представлен в результирующей программе?

                        Я ответил на этот вопрос и показал выше.


                        Т.е., грубо говоря, будет ли fmap типизирован? Например, как long[] -> long -> long[] (допустим, у нас нет проблем с ковариантностью массивов). И в программе у нас будет единственное представление терма fmap.

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


                        Или на fmap мы «забьем» и в результате в программе будут — условные — fmap:: Г1 и fmap:: Г2? Которые, вообще говоря, между собой могут вообще не иметь ничего общего.

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


                        Хаскель — это такое php к которому прикрутили примитивный тайпчекер. Семантически он php. Это как упомянутый тут typescript.


                        Поэтому там и существует такие понятия как один fmap и какая-то типизация в контекстах. Там один fmap лишь потому, что у него нету типизации. Он просто fmap(any, any), как fmap(void , void ) а си.


                        Далее к этому прикручена типизация. Просто ввиде статического анализатора, как это сделано в каком-нибудь пхп или typescript.


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


                        1. 0xd34df00d
                          07.01.2020 19:21
                          +1

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

                          Но вы ведь не знаете, как оно там называется, ведь вы не читали эти «методички».


                          Хаскель — это такое php к которому прикрутили примитивный тайпчекер. Семантически он php. Это как упомянутый тут typescript.

                          Поэтому там и существует такие понятия как один fmap и какая-то типизация в контекстах. Там один fmap лишь потому, что у него нету типизации. Он просто fmap(any, any), как fmap(void, void ) а си.

                          Далее к этому прикручена типизация. Просто ввиде статического анализатора, как это сделано в каком-нибудь пхп или typescript.

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

                          Основания.


                          По вашей логике C++ и его система типов — это такой макроязык с прикрученным сбоку правилом sfinae.


                          А на самом деле fmap — функция из типа в терм (System F, ага). Соответственно все может диспатчиться вот прям в момент применения этой функции к типу (в момент тайпчекинга, а не на уровне кодегена).


                          1. selrorener
                            07.01.2020 19:32
                            -3

                            Но вы ведь не знаете, как оно там называется, ведь вы не читали эти «методички».

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


                            Основания.

                            Выше дал пруф. Адепт хаскеля сел в лужу с пруфа.


                            По вашей логике C++ и его система типов — это такой макроязык с прикрученным сбоку правилом sfinae.

                            Нет, это представления о С++ уровня первого курса сельского вуза. Это представления адептов скриптухи о С++.


                            К тому же никакого всеобъемлющего правила sfinae нет. Это опять же наивные представления. Это просто базворд, которым не особо обременённые адекватными представлениям о С++ люди объясняют всё подряд.


                            А на самом деле fmap — функция из типа в терм (System F, ага).

                            Это примитивная скриптушный базворд.


                            Соответственно все может диспатчиться вот прям в момент применения этой функции к типу (в момент тайпчекинга, а не на уровне кодегена).

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


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


                            Хотя с пхп не особо удачный/популярный пример. Это js к которому прикрутили статический анализатор и получился ts. Но при этом, очевидно, никого диспатча там нет и никаких типов нет. Это всё фантазии адептов.


                  1. 0xd34df00d
                    07.01.2020 01:48

                    Даже так?! Я, похоже что-то пропустил… не подскажете, как давно типизированное лямбда-исчисление стало считаться «примитивной хернёй»? :-)

                    Добро пожаловать!


                    any — это т.н. ?-тип.

                    А сигма-тип — это разве не про зависимую сумму?


                    То есть, конечно, можно представить any как (a : Type ** a), получится прям почти питон какой-нибудь, но сделать что-то разумное без фиксированных универсумов с этим не получится (по крайней мере, в тех теориях типов, что реализованы в доступных сегодня языках).


                    1. gBear
                      07.01.2020 16:32

                      А сигма-тип — это разве не про зависимую сумму?
                      ?-тип — это и простой тип-сумма. В том смысле, что речь не про зависимые типы :-)

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

                      И вопрос в том, можно ли типизировать такой fmap не «как-то»?


                  1. PsyHaSTe Автор
                    07.01.2020 12:01
                    +2

                    Даже так?! Я, похоже что-то пропустил… не подскажете, как давно типизированное лямбда-исчисление стало считаться «примитивной хернёй»? :-)

                    Ну оно вроде всегда было простым. Там же всего пара правил: подстановка, генерализация и буквально всё :)


                    Язык Formality например поддерживает лямбда-счисление, а кода там в интерпретаторе 500 строк.


                    any — это т.н. ?-тип. В данном конкретном случае, экземпляром этого типа будет либо кошка, либо собака. Что есть ваше «или кошка или собака одновременно» — я вообще не могу представить.

                    Ну это же просто :)


                    type CatAndDogSimultaneously a = forall a . (Cat a, Dog a) => a


                  1. St_one
                    07.01.2020 12:05
                    +6

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


                    1. balajahe
                      07.01.2020 13:03

                      Предлагаю отлить в граните, и включить в учебники! )


                    1. selrorener
                      07.01.2020 16:04
                      -1

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

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


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

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


                      1. St_one
                        07.01.2020 16:24
                        +1

                        Чушь. И да, обоснования эти нелепым рассуждениям. Особенно смешно читать от адептов скриптухи то, что в С++ «простейшей макроподстановки». Но я напомню адептам скриптухи одно обстоятельство — не существует в мире «подстановки» сложнее оной в С++.

                        Ну т.е. С++ как макруха, обладает очень хорошей, мощной системой макросов. Правильно? Я не против. Я не претендую на последнюю инстанцию терминов — поправляйте, если что не так =)
                        Это так же чушь. Что-то является чем-то исходя из своих неотъемлемых свойств. Давайте опять на уровне детского садика. Если человек может передвигаться на четырёх конечностях — это не означает, что прямохождение не его основное свойство, либо он не классифицируется так

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


                        1. selrorener
                          07.01.2020 18:17
                          -3

                          Ну т.е. С++ как макруха, обладает очень хорошей, мощной системой макросов. Правильно? Я не против. Я не претендую на последнюю инстанцию терминов — поправляйте, если что не так =)

                          Нету в С++ макросов. Методичка несостоятельна. Меньше глупостей надо читать. Я понимаю, что вы там просто передаёте одну и ту же методичку, но она неверна. Шаблоны действительно в базе имеют семантику подстановки, но это даже не 1% того, что происходит в двух строчках выше.


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

                          Неверно. Я не говорил о том, что там что-то есть и не занимался классификацией по факту наличию возможностей.


                          Поэтому мы говорим что С++ и скриптуха и макруха одновременно.

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


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


                          1. 0xd34df00d
                            07.01.2020 19:23

                            Прям жалко, что мы на Хабре, а не на ЛОРе, где этакий зеркальный метод ведения дискуссии был бы более уместен.


                            1. balajahe
                              07.01.2020 19:29

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


                              1. selrorener
                                07.01.2020 19:41
                                -3

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


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


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


                                И именно поэтому это понятие мусор. в С++ диспатч статически-динамический, но никак не динамический. В целом — ошибаться в классификации/типизации — это вообще норма для мира скриптухи.


                                По базворду похоже — значит одно и тоже. В методичке написано — будет повторять.


                                1. 0xd34df00d
                                  08.01.2020 03:00
                                  +1

                                  Ну так не приравнивайте к пхп. В том же хаскеле вон всё статически генерируется, как тот же vtable.


                                  В рантайме там типов вообще нет (если Typeable в расчёт не брать).


                                  В целом — ошибаться в классификации/типизации — это вообще норма для мира скриптухи.

                                  Весь мир ошибается, весь мир не понимает, что такое типизация (включая скриптух-математиков, ага), только Царь знает, как правильно.


                                  Что-то это плоскоземельщиков начинает напоминать.


                                  1. selrorener
                                    08.01.2020 03:24
                                    -2

                                    Ну так не приравнивайте к пхп.

                                    Я приравниваю к пхп том, что является "пхп".


                                    В том же хаскеле вон всё статически генерируется, как тот же vtable.

                                    Нет, очевидно. Это мифы и легенды адептов хаскеля.


                                    Весь мир ошибается, весь мир не понимает, что такое типизация

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


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


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


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


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


                                    (включая скриптух-математиков, ага)

                                    Ну да, а это вообще смешно. Математика, за редкими исключениями, находится на дне мира программирования. И популярен так, сюрприз, пистон. Чистокровная скриптуха.


                                    Есть те, кто хочет понтануться и написать статейку по "разворот списка" описанный в базовом туториале на скриптухи, да ещё за месяц, да ещё и не забыв задать вопрос на СО(и получить ответ).


                                    Аудитория достаточно лояльна к подобным экспертам и воспринимает их за что-то состоятельное.


                                    только Царь знает, как правильно.

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


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


                                    Что-то это плоскоземельщиков начинает напоминать.

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


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


                                    В целом это чётко определяет уровень моих оппонентов. Обывательский.


                                    1. 0xd34df00d
                                      08.01.2020 03:38
                                      +1

                                      Я приравниваю к пхп том, что является "пхп".

                                      А хаскель тут причём?


                                      Нет, очевидно. Это мифы и легенды адептов хаскеля.

                                      Основания.


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

                                      Отнюдь, я лишь подытоживаю ваши тезисы.


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

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


                                      Математика, за редкими исключениями, находится на дне мира программирования. И популярен так, сюрприз, пистон. Чистокровная скриптуха.

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


                                      Есть те, кто хочет понтануться и написать статейку по "разворот списка" описанный в базовом туториале на скриптухи, да ещё за месяц, да ещё и не забыв задать вопрос на СО(и получить ответ).

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


                                      Разница между нами в том, что я выбираю то, что реально может.

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


                                      Здесь происходит подмена понятий, типа "против общественного мнения — против правды" и берётся пример, где общественно мнение действительно является правдой.

                                      Нет. Здесь исключительно отсылка к структуре вашей аргументации.


                                      1. selrorener
                                        08.01.2020 04:18
                                        -1

                                        А хаскель тут причём?

                                        Потому что такое же пхп.


                                        Основания

                                        Выше уже предоставил.


                                        Отнюдь, я лишь подытоживаю ваши тезисы.

                                        Зачем оправдываться? Это было явно зафиксировано. И какие такие мои тезисы?


                                        Не гуру, вовсе нет, есть куча людей, которые в этом шарят лучше меня.

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


                                        Просто я с шаблонами поизворачивался уже достаточно

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


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

                                        Опять какая-то чушь. В целом это можно фиксировать как. "не знал и не знаю, врал и хочу отмазаться".


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


                                        Но в С++ шаблоны(к тому же эта методичка устарела. В С++ уже давно не шаблоны) — это базовый инструмент. Он не может быть новым или старым. Он просто есть. И кто может, а кто-то не может.


                                        Математика, сюрприз, бывает разная.

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


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

                                        Это ничего не меняет. Везде почти одно и тоже. Ничего в плане программирования, за редкими исключениями, как я уже говорил.


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

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


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

                                        Что-то при попытке показать УБ — вы сели в лужу. А потом куда-то убежали. Да и с обоснованиям за "пример из ханы" у вас были проблемы — вы опять же сели в лужу его не предоставя.


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


                                        Нет. Здесь исключительно отсылка к структуре вашей аргументации.

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


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


                          1. St_one
                            07.01.2020 21:09
                            +1

                            Нету в С++ макросов. Методичка несостоятельна. Меньше глупостей надо читать. Я понимаю, что вы там просто передаёте одну и ту же методичку, но она неверна. Шаблоны действительно в базе имеют семантику подстановки, но это даже не 1% того, что происходит в двух
                            Это все замечательно, но как мы выяснили выше, в С++ самая мощная в мире система макросов, а значит мы можем смело присудить языку звание почетной макрухи.
                            Очевидно, что скриптуха — это низшая форма жизни. И можно так сказать, что многоклеточное оно и одноклеточное так же. Но оно не является одноклеточным
                            Ваш пример не подходит, потому, что существо не может быть одновременно многоклеточным и одноклеточным. А скриптухой и макрухой языку ничего не мешает быть. Так что с терминами определились.


                            1. selrorener
                              07.01.2020 21:18
                              -2

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

                              Нет, в С++ не система макросов. Это попытка адептов подменить понятия.


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

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


                              А скриптухой и макрухой языку ничего не мешает быть. Так что с терминами определились.

                              Мешает. Этому не мешает ничего быть в рамках фантазий адептов скриптухи, потому как в рантайме/кодогене тип будет any(какая-то динамическая структура, тип у которой вообще никак не будет связан с типов в воображаемом мире скриптухи).


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


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


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


                              1. St_one
                                08.01.2020 00:27
                                +1

                                Нет, в С++ не система макросов. Это попытка адептов подменить понятия.
                                Напомню, что адепт данной скриптухи выше писал:
                                не существует в мире «подстановки» сложнее оной в С++.

                                Да славься же С++ — самая сложная макруха в мире!
                                Подходит, потому как и тип не может быть одноклеточный и многоклеточный одновременно.
                                Вот именно что не подходит. Одноклеточный и многоклеточный одновременно тип быть не может. А вот скриптухой и макрухой — запросто. Посмотрите на тот же С++.


                                1. selrorener
                                  08.01.2020 00:41
                                  -1

                                  Напомню, что адепт данной скриптухи выше писал:

                                  Не вижу, что-бы какой-то адепт скриптухи такое писал.


                                  Вот именно что не подходит. Одноклеточный и многоклеточный одновременно тип быть не может. А вот скриптухой и макрухой — запросто. Посмотрите на тот же С++.

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


                                  И уже забыл обо всём. А так сильно распинался, базворды повторял. Ну бывает. Где же всё это?


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


      1. AndreyRubankov
        05.01.2020 00:19
        +1

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

        Если я правильно понял, в той же многословной java это будет:

        class Fmap {
            static <A, B extends A> Collection<B> fmap(Function<A, B> f, Collection<A> a) {
                return a.stream().map(f).collect(toList());
            }
        }
        

        и из церемоний тут:
        1. описание явной сигнатуры метода (да, громоздко)
        2. обернуть все в класс и объявить как static (т.к. функций первого порядка нету, но есть статик импорты)

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

        Кстати, та же декларация на TypeScript:
        const fmap = <A, B extends A>(f: (A) => B, a: Array<A>): Array<B> => a.map(f);
        


        И на JS:
        const fmap = (f, a) => a.map(f);
        


        1. PsyHaSTe Автор
          05.01.2020 00:44

          Верно. Правда, в данном конкретном случае вы написали конкретно для списка, а код выше работает для любых маппящихся вещей (см. F<A> вместо Collection<A>).


          Кстати я не уверен, что часть с B extends A — верна.


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

          Да нет там никаких "на порядок выше". Не считая немного странного для стороннего наблюдателя ML-синтаксис всё предельно просто. Концепции там сильно проще, чем какой-нибудь сборник банды четырех, которую в ООП мире считают мастхевом. Гением как раз надо быть, чтобы без сигнатур во всем разобраться. Я вот — не могу, мне нужно чтобы комплиятор мне подсказывал: что я могу делать с некоторыми структурами, что не могу, что они умеют, а чего — нет.


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


          const fmap = <A, B extends A>(f: (A) => B, a: Array<A>): Array<B> 
            => 1000 строк нечитаемого кода

          Могу понять намного больше, чем из


          const fmap = (f, a) 
            => 1000 строк нечитаемого кода


  1. VolCh
    04.01.2020 17:48
    -2

    Может дело в том, что обычно дискуссии идут не в области чистой теории, а применительно к конкретным задачам, коммерческим и близким к ним, где не к мейнстрим языкам отношение, скажем так, предвзятое, где первый вопрос к предложению сменить язык "где мы возьмём специалистов и сколько они будут стоить?"


    1. 0xd34df00d
      04.01.2020 18:06
      +2

      Хаскель уже можно считать мейнстримом настолько же, насколько какой-нибудь Go. По крайней мере, [организационных] проблем с использованием его в проде не было, и в резюме я его вижу достаточно часто (хотя работаю не в хаскель- и вообще не в ФП-шопах).


      1. VolCh
        04.01.2020 19:48
        -2

        Go, на мой взгляд, только приближается к мейнстриму. Haskell же страшно далёк от него.


  1. fimashagal
    04.01.2020 18:03

    В javascript выйдет ещё меньше церемоний: можно было бы вместо написания consume использовать метод slice


    1. PsyHaSTe Автор
      04.01.2020 18:05

      Церемонии JS — это одна строчка с именем функции и аргументов, мы ведь специально не рассматриваем тело. Если можно это упростить, то, пожалуйста, покажите как.


      1. Nara7
        04.01.2020 20:43

        Я конечно не занимаюсь разработкой на js, но мне кажется, что такой код должен сработать:

        var consume = function (source, quantity) {
          if (!source) {
            return [];
          }
          if (quantity <= 0) {
            return source;
          }
          var first = source.shift();
          return consume(source, quantity - first);
        }
        


        1. PsyHaSTe Автор
          04.01.2020 21:39

          Но ведь строка var consume = function (source, quantity) {, а всё остальное (серое) мы не сравниваем, потому что у автора не было цели оптимально реализовать функцию, более того, он прямо пишет "я не особо пишу на ЖС и точно можно лучше".


          Один из вариантов более симпатичного тела функции:


          var consume = function (source, quantity) {
            let s = 0;
            const index = source.findIndex(x => (s += x) >= quantity);
            return index < 0 ? [] : source.slice(index + 1);
          }


        1. mayorovp
          05.01.2020 09:45
          +2

          Взяли и заквадратили алгоритм… Не надо так делать, пожалуйста!


          1. chapuza
            05.01.2020 10:04
            +2

            Не говоря о том, что из-за отсутствия TCO в JS оно на списке длиной элементов в двести повалит рантайм из-за переполнения стека.


  1. neplul
    04.01.2020 18:03
    +2

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


    1. PsyHaSTe Автор
      04.01.2020 18:10
      +3

      Что опять складывание чисел?

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


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

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


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

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


      Ну и в любом случае информации не меньше, чем в PR в JavaScript репозитории.


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


      1. VolCh
        04.01.2020 18:34

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


        1. PsyHaSTe Автор
          04.01.2020 18:49
          +5

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


          type HeadersInit = Headers | string[][] | Record<string, string>;
          
          interface Headers {
              append(name: string, value: string): void;
              delete(name: string): void;
              get(name: string): string | null;
              has(name: string): boolean;
              set(name: string, value: string): void;
              forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any): void;
          }

          То есть хэдеры — это либо просто мапа стринги на стрингу, либо двумерный массив, либо вообще объект со своими методами. Или вот моё любимое:



          Тип поля: string | false | null. Не bool, а false. Вот такие вот завтипы.


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


          1. chapuza
            05.01.2020 09:58

            Тип поля: string | false | null. Не bool, а false. Вот такие вот завтипы.

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


            1. mayorovp
              05.01.2020 10:18
              +1

              Ну, "не указан" лучше бы было как undefined указывать, тем более что внутри эти параметры всё равно в string | false | null | undefined превращаются из-за своей опциональности.


              1. chapuza
                05.01.2020 10:21

                "не указан" лучше бы было как undefined указывать

                Абсолютно не согласен. «Не указан» в данном контексте — это пустой, null, void, если хотите. Ну и, кроме того, в здоровом API, которому не нужен специальный клиент на JS, — undefined немного не в чести.


                1. mayorovp
                  05.01.2020 10:31

                  Обратите внимание на "вопросики": эти параметры можно реально не указать, и тогда там будет undefined. Зачем тут ещё и null?


                  «Не указан» в данном контексте — это пустой, null

                  А false тогда что означает? :-)


                  1. chapuza
                    05.01.2020 10:35

                    false означает «указан, игнорировать», как я написал в первом комментарии;
                    null означает «указан, значение: пусто» (nullnull — означает дубль пусто-пусто. Кхм. Простите :)
                    string означает «указан, вот значение»;
                    - отсутствие параметра означает «не указан».


                    1. mayorovp
                      05.01.2020 10:45
                      +1

                      Вас послушать, так там все 3 случая обрабатываются по-разному, хотя на самом деле значения false, null, undefined и даже пустая строка означают одно и то же.


                      1. chapuza
                        05.01.2020 10:53
                        -1

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


                        Я просто высказался на тему «false» и «null» — это разные сущности, а наличие варианта «false» не предполагает наличие варианта «true».


          1. mayorovp
            05.01.2020 10:15

            То есть хэдеры — это либо просто мапа стринги на стрингу, либо двумерный массив, либо вообще объект со своими методами.

            Не всё так плохо :-)


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


            Вполне нормально для API, написанного исходя из удобства использования, а не удобства реализации.


            1. chapuza
              05.01.2020 10:18

              API, написанного исходя из удобства использования, а не удобства реализации

              Угу. Вообще, за API, написанные, исходя их удобства реализации / сопровождения — надо гнать мокрыми тряпками из профессии.


            1. PsyHaSTe Автор
              05.01.2020 12:31

              И где тут простота использования? Мне пришел вот такой объект, и мне теперь нужно паттерн матчиться, чтобы понять, то ли мне массив создавать, то ли в мапу добавлять, то ли метод append дергать. Ну вот из моего кода:


              export class BaseClient {
                  private configuration: ClientConfiguration;
              
                  constructor(configuration: ClientConfiguration) {
                      this.configuration = configuration;
                  }
              
                  protected transformOptions(options: RequestInit): Promise<RequestInit> {
                      const headersToInsert = [["Authorization", this.configuration.bearer]];
                      // ???
                      return Promise.resolve(options);
                  }
              }

              Вот как мне теперь вставить этот хэдер? Нужно проверить все варианты что за RequestInit и действовать соответствующе. При чем тут удобство реализации? Этим пользоваться неудобно.


              1. chapuza
                05.01.2020 12:37

                Код выше — это реализация. Пользоваться этим будет тот, у кого есть объект типа BaseClient.


                1. PsyHaSTe Автор
                  05.01.2020 12:42

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


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


                  1. chapuza
                    05.01.2020 12:55

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


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


                    1. PsyHaSTe Автор
                      05.01.2020 12:57

                      В чем тут комфорт-то? Вот в сишарпе хэдеры это просто Map. Какие проблемы из-за этого могут возникнуть? Чем такой интерфейс удобнее?


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

                      Видимо проблема в том, что у меня 50% кода — имлементация, и 50% — использование таких имплементаций.


                      1. chapuza
                        05.01.2020 13:01

                        Чем такой интерфейс удобнее?

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


                        Вот в сишарпе хэдеры это просто Map.

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


                        1. PsyHaSTe Автор
                          05.01.2020 13:04

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

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


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

                          Что тут высокоуровневого? Это просто набор ключей и значений.


                          1. chapuza
                            05.01.2020 13:31
                            -1

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


                            Что тут высокоуровневого?

                            Как бы Map — это прямо очень высокий уровень для HTTP протокола.


                            1. PsyHaSTe Автор
                              05.01.2020 13:34

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

                              Зачем лезть? Вы можете придумать кейс где двумерный массив лучше? Или где хоть одна из функция интерфейса Headers удобнее обычной хэшмапы?


                              Как бы Map — это прямо очень высокий уровень для HTTP протокола.

                              Речь не про HTTP протокол, а про одну из его частей — заголовки.


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


                              1. chapuza
                                05.01.2020 13:36
                                -2

                                Зачем лезть?

                                Всего наилучшего.


                  1. mayorovp
                    05.01.2020 15:43

                    Вот как раз генерённые тулзой классы — самое то место, где надо бы преобразовать HeadersInit в Headers. Если тулза этого не делает — ну, такая тулза :-(


                    Но, вообще говоря, преобразование-то довольно простое выходит:


                        protected transformOptions(options: RequestInit):Promise<RequestInit>
                        {
                            const headers = new Headers(options.headers);
                            headers.set("Authorization", this.configuration.bearer);
                            return Promise.resolve({ ...options, headers });
                        }


    1. 0xd34df00d
      04.01.2020 18:10
      +3

      И опять игнорируют тот факт, что за «магией» скрывается нетвиальная мат теория

      Вывод типов по Хиндли-Милнеру предельно прост.


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

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


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

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


    1. mayorovp
      04.01.2020 18:15
      +3

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


  1. mayorovp
    04.01.2020 18:08
    +3

    Тут описаны не те церемонии, которые и правда раздражают.


    Вот то что раздражает даже C#-программистов:


    public interface IRequest
    {
        Guid Id { get; }
        Guid AuthorityId { get; }
        Guid UserId { get; }
        // ещё 30 свойств
    }
    
    public class Request : IRequest
    {
        public Guid Id { get; set; }
        public Guid AuthorityId { get; set; }
        public Guid UserId { get; set; }
        // ещё 30 свойств
    
        public Request(IRequest other)
        {
             Id = other.Id;
             AuthorityId = other.AuthorityId;
             UserId = other.UserId;
             // ещё 30 присваиваний
        }
    }
    
    public class ImmutableRequest : IRequest
    {
        public Guid Id { get; }
        public Guid AuthorityId { get; }
        public Guid UserId { get; }
        // ещё 30 свойств
    
        public ImmutableRequest(IRequest other)
        {
             Id = other.Id;
             AuthorityId = other.AuthorityId;
             UserId = other.UserId;
             // ещё 30 присваиваний
        }
    }


    1. PsyHaSTe Автор
      04.01.2020 18:14
      +1

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


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


      public interface IRequest
      {
          Guid Id { get; }
          Guid AuthorityId { get; }
          Guid UserId { get; }
          // ещё 30 свойств
      }
      
      [Implement(typeof(IRequest), readonly: false)]
      public partial class Request
      {
      }
      
      [Implement(typeof(IRequest), readonly: true)]
      public partial class ImmutableRequest
      {
      }

      То, что неизменяемость — свойство типа а не биндинга, это конечно печально.


    1. questor
      05.01.2020 01:47

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


    1. aikixd
      05.01.2020 15:11

      Та причина по которой я накатал себе генератор кода. С partial классами заходит на ура.


  1. dopusteam
    04.01.2020 18:33
    +1

    "Но на самом деле всё еще хуже. Код выше работает только с int массивами. А что, если мы хотим использовать long?


    Нам придется написать еще одну перегрузку:"


    Как бы шарпы в дженерики умеют
    Ловко автор всех обманул


    1. PsyHaSTe Автор
      04.01.2020 18:50
      +1

      И какой дженерик вам позволит написать сложение произвольных чисел? Можно пример? И почему разработчики STD либы такие глупые что не сделали этого?



      1. dopusteam
        04.01.2020 19:08
        +2

        Невнимательно прочитал всю задачу, прошу прощения.


      1. xdenser
        04.01.2020 19:49

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


        1. PsyHaSTe Автор
          04.01.2020 21:47

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


          1. xdenser
            04.01.2020 22:42

            А так работает


              public static IEnumerable<T> Consume<T>(this IEnumerable<T> source, dynamic quantity) {
                  if(source == null) yield break;
                  dynamic accumulator = 0;
                  foreach(T i in source) {
                     if(quantity <= accumulator) {
                        yield return i;
                     }
                     accumulator += i;
                  }
               }


            1. PsyHaSTe Автор
              04.01.2020 22:59

              Не похоже:


              var result = new[] {1,2,3}.Consume("Hello").ToArray()
              // RuntimeBinderException: Operator '<=' cannot be applied to operands of type 'string' and 'int'


              1. xdenser
                04.01.2020 23:13

                а что ожидалось?


                1. PsyHaSTe Автор
                  04.01.2020 23:13

                  Что компилятор скажет что тут происходит дикость и не даст скомпилировать.


                  Nullable кстати тоже не будут корректно отрабатывать.


                  1. xdenser
                    04.01.2020 23:25

                    Ну если определить соответствующие операторы для string и int то такой код может быть корректным, а так конечно это не в ту сторону по шкале движение, в том смысле что статический контроль типов наоборот подавлен dynamic, там можно еще поиграть, например обявить T quantity, тогда ваш пример будет падать уже при компиляции, не знаю можно ли в с# как то форсировать проверку наличия оператора для дженерик типа..., так это переносится в рантайм.


                    1. PsyHaSTe Автор
                      04.01.2020 23:34

                      Но я не хочу подавлять контроль типов.


                      Ни в одном серьезном проекте на сишарпе новее 2010 года вы dynamic не встретите. Это фича сдлеанные давным давно для совместимости с COM и грудами легаси. Во многих проектах он просто под запретом.


                      Вынос проблем в рантайм — это не решение.


                      Ну если определить соответствующие операторы для string и int то такой код может быть корректным

                      Но я не могу залезть в std и добавить операторы для string и int. Да и даже если бы мог, я бы такой оператор писать не стал — какая для него логика должна быть? Никакого разумного в голову не лезет.


                      не знаю можно ли в с# как то форсировать проверку наличия оператора для дженерик типа..., так это переносится в рантайм.

                      В этом и суть — что никак. А в языках с более мощными системами типов (Rust/Haskell/F#/Scala) — можно.


                      1. xdenser
                        05.01.2020 01:27

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


                        public static IEnumerable<T> Consume<T>(this IEnumerable<T> source, T quantity) where T : IConvertible  {
                              if(source == null) yield break;
                              long accumulator = 0;
                              long qLong = Convert.ToInt64(quantity); 
                              foreach(T i in source) {
                                 if(qLong <= accumulator) {
                                    yield return i;
                                 }
                                 accumulator += Convert.ToInt64(i);
                              }
                           }

                        Наверно можно написать и более "дженерик вариант", если еще потребовать от T поддержку IComparable и использовать достаточно широкий аккумулятор, чтоб не попасть на переполнение или потерю точности, впрочем с плавающей точкой это не решается и в "правильном" варианте, надо знать что там внутри у метода


                        1. PsyHaSTe Автор
                          05.01.2020 01:37

                          Ну интерфейс IConvertible вообще отвратительный, половина методов просто бросают исключения:


                          var result = new ulong[] {ulong.MaxValue}.Consume(1UL).ToArray();
                          var result2 = new double[] {((double) long.MaxValue) + 1}.Consume(1UL).ToArray();
                          var result3 = new string[] {"Hello"}.Consume("World").ToArray();

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


                          1. xdenser
                            05.01.2020 02:20

                            Ну простую можно копипастить. Что то более сложное лучше обобщать. А на std лежит еще тяжесть обратной совместимости.


          1. algotrader2013
            04.01.2020 23:30

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

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


            1. PsyHaSTe Автор
              04.01.2020 23:36
              +1

              Скорее всего


              1. сначала не подумали
              2. потом было поздно (ломать обратную совместимость)

              В C# 10-11 сделают наконец тайпклассы, тогда это всё сделать будет можно.


  1. somebody4
    04.01.2020 19:25

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

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

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


    1. PsyHaSTe Автор
      04.01.2020 21:54

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

      ИМХО лучше иметь возможность написать изящную конструкцию, чем не иметь. С тезисом что разработчика нужно заставить много писать и страдать, что он пока пишет понял, что он делает — я не согласен (хотя есть люди которые так считают).


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


  1. podivilov
    04.01.2020 21:45

    Почему в статье используется знак диеза (?) вместо октоторпа (#)?


    1. PsyHaSTe Автор
      04.01.2020 21:49

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


      The name "C sharp" was inspired from musical notation where a sharp indicates that the written note should be made a half-step higher in pitch. This is similar to the language name of C++, where "++" indicates that a variable should be incremented by 1. The sharp symbol also resembles a ligature of four "+" symbols (in a two-by-two grid), further implying that the language is an increment of C++.

      Due to technical limitations of display (standard fonts, browsers, etc.) and the fact that the sharp symbol (?, U+266F, MUSIC SHARP SIGN) is not present on the standard keyboard, the number sign (#, U+0023, NUMBER SIGN) was chosen to represent the sharp symbol in the written name of the programming language. This convention is reflected in the ECMA-334 C# Language Specification. However, when it is practical to do so (for example, in advertising or in box art), Microsoft uses the intended musical symbol.

      Во-вторых парсер хабра в режиме markdown (а я всегда пишу в нем) считает решетки началом заголовка и съедает их.


  1. johnfound
    04.01.2020 22:22
    +1

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


    – Храбрость без ритуала ведёт к бунту. Правдивость без ритуала ведёт к грубости. Верность без ритуала ведёт к подхалимству, – ответил Учитель...


    1. selrorener
      04.01.2020 23:13

      Вот цитата которая однажды мне понравилась.

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


    1. S-e-n
      05.01.2020 00:14

      Но разве это так?
      Да.

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


  1. Zar13st
    04.01.2020 22:39

    что-то я не понял… в с# есть дженерики, о каких неудобных перегрузках идёт речь?


    1. Szer
      04.01.2020 23:18

      Констрейнов на наличие стат методов в типе в сишарпе нет.


      В фшарпе есть.


  1. abar
    05.01.2020 00:43

    Забавно. Когда я пытался написать рейтрейсер на Хаскелле, я постоянно спотыкался о то, что Number, Numeric, и какой-то Интегральный типы — это разные типы, часть функций из стандартной библиотеки возвращает одни типы, часть — другие, как это конвертировать и куда приводить — непонятно. Тот пример, который я написал бы на джаве в пару (о ужас!) классов (даже не пришлось бы указывать, что short и int надо переводить в long), на хаскелле обернулся двухдневной борьбой с компилятором. Такое вот «отсутствие церемоний». Финальным аккордом стало то, что библиотека, которую я взял для рендеринга, не поддерживала паралелизации и вся эта битва за чистоту функций оказалась (в моём случае) бесполезной.


    1. 0xd34df00d
      05.01.2020 00:53
      +1

      Когда я пытался написать рейтрейсер на Хаскелле, я постоянно спотыкался о то, что Number, Numeric, и какой-то Интегральный типы — это разные типы, часть функций из стандартной библиотеки возвращает одни типы, часть — другие

      Стандартная Prelude в хаскеле — дно, да. Зато есть несколько дюжин альтернативных реализаций! Мне вот subhask больше всего нравится.


      как это конвертировать и куда приводить — непонятно

      fromIntegral — швейцарский нож всех приведений.


  1. Siemargl
    05.01.2020 01:35
    -1

    Какой то троллинг даже без цели.


  1. impwx
    05.01.2020 11:46
    -1

    Диаграмма на КДПВ неправильная. Там должно быть две оси: «количество церемоний» по горизонтали и «строгость типизации» по вертикали". Это позволит показать, например, что Java куда более церемониальная, чем тот же C#.

    С другой стороны, отсутствие «церемоний» — не всегда хорошо. Явное указание типов в интерфейсе является single source of truth: по нему можно сразу определить, что неправильно — реализация функции или ее использование. Вот например:

    let add a b = a + b
    printf "%A" (add 1 2)
    printf "%A" (add "a" "b")
    
    Компилятор падает на втором вызове функции, потому что первый «застолбил» за ней конкретные типы. Поменяем вызовы местами, сделаем сложение строк первым — будет падать на сложении чисел. Как понять, что имелось в виду — сложение чисел, или строк, или вообще тут предполагалось наличие SRTP, но компилятор не смог сам об этом догадаться?..

    In the face of ambiguity, refuse the temptation to guess.


    1. PsyHaSTe Автор
      05.01.2020 12:40

      Ну в фшарпе компилятор немного глуповат, да.


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


      С другой стороны, отсутствие «церемоний» — не всегда хорошо.

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


      1. Szer
        05.01.2020 16:15

        Ну в фшарпе компилятор немного глуповат, да.

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


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


        let inline add x y = x + y


        И все заработает.


  1. balajahe
    05.01.2020 12:19
    +1

    Вас всегда очень приятно читать :) Раньше программировал на JavaScript, и церемоний с типами было на самом деле больше, так как приходилось на каждую функцию писать документацию. Перешел на TypeScript и просто в восторге — из сигнатуры уже все понятно, комментарии не нужны, а если хочется дополнительной гибкости — есть объединения типов и any. Для энтерпрайза самый красивый язык, по моему мнению.
    PS
    Так выглядит полностью динамический но при этом типизированный код на TS )

    type Document = any
    type Result = any
    public async reduce(
        filter: (doc: Document) => boolean, 
        reducer: (doc: Document, result: Result) => void,
        result: Result
    ): Promise<Result> {
    ...


    1. chapuza
      05.01.2020 12:34

      Для энтерпрайза самый красивый язык, по моему мнению.

      В сравнении с чем? Со скалой? F?? erlang? go? COBOL? Haskell? Idris? Agda?


      1. vitvakatu
        05.01.2020 12:59

        У вас интересный выбор энтерпрайз-языков, особенно Go, Idris и Agda.


        1. chapuza
          05.01.2020 13:03

          Не я первый начал :) JS еще интереснее в этом ключе (Go — уже давно энтерпрайз, если Гугл считать таковым, конечно).


        1. 0xd34df00d
          05.01.2020 18:24

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


      1. balajahe
        05.01.2020 13:07

        Ну, погорячился. Если с Java или Go — безусловно лучше (если забыть про многопоточность и много чего еще), если с Kotlin / Scala не уверен. У меня часто бывают задачи на разбор динамических Json, с логикой в зависимости от структуры, а все структуры заранее не опишешь, поэтому лишние церемонии с искусственным динамизмом мешают. Когда есть any — это приятно.


        1. chapuza
          05.01.2020 13:28

          если забыть про многопоточность и много чего еще

          Разбор динамического Json — это восемь часов на написание библиотеки (если 100500 существующих почему-то не подошли) и MyJson.parse везде после этого. Какое это отношение имеет к энтерпрайзу, где без многопоточности и много чего еще — вообще шагу не ступить в современном мире, не очень понятно.


    1. PsyHaSTe Автор
      05.01.2020 12:59
      +1

      Спасибо, рад, что нравится.


      Что до TypeScript — то с ним действительно довольно приятно работать. Хейлсберг — большой молодец


      Так выглядит полностью динамический но при этом типизированный код на TS )

      Ну, откровенного говоря не особо это типизированно. Мне вот в Express еще такое понравилось, так сказать, интерфейс "что-то с чем-то".


      interface MyInerface {
          [key: any]: any;
      }


      1. balajahe
        05.01.2020 13:17

        Я типизированные заглушки обычно на будущее оставляю, и для авто-доки полезно, а писать в коде явно any — как-то неудобно перед потомками )


  1. muhaa
    05.01.2020 12:27

    1. Как уже упоминалось, в C# есть дженерики. Они годятся для классов, но не всегда годятся для чисел. Вопрос — насколько часто приходится делать подобного уровня абстракции функции для чисел? И если таки пришлось, то очень вероятно это какая-то базовая библиотека, от которой требуется высокое быстродействие а не максимальная абстрактность. Тогда нет проблем скопировать несколько версий функции или привести все к одному типу. Т.е. это проблема, которой никогда нет в действительности.

    2. Если не хочется церемоний c классами, ничто не мешает писать что-то вроде:

    var myObject = new MyClass() { name = "Имя", id = 1 };

    Или даже:
    var myObject = ( name: "Имя", id:  1 );

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


    1. PsyHaSTe Автор
      05.01.2020 12:56
      +2

      Вопрос — насколько часто приходится делать подобного уровня абстракции функции для чисел?

      А они и не для чисел. Ну самый жизненный пример — хотел бы я иметь такой интерфейс:


      interface IParseable<T> {
          static T Parse(string text);
      }

      А его сделать нельзя. А вот эта штука мне бы везде пригодилась, где Json/Xml/… у меня используются.


      Поэтому если вопрос "часто ли нужны тайпклассы" — да, часто.


      Если не хочется церемоний c классами, ничто не мешает писать что-то вроде:

      Не понял, тут вроде церемоний ровно столько же


      Или даже:

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


      private static (string name, int id) GetMyObject() {
          return ( name: "Имя", id:  1 );
      }


      1. muhaa
        05.01.2020 16:17

        И тогда получаются такие вот хрени:
        Честно признаться, в длинных и нудных прикладных алгоритмах, с которыми я обычно работаю, я так и делаю:
        private static (string name, int value) GetSomeResult() {
            return ("Имя", 1 );
        }

        Если класс нужен только в одном месте кода, достаточно «описать» его один раз в сигнатуре функции. Если позже оказалось что описание нужно повторять, тогда заменяю на класс (или структуру), в котором только public поля без конструкторов, жеттеров, сеттеров.
        Я к тому, что по ничто не мешает писать на C# в стиле близком к минимальному, как в JS.
        Сути проблемы с IParseable не понял, но бог с ней.


  1. potan
    05.01.2020 17:22
    +1

    Интересен подход с максимализацией таких церемоний — type-driven development, в наиболее полном виде реализованный в IDE для Idris, но присутствующий и в IDE для более распространенных языков.
    Программист сначала пишет типы, а по типам соответствующая им программа генерируется полуавтоматически.


  1. balajahe
    05.01.2020 18:14
    +1

    Столько классных комментариев в одном месте, а меня на философию потянуло ) Ведь типизация — это всего лишь система ограничений, причем чем жестче мы хотим ограничить наши компоненты (strong cohesion и все такое), тем гибче и сложнее должны быть ограничивающие механизмы, чтобы каждого ограничить точно по фигуре (тайпклассы, завтипы и т.д.). При этом мы исходим из гипотезы, что чем жестче ограничен каждый компонент, тем надежнее система в целом. А это верно лишь отчасти. В живой природе интерфейсы между органами построены на адаптивности, причем в весьма широких пределах. Часть нейронов может помереть от гипоксии — человек что-то забыл, но новые связи в других зонах мозга взяли на себя функцию, и через год он здоров. Можно желчный пузырь отрезать, или половину желудка — и ничего, организм справляется. Можно даже нейромедиаторами закинуться — мозг поплывет немного, но быстро обнаружит обман и включит компенсацию. Получается, что технологии будущего — это построение «умных интерфейсов», которые из слабо-типизированного сигнала могут извлекать полезную информацию, подстраиваясь под источник. Что-то типа автономных адаптивных микросервисов на основе NLP. Простите уж за оффтоп.


    1. selrorener
      05.01.2020 18:28

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

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


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


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


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


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

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


      1. balajahe
        05.01.2020 22:43
        -1

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


        1. PsyHaSTe Автор
          06.01.2020 00:09
          +4

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


          1. selrorener
            06.01.2020 00:19
            -4

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


            Эти люди не понимают, что типы это не только "у меня тут any — хочу ограничить тип "для пользователя"". Типы — это такая же логика, как a + b. И пишется она в первую очередь для компилятора, как и обычная логика. А уже далее появляются какие-то пользователи. Если код не реализует нужную логику — абсолютно неважно то, насколько он читаем. И типы — это такой же код, но только НЕ в языках с описательной типизацией.


          1. balajahe
            06.01.2020 01:42

            -


        1. selrorener
          06.01.2020 00:12
          -3

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

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


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


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


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


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


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

          Ну да, поэтому я уже давно выступаю за то, что "статическая типизация" несостоятельное понятие. Сейчас это уже понятно многим, когда "статическая типизация" пошла в пхп/js/python. Просто нужно понимать, что какая-то типизация прикрученная поверх рантайм-типизации не является статической, хоть так и называется.


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


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


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


          Поэтому мы и можем видеть всякие совсем нелепые тезисы. Допустим "С++ не может вывести тип". Откуда такой тезис относительно статического языка, в котором тип попросту не может не вывестись? Правильно, из логики описательной типизации.


          Вот мы и получаем. Эти люди сами себя объявили евангелистами типизации, назначили себя судьями. Начинают кидаться лозунгами вида "если не как у нас — то никак". Выучили пару базвордов и кнопку "минус". Вот и организуют набеги, вместо аргументации.


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


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


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


          1. TargetSan
            06.01.2020 01:45

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

            Уж простите что влезаю в ваш разговор. Но что тогда для вас тип? Можете дать определение со своей стороны?


            1. selrorener
              06.01.2020 02:38
              -1

              Но что тогда для вас тип? Можете дать определение со своей стороны?

              Я бы не сказал, что тип вообще требует какого-либо определения в том плане, в котором его обычно определяют. Тип — это просто какой-то идентификатор. Всё. Далее на него каким-либо образом, прямо или косвенно — навешиваются всякие свойства. Далее каждый объект аннотируется этим идентификатором, тем самым объект наследует свойства типа.


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


              А далее уже появляется какая-то логика работы с этими свойствами. Классификация и прочее.


              1. TargetSan
                06.01.2020 03:02
                +3

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

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


                Тип — это просто какой-то идентификатор. Всё.

                Согласно вашему определению, в выражении int foo = 0; типами можно назвать и int, и foo. Но это ведь не так, правда?


                Далее на него каким-либо образом, прямо или косвенно — навешиваются всякие свойства.

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


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

                Какие у этого типа будут свойства? Или, если это не тип, что это тогда?


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

                А тут мы с вами должны дать определение объекту и процессу наследования. Может, пока остановимся на типах?


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

                Так всё-таки, чтобы наделять объект свойствами (?) типы не нужны?


                Чуть выше вы сами пишете:


                Поэтому типы именно как типы появились в статических языках в связи с необходимостью.

                Пока не совсем понятно, какая необходимость заставила статические языки (С?) вводить типы. Если для наделения объекта свойствами типы не нужны.


                Общие свойства множества объектов выносятся отдельно и им даётся имя/идентифактор. Это просто упрощает определение нового объекта с аналогичным набором свойств.

                Т.е. если я правильно понял, для вас тип — какое-то соглашение?


                А далее уже появляется какая-то логика работы с этими свойствами. Классификация и прочее.

                Чтобы что-то классифицировать, и чтобы появлялась логика работы, надо определиться — с чем мы имеем дело. Давайте начнём с этого?


                1. selrorener
                  06.01.2020 03:29
                  -3

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

                  Нет. К тому же определение я дал и оно очевидно.


                  Согласно вашему определению, в выражении int foo = 0; типами можно назвать и int, и foo. Но это ведь не так, правда?

                  Нет, не согласно. Язык разделяет идентификаторы типов и не типов.


                  Вот тут уже интересней. Что это за свойства, откуда они берутся?

                  Неважно.


                  Если я понял вас правильно, то int вы типом считаете — исходя из вот этой вашей фразы:

                  Какая-то не внятная попытка. Я не совсем понял её смысл.


                  Какие у этого типа будут свойства? Или, если это не тип, что это тогда?

                  Свойства ему определяет язык. Самой базовое свойство в си — sizeof.


                  А тут мы с вами должны дать определение объекту и процессу наследования. Может, пока остановимся на типах?

                  Почему? К тому же, опять же неверно. Объект никакого отношения к наследованию не имеет.


                  Так всё-таки, чтобы наделять объект свойствами (?) типы не нужны?

                  Не нужны.


                  Чуть выше вы сами пишете:

                  Опять какие-то невнятные попытки.


                  Пока не совсем понятно, какая необходимость заставила статические языки (С?) вводить типы. Если для наделения объекта свойствами типы не нужны.

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


                  Т.е. если я правильно понял, для вас тип — какое-то соглашение?

                  Нет, тип — это идентификатор. Всё.


                  Чтобы что-то классифицировать, и чтобы появлялась логика работы, надо определиться — с чем мы имеем дело. Давайте начнём с этого?

                  Уже всё определено. Ничего более определять ненужно. Есть свойства — они биндятся на идентификатор. Этот идентификатор биндится на объект — далее объект наследует свойства объекта привязанные к типу.


                  Давайте совсем для дошкольников. Есть свойство — sizeof. Это свойство типа, свойство привязанное к идентификатору. Допустим, в каком-то случае к int привязывается свойство sizeof == 4. Далее объект аннотируется типом и наследует(это не то наследование, о котором вы подумали) этот sizeof.


                  Всё остальное работает по тому же принципу. В тип так же может быть забинжены какие-нибудь операции над объектом данного типа. И не только.


                  1. TargetSan
                    06.01.2020 10:42
                    +3

                    Ну хорошо, возьмём ваше определение.


                    Тип — это просто какой-то идентификатор. Всё.
                    Далее на него каким-либо образом, прямо или косвенно — навешиваются всякие свойства.

                    С тем, что такое тип, определились.


                    Но тогда меня немного смущает ваша фраза из контекста выше:


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

                    Есть такая занятная штука как std::variant, которая позволяет хранить в одном и том же оъекте (?) какие-то значения одного из двух или более других типов. Т.е. это реализация тех самых типов-сумм для С++. Вы говорите выше, что это не тип. А потом даёте такое определение типа, под которое std::variant попадает на 100%. Так всё-таки, это тип или нет? Мне правда интересно.


                    А тут мы с вами должны дать определение объекту и процессу наследования. Может, пока остановимся на типах?

                    Почему? К тому же, опять же неверно. Объект никакого отношения к наследованию не имеет.

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


                    Если я понял вас правильно, то int вы типом считаете — исходя из вот этой вашей фразы:

                    Какая-то не внятная попытка. Я не совсем понял её смысл.

                    Попытка, простите, чего? Не понял.


                    Так всё-таки, чтобы наделять объект свойствами (?) типы не нужны?

                    Не нужны.

                    Тогда получается, что в языке (С/С++?) можно создать объект какого-либо типа (или вообще без типа) и наделить его какими-то свойствами по ходу дела? Получается та самая "скриптуха"? Или приведите пожалуйста пример, если я вас неправильно понял.


                    Опять какие-то невнятные попытки.
                    Ещё более невнятные попытки. Там всё понятно.
                    … и не пытаться меня поймать, что заранее обречено.

                    Так и не понял, попытки чего. Пока я только честно пытаюсь вас понять.


                    Надо просто мыслить не так узко

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


                    Давайте совсем для дошкольников. Есть свойство — sizeof. Это свойство типа, свойство привязанное к идентификатору. Допустим, в каком-то случае к int привязывается свойство sizeof == 4. Далее объект аннотируется типом и наследует(это не то наследование, о котором вы подумали) этот sizeof.

                    Ок. Пусть будет sizeof. Что это свойство для вас определяет? Почему оно равно именно 4? Если это не то наследование (уже спросил выше), то какое?


                    Всё остальное работает по тому же принципу. В тип так же может быть забинжены какие-нибудь операции над объектом данного типа. И не только.

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


                    1. selrorener
                      06.01.2020 21:20
                      -3

                      Есть такая занятная штука как std::variant, которая позволяет хранить в одном и том же оъекте (?) какие-то значения одного из двух или более других типов. Т.е. это реализация тех самых типов-сумм для С++. Вы говорите выше, что это не тип. А потом даёте такое определение типа, под которое std::variant попадает на 100%. Так всё-таки, это тип или нет? Мне правда интересно.

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


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

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


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

                      Хорошо. Здесь подойдёт и словарное определение объекта. Это не то, о чём нужно заботиться. Просто ненужно думать, что определение из какой-то ооп-скриптухи является каким-то общепринятым, либо оно вообще что-то да значит. Это определение специфично для отдельной области.


                      Попытка, простите, чего? Не понял.

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


                      Тогда получается, что в языке (С/С++?) можно создать объект какого-либо типа (или вообще без типа) и наделить его какими-то свойствами по ходу дела?

                      Не получается. Хотя в си смешанная схема. Свойства навешиваются не только через типы, но и прямо на объекты(~= переменные/значения).


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


                      Поэтому мы выделяем эти общие свойства в группы/классы и уже описываем свойства для них. А далее зайчика/лошадку приписываем к этой группе.


                      Получается та самая "скриптуха"? Или приведите пожалуйста пример, если я вас неправильно понял.

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


                      Хотя я определял скриптуху не через это, но это одно можно назвать различием так же.


                      Ок. Пусть будет sizeof. Что это свойство для вас определяет?

                      Абсолютно неважно. Что определяет свойство "цвет" у лошадки? Это глупый вопрос. Это не задача системы типов. Есть то, что наделяет. И есть то, что это свойство интерпретирует. В данном случае его интерпретирует "язык", а не пользовательский интеретатор. Но может быть наоборот.


                      Почему оно равно именно 4?

                      Почему цвет лошадки чёрный? Это неважно.


                      Если это не то наследование (уже спросил выше), то какое?

                      Обычное. На примере лошадки выше объяснил.


                      Ведь не всякие же свойства. Или вообще любые?

                      Любые.


                      Или есть какие-то правила, какие свойства и операции могут быть ассоциированы с типом?

                      Это уже нюансы каждого свойства. К делу отношения не имеет.


                      К тому же, выше вы говорили, что свойства и операции могут быть ассоциированы непосредственно с объектом. Можете показать? Я правда о таком не слышал.

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


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


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


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


                1. PsyHaSTe Автор
                  06.01.2020 03:32

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


                  1. selrorener
                    06.01.2020 03:48
                    -3

                    Посмотрите на профиль товарища — специально зарегистрировался чтобы в этой теме нести чушь.

                    Основания.


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

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


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


          1. balajahe
            06.01.2020 01:54
            -1

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


            1. 0xd34df00d
              06.01.2020 02:34
              +2

              По сути-то Вы правы

              Нет.


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


              1. selrorener
                06.01.2020 02:46
                -1

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

                Как там с С++ и прочим? Совсем всё печально?


                1. 0xd34df00d
                  06.01.2020 04:11

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


                  Ну хоть платят за всё это хорошо.


                  1. selrorener
                    06.01.2020 04:26
                    -1

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

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


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


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


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


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


                    1. 0xd34df00d
                      06.01.2020 04:34
                      +2

                      Ведь как минимум приду я, либо ещё кто-то

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


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


                      Я уж не говорю о метауровне ведения дискуссии.


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

                      Низзя так с виртуалами.


                      1. selrorener
                        06.01.2020 04:47
                        -2

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

                        Лозунги. Выше вы опростоволосились, да и множество раз до этого. А далее игнорирование темы.


                        Но только это же не тот случай.

                        Тот.


                        С вами ведь невозможно вести конструктивный диалог

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


                        начиная от весьма воинственного непонимания предмета

                        Основания. Не принятие догматов какой-то там секты — это не непонимание предмета. Я не обязан понимать сектантские домагматы.


                        который вы обсуждаете (как в этой ветке), до совсем, гм, странных утверждений,

                        Основания.


                        вроде того, что на стандарт языка всем плевать

                        Это чушь. Такого не было. Да и опять же — если не плевать, то где же ваш стандарт?


                        и никто не стремится реализовывать стандарт (как в соседней ветке).

                        Опять враньё. Ну это для вас типично. Там было "весь стандарт".


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


                        В любом случае методичка эта работает следующим образом. Берётся какой-то язык без стандарта и начинается сравнение со стандартом у С++. Обычно зелёные крестовики на это ведутся и боятся идти против стандарта. Но, очевидно, с не-зелёным человеком такая херня не прокатит.


                        Я уж не говорю о метауровне ведения дискуссии.

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


                        1. 0xd34df00d
                          06.01.2020 04:53
                          +2

                          Выше вы опростоволосились, да и множество раз до этого.

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


                          Не принятие догматов какой-то там секты — это не непонимание предмета. Я не обязан понимать сектантские домагматы.

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


                          как это делают все.

                          Основания.


                          Олсо.


                          вроде того, что на стандарт языка всем плевать

                          Это чушь. Такого не было. Да и опять же — если не плевать, то где же ваш стандарт?

                          и


                          а во-вторых я плевал на стандарт, как это делают все.

                          Это просто топ кек.


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

                          Я искренне надеюсь, что вы троллите.


                          1. selrorener
                            06.01.2020 05:13
                            -4

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

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


                            Здесь пациент пытается показать, что он герой. А его оппонент клоун. Нет, он не сел в лужу — он просто игрался. Не хватает ещё "я просто троллил — на самом деле я то знал, что сделать в С++ это можно".


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

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


                            Расчёт делает на то, что оппонент услышав "завтипы" убежит и всё забудет. Методичка там стара как мир.


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


                            А надеется он на то, что оппонент не знает что это такое и что есть, а чего нет в хаскеле. Далее там он начинает "ну дак идрис" и прочая чушь. "ну дак фп — идрис то ФП и хаскель ФП — значит завтипы", "а С++ не фп — значит не завтипы". Логично? Ахрененно.


                            Основания.

                            Я оставлю это вам в качестве домашнего задания.


                            и

                            Что и? Где стандарт?


                            Это просто топ кек.

                            Это просто уровень развития. Ответ то будет? Или как?


                            Я искренне надеюсь, что вы троллите.

                            Опять попытка включить клоуна и сделать вид, что пациент чего не понимает, хотя он всё понимает.


                            1. 0xd34df00d
                              06.01.2020 06:16
                              +5

                              Не хватает ещё "я просто троллил — на самом деле я то знал, что сделать в С++ это можно".

                              Что именно — это?


                              А с чего меня это волновать должно?

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


                              Расчёт делает на то, что оппонент услышав "завтипы" убежит и всё забудет. Методичка там стара как мир.

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


                              Я уже показывал примеры. "Бла-бла — С++ говно, а хаскель круто", "почему?", "а завтипы".

                              Лол. Но в хаскеле их нет! И нормальных не будет, скорее всего, никогда.


                              Я оставлю это вам в качестве домашнего задания.

                              Какую из ваших цитат про слив оппонента (или пациента?) мне здесь взять?


                              Это просто уровень развития. Ответ то будет? Или как?

                              Я оставлю это вам в качестве домашнего задания.


                              Опять попытка включить клоуна и сделать вид, что пациент чего не понимает, хотя он всё понимает.

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


                              1. selrorener
                                06.01.2020 06:31
                                -3

                                Что именно — это?

                                Ну как, поиск типа в тапле.


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

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


                                Лол. Но в хаскеле их нет! И нормальных не будет, скорее всего, никогда.

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


                                Какую из ваших цитат про слив оппонента (или пациента?) мне здесь взять?

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


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


                                А далее я просто дам ответ и сниму с себя последствия.


                                Я оставлю это вам в качестве домашнего задания.

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


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

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


                                Поэтому я говорю "С++ может" — я иду и делаю. А вы говорите и ничего не можете. Это то, почему вокруг меня бегают табуны адептов и гадят мне.


                                А один, а адептов много. Так и живём.


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


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


                                Самое интересное, что эти гении действительно верят в свои супер-способности. Он сидит и думает "вот, я врал и заставил сказать его "стадарт говно" и теперь я буду пастить везде это.


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


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


                                И вот интересно — кто окажется сильнее. Я или табун сектантов.


                                1. 0xd34df00d
                                  06.01.2020 08:36
                                  +5

                                  Ну как, поиск типа в тапле.

                                  Давайте вы сначала тыкнете меня, где я сказал, что это сделать нельзя. Напротив, я сказал, что это как раз сделать можно. Конкретная цитата (моя): «Ближайший костыль — ограничиться, скажем, std::tuple и проверять, что std::get — well-formed.»

                                  Но окружение позволяет на вопрос "а почему в С++ говно, а в хаскеле лучше" отвечать хернёй "завтипы".

                                  С этим у вас так же получится, как с якобы тезисом о тупле выше?


                                  Иными словами, конкретную ссылку дайте. Или цитату.




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


                                  1. selrorener
                                    06.01.2020 15:56
                                    -6

                                    Давайте вы сначала тыкнете меня, где я сказал, что это сделать нельзя.

                                    Здесь пациент пытается играть в клоуна, т.е. ссылаться на то, что было после. Когда он уже сел в лужу и в своих тезисах запутался. Потом он погулил и узнал о std::get.


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

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


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

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


                                    И теперь понятно зачем он пытался это сделать. Он думал, что этого сделать нельзя, поэтому и предлагал "мерится".


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


                                    Ближайший костыль — ограничиться, скажем, std::tuple и проверять, что std::get — well-formed

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


                                    Я уже не раз доказывал, что представления адепта ограничены си с классами. И он С++14 он ничего не знает, очевидно. И он не знал про get, но после он погуглил и узнал. В противном случае он бы такую чушь не нёс.

                                    С этим у вас так же получится, как с якобы тезисом о тупле выше?

                                    Соревнование было в контексте "С++ чего-то не может", всё это в контексте системы типов. Связь очевидна.


                                    В любом случае, одна из двух причин, почему я тут трачу свои силы на эту вот писанину

                                    Она очевидна. Вы слабы, очень слабы. Единственное, что вы можете — спамить и надеятся, что табуны сектантов меня заминусуют до "раз в день" и тогда я отвечать не смогу.


                                    Далее данный пациент начнёт усиленно спамить и сообщать "да вы посмотрите — он не отвечает. Да и он заминусован — он явно не прав".


                                    1. 0xd34df00d
                                      06.01.2020 18:09
                                      +3

                                      И он не знал про get, но после он погуглил и узнал. В противном случае он бы такую чушь не нёс.

                                      Доказательства от бога.


                                      Далее данный пациент начнёт усиленно спамить и сообщать "да вы посмотрите — он не отвечает. Да и он заминусован — он явно не прав".

                                      Хрустальный шар у вас тоже так себе.


                                      1. selrorener
                                        06.01.2020 18:35
                                        -4

                                        Доказательства от бога.

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


                                        Хрустальный шар у вас тоже так себе.

                                        Основания.


            1. selrorener
              06.01.2020 02:54
              -4

              так как мы начинаем спорить о значении слов «статическая», «скриптуха» и т.д. Зачем такое жесткое противостояние?

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


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


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


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