Под катом — перевод статьи опытного разработчика о его опыте практического применения Go. Важно — мнение переводчика может не совпадать с мнением автора статьи.




Итак, прошел год с тех пор, как я начал использовать Go. Неделю назад я удалил его из production.

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

Итак, поговорим о том, почему я не считаю Go полезным инструментом:

Инструментарий


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

анализ покрытия


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

GoCover.Count[n] = 1

Где n — это идентификатор позиции ветвления в файле. Ну а еще она вставляет в конец файла вот такую гигантскую структуру:

действительно гигантская
var GoCover = struct {
        Count     [7]uint32
        Pos       [3 * 7]uint32
        NumStmt   [7]uint16
} {
        Pos: [3 * 7]uint32{
                3, 4, 0xc0019, // [0]
                16, 16, 0x160005, // [1]
                5, 6, 0x1a0005, // [2]
                7, 8, 0x160005, // [3]
                9, 10, 0x170005, // [4]
                11, 12, 0x150005, // [5]
                13, 14, 0x160005, // [6]
        },
        NumStmt: [7]uint16{
                1, // 0
                1, // 1
                1, // 2
                1, // 3
                1, // 4
                1, // 5
                1, // 6
        },
}


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

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


То же самое с утилитой для анализа производительности — выглядит хорошо, пока не посмотришь как она работает. А работает она путем оборачивания кода в цикл с переменным количеством итераций. После чего цикл итерируется пока код не выполняется «достаточно долго» (по умолчанию 1 секунда), после чего общее время выполнения делится на количество итераций. Такой подход не только включает в замер производительности сам цикл, но также скрывает флюктуации. Код реализации из benchmark.go:

func (b *B) nsPerOp() int64 {
    if b.N <= 0 {
        return 0
    }
    return b.duration.Nanoseconds() / int64(b.N)
}

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

компилятор и go vet


Одна из обсуждаемых сильных сторон Go — это быстрая компиляция. Насколько я могу сказать, это частично достигается за счет того, что многие проверки, которые обычно делает компилятор просто пропускаются — они реализованы в go vet. Компилятор не проверяет проблемы с одинаковыми именами переменных в разных областях видимости или с некорректным форматом printf, все эти проверки реализованы в go vet. Более того, качество проверок ухудшается в новых версиях: в версии 1.3 не показывает проблемы, которые показывала версия 1.2.

go get


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

$GOPATH


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

Go race detector


Вот это — неплохая штука. Огорчает что оно вообще нужно. Ну и тот факт, что работает не на всех поддерживаемых платформах (FreeBSD, кто-нибудь?) и максимальное количество goroutine всего 8192. Более того, необходимо умудриться столкнуться с race condition — что довольно трудно, учитывая насколько race detector все замедляет.

Рантайм


Channels/mutexes


Каналы и мьютексы МЕДЛЕННЫЕ. Добавление синхронизации через мьютексы на production настолько снизило скорость работы, что лучшим решением стал запуск процесса под daemontools и его перезапуск в случае падения.

логи падений


Когда go падает, все без исключения goroutine отгружают свой стек вызова в stdout. Объем этой информации растет с ростом вашей программы. Более того, многие сообщения об ошибках косноязычно сформулированы, к примеру ‘evacuation not done in time’ или ‘freelist empty’. Создается впечатление что авторы этих сообщений задались целью максимизировать трафик к поисковому движку google, потому что в большинстве случаев это единственный способ понять что происходит.

интроспекция runtime



Не работает, на практике Go поддерживает в живых концепцию «отладка принтами». Можно использовать gdb, но не думаю что вы захотите это делать.

Язык


Я не получаю удовольствия от написания кода на Go. Я либо сражаюсь с ограниченной системой типов с кастами всего в interface{} либо занимаюсь копипастой кода который делает практически одно и то же для разных типов. Каждый раз, когда я добавляю новую функциональность это выливается в определение еще большего количества типов и допиливания кода для работы с ними. Чем это лучше использования C с адекватными указателями, или использования функционального кода со сложными типами?

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

Проблемы вызывает преобразование byte[] в string и работа с массивами/слайсами. Да, я понимаю для чего все это было сделано, но по моим ощущениям оно слишком низкоуровневое по отношению к остальному языку.

А еще есть [:],... с append. Посмотрите на это:

iv = append(iv, truncatedIv[:]...)

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

стандартная библиотека


Часть стандартной библиотеки неплоха, особенно криптография, которая в лучшую сторону отличается от простой обертки над OpenSSL, которую вам предлагает большинство языков. Но документация и все что связано с интерфейсами… Мне часто приходится читать код реализации вместо документации, потому что последняя часто ограничивается бесполезным «имплементирует метод X».

Большие проблемы вызывает библиотека 'net'. В отличие от обычных сетевых библиотек, эта библиотека не позволяет менять параметры создаваемых сокетов. Хотите установить флаг IP_RECVPKTINFO? Используйте библиотеку 'syscall', которая является самой плохой оберткой над POSIX из всех, которые я видел. Нельзя даже получить файловый дескриптор созданного соединения, все приходится делать через 'syscall':

Скрытый текст
fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_DGRAM, 0)
if err != nil {
    rlog.Fatal("failed to create socket", err.Error())
}
rlog.Debug("socket fd is %d\n", fd)

err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1)
if err != nil {
    rlog.Fatal("unable to set IPV6_RECVPKTINFO", err.Error())
}

err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
if err != nil {
    rlog.Fatal("unable to set IPV6_V6ONLY", err.Error())
}

addr := new(syscall.SockaddrInet6)
addr.Port = UDPPort

rlog.Notice("UDP listen port is %d", addr.Port)

err = syscall.Bind(fd, addr)
if err != nil {
    rlog.Fatal("bind error ", err.Error())
}


А еще вы получите море удовольствия, получая и передавая byte[] при вызове 'syscall' функций. Создание и удаление C структур из Go — это просто какой-то заряд позитива.

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

Выводы


Я не могу понять смысл Go. Если мне нужен системный язык, я использую C/D/Rust. Если мне нужен язык с хорошей поддержкой параллелизма, то я использую Erlang или Haskell. Единственное применение Go, которое я вижу — это утилиты командной строки, которые должны быть портабельны и не тянуть за собой зависимости. Я не думаю, что язык хорошо подходит для «долгоживущих» серверных задач. Возможно, он выглядит привлекательно для Ruby/Python/Java разработчиков, откуда, насколько я понимаю, и пришло большинство разработчиков на Go. Я также не исключаю, что Go станет «новой Java», учитывая легкость развертывания и репутацию языка. Если вы ищите более хорошую версию Ruby/Python/Java, возможно, Go вам подойдет — но я бы не рекомендовал останавливать свой поиск на этом языке. Хорошие языки программирования позволяют вам развиваться как программисту. LISP демонстрирует идею «код как данные», «C» обучает работе с компьютером на низком уровне, Ruby показывает работу с сообщениями и анонимными функциями, Erlang рассказывает про параллелизм и отказоустойчивость, Haskell демонстрирует настоящую систему типов и работу без побочных эффектов, Rust позволяет понять как разделять память для параллельно выполняемого кода. Но я не могу сказать, что научился чему-то, используя Go.

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


  1. Zloboglaz
    08.10.2015 10:04
    +4

    Ну а мнение уважаемого переводчика каково?


    1. Dim0FF
      08.10.2015 10:20
      +18

      Я не переводчик, добавлю от себя.

      Попробовал писать на Go несколько домашних поделок, на работе пишу на C#. Если вкратце, я пока так и не смог оценить преимуществ Go, кроме кросплатформенности:

      1. Нет удобных средств для разработчика, IDE со встроенным дебаггером под винду так и не нашёл. Пользуюсь плагином для Idea
      2. Каналы — удобно, но мне они нужны для параллельной обработки массивов данных. В C# это решается проще, Parallel.ForEach и вперёд
      3. Очень непривычно создавать свои ненужные структуры для простой сортировки в Go. И в целом, LINQ для работы с коллекциями в разы удобнее. При работе с Go сильно не хватает
      4. Зачастую, Go кажется слишком низкоуровневым, даже чрезмерно. В идеале, не хотел бы видеть в языке указатели без особой на то причины
      5. Использовал библиотеку написанную на C++ в Go. Не скажу, что очень удобно, а, например, valgrind и вовсе не работает с такими приложениями. Встроенный отладчик память, выделенную в C++ коде, разумеется, не видит. И как отлаживать утечки?


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


      1. QtRoS
        08.10.2015 11:05
        +6

        Аналогично, в основном на работе пишу на C#, тогда как хобби C++\Qt\QML. И те же самые замечания! К LINQ очень быстро привыкаешь, к генерикам, к честным ссылкам, к нормальной работе со строками в конце концов (А то в Go это то ли функции из «bytes», то ли «strings», и непонятно, выстрелит ли это в плане локализации)! Хотя некоторые вещи вроде «go» и «defer» хороши.


        1. RomanPyr
          09.10.2015 14:46

          Dim0FF, QtRoS go-linq пробовали?


          1. lair
            09.10.2015 14:52

             From(students).
             Where(func (s T) (bool, error){
                        return s.(*Student).age >= 20, nil
                }).
            


            Я правильно понимаю, что (а) внутри Where используется делегат и (б) в этом делегате входной параметр приводится к нужному типу?


            1. RomanPyr
              09.10.2015 15:14

              Import your []*Student.
              Find those over 20. Note T is an alias for interface{}. So we make type assertion to our input type.

              Да.


              1. lair
                09.10.2015 15:15

                Мда. Боль и печаль.


                1. Mikanor
                  09.10.2015 17:15

                  Dim0FF RomanPyr lair Ну есть менее печальные варианты , хотя далеко и не идеальные.


                  1. lair
                    09.10.2015 17:16

                    Все равно же делегаты, да?


                    1. Mikanor
                      09.10.2015 18:35

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


                      1. lair
                        09.10.2015 18:36

                        Я не спрашивал, есть ли приведение типов (я вижу, что нет), я говорю, что аргумент Where — делегат. Это ведь так?


                        1. Mikanor
                          09.10.2015 18:53

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


                          1. lair
                            09.10.2015 18:55

                            1. Mikanor
                              09.10.2015 19:03
                              +1

                              Либо я чего-то не понимаю в C#, либо в

                              fruits.AsQueryable().Where(fruit => fruit.Length < 6);
                              


                              fruit => fruit.Length < 6
                              


                              Как раз та самая лямбда-функтор-предикат.


                              1. lair
                                09.10.2015 19:11

                                Зависит от того, что именно вы понимаете под лямбдой/функтором.

                                fruits.AsEnumerable().Where(fruit => fruit.Length < 6);
                                


                                Внутри Where — делегат (анонимная функция), которая будет скомпилирована в исполняемый код вместе со всем остальным кодом вокруг, и выполнена .net-рантаймом в момент итерации.

                                fruits.AsQueryable().Where(fruit => fruit.Length < 6);
                                


                                Внутри Whereвыражение (AST), которое в момент компиляции будет только построено, а вот в рантайме будет проанализировано и выполнено тем способом, который нужен провайдеру, лежащему под fruits. Например, преобразовано в предикат WHERE Length < 6, если провайдер поверх БД. Или в $filter=Length lt 6, если провайдер поверх OData.


                                1. Mikanor
                                  09.10.2015 19:29

                                  Черная магия .Net (:

                                  Не знал про такое — но это свидетельствует скорее о умном компиляторе IL кода, нежели выразительности самого языка. Такие вот «макросы времени исполнения», причем подобная «магия» в коде далеко не всегда оправдана. Честно говоря после войн с Hibernate в яве, я очень осторожно отношусь к «умным выражениям». Да и AOT накладывает ограничения на такие вещи.

                                  Впрочем формально, это действительно вполне обычный предикат-функтор.

                                  П.С. На C# и .Net действительно очень много вкусных и интересных вещей. Но есть и проблемы — эталонная реализация работает только под Windows, поэтому если у вас Linux\*BSD то продвинуть использование шарпа нетривиально. Вторая этот тот факт, что даже если вам удалось продвинуть Mono — ваша реализация будет медленнее работать и может быть подвержена ошибка среды исполнения (тут был цикл статей о нем). Ну и наконец третье, что экосистема шарпа скуднее по сравнению с той же явой.
                                  Во вторых, Go и C# уж совсем разные сегменты рынка занимают. Откуда такой интерес?


                                  1. 0xd34df00d
                                    09.10.2015 19:38

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

                                    Ну, как… Есть у меня самописный недоORM-фреймворк для плюсов, там тоже можно писать вещи типа (простите за куски кутей)
                                    struct Record
                                    {
                                        int m_id;
                                        QDateTime m_timestamp;
                                        QString m_name;
                                    };
                                    // ...
                                    Adapted<Record> queries;
                                    auto records = queries.SelectByFields (_1 <= yesterdayDate && _2 == thisName);
                                    

                                    Разворачивается тоже в какое-то там SQL-выражение, в точке SelectByFields проверяются типы (чтобы ненароком не было выражения со сравнением даты со строкой или int'ом), в рантайме никаких лямбд нет, и так далее.

                                    Адресация, к сожалению, позициональная, именованную с достаточно кратким синтаксисом (чтобы не писать &Record::m_timestamp <= yesterdayDate) я пока не придумал.

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

                                    Ну это так, к выразительности языка.


                                    1. Mikanor
                                      09.10.2015 19:49

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


                                      1. 0xd34df00d
                                        09.10.2015 19:51

                                        Однако же, язык позволяет это выразить. И про это-то и речь!


                                        1. Mikanor
                                          09.10.2015 19:54

                                          В выразительности плюсов никто никогда не сомневался. Вопрос в отладке таких шаблонов (концепты привет) и времени компиляции этого дела.

                                          Из этого кода Boost Spirit вспомнился.


                                          1. 0xd34df00d
                                            09.10.2015 20:04

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

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

                                            Спирит прекрасен, конечно. Хаскелевский parsec/attoparsec-код можно переносить практически не думая.


                                  1. lair
                                    09.10.2015 21:49

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

                                    Не, IL-компилятор здесь вообще ни при чем. Это чисто C#-ный трюк, когда стрелочная запись в зависимости от ожидаемого типа разворачивается либо в анонимный метод, либо в конструктор AST (очень грубо — в LambdaExpression(CompareExpresssion(MemberAccessExpression(ParameterExpression("fruit"),"Length"), LessThan, ConstExpression(6)))). А дальше это AST уже разворачивается исполняемым кодом.

                                    Это не макрос, это совсем другого рода развлечение, очень мощное, по-своему.


          1. Dim0FF
            09.10.2015 15:11

            Спасибо, попробую.


          1. QtRoS
            09.10.2015 15:47
            +1

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


            1. RomanPyr
              10.10.2015 10:54

              вот именно.


      1. Sevlyar
        08.10.2015 12:48
        +3

        Вот смотрите, вы же в C# понимаете отличия struct от object? Где они располагаются, как передаются в качестве параметра? Также, думаю, вам вполне понятны значения модификаторов ref и out? А давайте добавим сюда еще unmanaged код, где можно проводить операции с указателями, stackallock и fixed. Получается что в C# тоже не все просто. Кому-то тоже это может не нравится, а кто-то настолько привык, что даже не замечает. Видимо дело в привычке.


      1. pav5000
        08.10.2015 15:25
        +2

        Каналы — удобно, но мне они нужны для параллельной обработки массивов данных. В C# это решается проще, Parallel.ForEach и вперёд

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


        1. nwalker
          08.10.2015 16:26

          В C# от него защищают async/await, если я все правильно понимаю.


          1. pav5000
            08.10.2015 16:54
            +1

            На C# не пишу, почитал сейчас немного про acyns/await. Насколько успел разобраться, это все же разные подходы.
            Го меня цепляет тем, что можно просто писать plain-код. Тот же async/await будет работать не с любой функцией, она должна это поддерживать, а в го можно любое действие дернуть через go… и оно не будет блокировать остальные потоки выполнения. Т.е., тут не асинхронная модель.
            В совокупности с каналами и особенно с такой фичей как «select» это позволяет очень легко писать сложную логику управления кучей параллельных задач. Но за это мы платим тем, что нужно следить за потокобезопасностью кода, в го у нас нет гарантий, что в середине функции планировщик не переключится на выполнение другой функции.


            1. aspcartman
              08.10.2015 17:38
              +1

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


              1. nwalker
                08.10.2015 17:49
                +1

                > единственный язык, где об этом не нужно думать, это Rust.
                Ну почему же. Есть Erlang, Haskell, Clojure, где об этом точно не надо думать.

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


              1. pav5000
                08.10.2015 18:52
                +1

                Дак вот как раз если горутина слишком долго тупит (это может быть и не системный вызов), то создается еще тред, в который запихиваются другие горутины. Вот тогда мы и получаем возможные проблемы с одновременной записью в map, например, если не учтем этого.
                Вот довольно тупой пример, иллюстрирующий ситуацию. pastebin.com/jkH1Nvp2

                $ go run check.go
                Count 10000; 25.437204715 - 25.484347422
                Count 20000; 25.437177393 - 25.605745478
                End
                

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


                1. nwalker
                  08.10.2015 19:09

                  В Go 1.5 GOMAXPROCS по дефолту ставится равным числу ядер, соответственно, горутины выполняются на нескольких тредах по умолчанию.
                  То есть, ваш пример не демонстрирует ничего, кроме стандартного поведения.


                  1. pav5000
                    08.10.2015 19:15

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


                    1. nwalker
                      08.10.2015 19:53

                      А, ну ок, я не тот мессидж прочитал.

                      BTW, в корректности вот этого тезиса

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

                      я ощутимо сомневаюсь, но не настолько ориентируюсь в планировщике Go, чтобы уверенно отрицать.


                1. aspcartman
                  08.10.2015 21:10

                  Я писал о том, что горутину никто не остановит. В вашем примере ее так же никто не остановил. :) Вы просто запустили две горутины. То, что рядом может выполняться еще горутина и одновременно с нами использовать наши же ресурсы, мне казалось очевидным, о чем я и написал:
                  > Очевидно, что рядом работают в других тредах другие горутины и они могут начать писать туда, куда пишем мы.

                  > Вот тогда мы и получаем возможные проблемы с одновременной записью в map, например, если не учтем этого.
                  Я просто не представляю, как можно не учесть этого. Невнимательность? Да, но а как же иначе? Если язык будет это за нас учитывать (не методами разделения ресурсов аля Rust, а блокировками) то мы, возможно, получим потери в скорости, где нам бы этого не хотелось.


                  1. pav5000
                    09.10.2015 12:04

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


                    1. aspcartman
                      09.10.2015 15:52

                      Да, это конечно так :)


    1. vindi
      08.10.2015 10:28

      Я считаю, что синтаксис и текущая реализация языка программирования — вторичны по отношению к экосистеме и сообществу. Где был javascript? А потом пришли ребята с V8, другие ребята с node.js — и все поменялось в течении пары лет. В дизайне самого языка есть спорные момент: GOROOT, отказ от классов, ручное управление контейнерами, контроль ошибок через возвращаемые значения — но все это сделано с определенными целями — серверная разработка «чтобы не текло и не падало». У меня нет большого практического опыта работы с Go. Что видел — работает быстро, но программисты жалуются что много ручной работы на низком уровне. Время покажет куда он будет развиваться и какое вокруг него сформируется сообщество.


      1. Zloboglaz
        08.10.2015 10:44
        +13

        Не согласен со вторичностью. У разработчиков экосистемы должна быть мотивация её развивать. Чтобы написать node.js надо угорать по языку и мечтать засунуть его всюду.


        1. vindi
          08.10.2015 10:55
          +3

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


      1. erlyvideo
        08.10.2015 11:45
        +12

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


        1. vindi
          08.10.2015 12:44

          В том-то и магия. Ничего по сути не поменялось — а популярность растет. И разработчики думают над способами борьбы с лапшой. Генераторы и async await вот сделали :)


          1. sulnedinfind
            08.10.2015 14:20
            +2

            На самом деле, тут все достаточно просто объяснимо, по крайней мере, постфактум.
            1. Случайно образовался JS в браузере. Пусть достаточно случайное явление, но язык не повернется назвать магическим.
            2. Жесткая конкуренция за растущий пирог случайно привела к тому, что он оказался во всех современных браузерах. Вот это магия, на мой взгляд. Условия рынка сложились достаточно специфические, здесь было вариантов пока еще много. Дальше все строго предсказуемо.
            3. Пирог веба вырос настолько, что браузеры стали использоваться почти всеми цивилизованными людьми чуть ли не каждый день. Оно и понятно: почти мгновенная коммуникация — лучшее изобретение человечества пока что.

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

            Итак, JS везде и не содержит изъянов, делающих его использование невозможным. Чего ждать? Того, что мы сейчас имеем. Пока веб-платформа не упрется в свои фатальные недостатки, она будет расти в сторону еще большего распространения, улучшения скорости работы и развития инструментов разработки. В принципе, после анонса WASM у меня не хватает фантазии, что еще может выйти определяющего.
            Разве что расширение набора инструкций ARM для более эффективной работы виртуальной машины JS, но сначала надо стандартизировать их как следует.

            Так что, думаю, популярность растет просто потому что до сих пор не уперлась в потолок, но не просто так, а потому что JS-интерпретатор — самый распространенный на планете интерпретатор/компилятор.


      1. Belikov
        08.10.2015 14:12
        +3

        Для javascript особо альтернативы не было по-моему. И, увы, никто так и не создал адекватной альтернативы (а еще — лучше замены связки HTML+JS+CSS) и теперь приходится с этим жить.


  1. FreeLancer
    08.10.2015 10:05
    +4

    Хороший перевод. Но я еще ожидал немного Вашего мнения по теме, ибо его несоответствие с мнением автора особенно выделено перед переводом.


    1. vintage
      08.10.2015 10:23
      +39

      Это дисклеймер, чтобы фанаты Go не слили переводчику карму.


      1. vindi
        08.10.2015 10:29
        +10

        В целом да :). На Хабре не все читатели замечают что какая-то статья является переводом и начинает обращаться к переводчику как к автору. А у переводчика нет года практического опыта работы с Go


  1. wiygn
    08.10.2015 12:11
    +8

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


    1. divan0
      08.10.2015 15:28
      +3

      Вы, наверное, догадываетесь, что их там нет намеренно — на практике, по мнению авторов Go, удобство от наличия одноименных функций с разными сигнатурами параметров оказывается сбивающем с толку и запутывающим программистов. Этот вопрос есть в FAQ: golang.org/doc/faq#overloading


      1. wiygn
        08.10.2015 16:51
        +6

        Я умею гуглить, спасибо.

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

        func f(n int := 0) {
            // pass
        }
        

        вместо вот таких не сбивающих с толку программистов решений.

        Особенно после распаковки аргументов в Python (*args, **kwargs), с которым Go часто сравнивают.


        1. divan0
          08.10.2015 17:27
          -2

          Вы совершаете ту же ошибку, что и автор статьи — вы боретесь с языком. Вместо того, чтобы понять, как с его помощью решать проблему, вы пытаетесь понять, как с его помощью сделать так, как я привык в других языках.
          Не нужно делать из variadic parameters попытку симулировать argument overloading. Поймите, что решить задачу (реальную задачу, которую должна решать программа) можно сделать несколько иным способом, кроме как «найти любой ценой способ передавать дефолтные значения». И ценой вашего болезненного раздражительного «отвыкания» будет более ясный и читабельный для других код.


    1. dmbreaker
      13.10.2015 21:59
      +1

      Optional arguments можно реализовать через структуру с инициализацией с именованными полями.


  1. ik62
    08.10.2015 12:23
    +4

    Пишу на питоне когда нет особых требований к скорости исполнения, или на D — когда они есть. Счастлив в обоих случаях. Попытка освоить Go окончилась неудачей по причине отсутствия удовольствния при написании кода.


  1. kolesnevg
    08.10.2015 12:48
    +4

    Пишу на го пол года, до этого где то год назад всё в нем не нравилось (первый подход )), но появился проект в котором нужно было написать сложную бизнес логику, работающую по крайней мере не медленно, и всё это за 4 месяца. На java писать не хотел, на Си не умел, нужен был язык который изучишь быстро, в итоге выбор пал на го, и я не разочарован. Как оказалось на го писать легко и приятно, есть возможности профилирования памяти и процессора, быстрая компиляция, стандартная библиотека которая охватывает почти всё. Среду разработки использую LiteIDE, выглядит страшновато, зато работает быстро и всё что нужно есть. Писать тесты на нем легко и приятно. Ну и то что он активно развивается и имеет отзывчивое сообщество это также на мой взгляд огромный плюс. Пока я работал над проектом они выпустили новую версию GC которая уменьшила задержки до неприлично малых значений. Проект в итогде в продакшене, будем смотреть :)


  1. gentee
    08.10.2015 13:11

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


    1. Olej
      08.10.2015 13:17
      +3

      — не такие большие сообщество и база знаний. Не всегда удается найти готовые решения или ответы.

      Язык программирования Go


  1. Olej
    08.10.2015 13:15
    -40

    перевод статьи опытного разработчика о его опыте практического применения Go.

    Итак, прошел год с тех пор, как я начал использовать Go.


    Н-да… о-о-о-огромный опыт… — 1 год попробовал Go.

    Статья — бред!
    … обиженной девки, надувшей губки: «я такая красивая, а он меня не любит...»


    1. lair
      08.10.2015 13:17
      +9

      А аргументы кроме ad hominem у вас есть?


      1. Olej
        08.10.2015 13:27
        -30

        аргументы в том, что 1 год — это не тот опыт чтобы рот раскрывать?


        1. lair
          08.10.2015 13:32
          +20

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

          Но это все не важно, потому что аргумент «один год — не тот опыт, чтобы» — это и есть аргумент ad hominem. В посте изложены вполне конкретные вещи; спорьте с ними, а не с личностью автора.


          1. Olej
            08.10.2015 13:34
            -4

            Go всего три года — это вполне ощутимый срок.

            не 3, а 6


            1. lair
              08.10.2015 13:37
              +5

              Go 1 вышел в марте 2012. Но даже если шесть — это все равно не меняет остальной аргументации.


    1. Olej
      08.10.2015 14:29
      -32

      Вань! Ты посмотри какие клоуны — рот хоть завязочки пришей!


      Н-да… сильно я разрушил единомыслие и согласие в таком дружном семействе…

      Ты глянь, как по минусам тыцкают! ;-)


    1. sefus
      08.10.2015 14:42
      +4

      По вашему невозможно быть опытным разработчиком без опыта использования Go? И сколько лет должен проработать c Go человек, писавший скажем всю жизнь на Си, чтобы иметь право высказывать свое мнение?


      1. Olej
        08.10.2015 14:49
        -19

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


        … в WEB-программировании? ;-)
        … или в этом… в DevOps-се? ;-) ;-)

        Обсуждать вкус устриц хотелось бы с теми, кто их пробовал.

        (с) М.Жванецкий


        1. iroln
          08.10.2015 15:42
          +3

          или в этом… в DevOps-се? ;-) ;-)
          Вот есть такие ребята. У них всё на Go написано, номады всякие с консулами. Логично, что люди, которые крутятся в этой кухне, пытаются пробовать Go, потому что авторы Go его для этого самого и позиционируют. Системный язык из Go не получился, остался пресловутый web и DevOps. Кто по вашему должен составлять мнение о Go в таком случае, бородатые системные программисты?


          1. divan0
            08.10.2015 17:20
            +3

            Сама фраза «системный язык» имеет различные смыслы. Вот в этом видео Александреску, Матсакиса, Страуструпа и Пайка спрашивают как раз один из вопросов про то, что вы считаете «системным языком».

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


            1. deep_orange
              08.10.2015 17:39

              Кстати в Go реально написать свой аллокатор, с помощью syscall.Mmap и unsafe.Pointer например.


            1. iroln
              08.10.2015 18:17
              -1

              Под «системным языком» можно понимать что угодно, но есть чёткие определения, что такое «прикладное ПО» и «системное ПО». На Go пишут прикладное ПО.

              Я к Go отношусь совершенно нейтрально, язык свою нишу нашёл, и его используют. Я просто не понимаю, что хотел сказать товарищ выше и что он понимает под вкусом устриц. Но ему, наверное, лучше знать с высоты его 40 лет опыта в программировании. :)


              1. Olej
                08.10.2015 18:29
                -5

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


                Нука, нука… Определение — в студию.
                Желательно со ссылкой на авторитетный источник.


                1. iroln
                  08.10.2015 18:33
                  +1

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


                  1. divan0
                    08.10.2015 18:40

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


                    1. iroln
                      08.10.2015 18:52
                      +1

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

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

                      (если что, минус не мой :)


          1. shpaker
            09.10.2015 03:47

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


            1. iroln
              09.10.2015 10:15

              Я же написал, что «системный язык не получился». Эту мысль можно проследить из этого интервью: sourcegraph.com/blog/live/gophercon2015/123645585015

              Q: You mentioned initially having the clear target of being a systems language was important. Is that still the target or has the target changed?

              A: At this point, we really think of Go as a general purpose language. That’s also how people use it. It’s being used across the spectrum, and so that’s how we feel at this point.

              Q: Most users of Go seem to be server-side. Do you think one way to make Go more mainstream is to attract more client-side developers.

              A: The original design was not a standard general purpose language; it was a systems server-side programming language. There’s no ui package, for instance. Now that it’s general purpose, we would really like a ui package, but it’s a lot of work to come up with something that’s cross platform. We could use a lot of experts from the Go community here.
              Создатели языка сами позиционируют его как язык общего назначения, на таких языках обычно не пытаются всерьёз писать драйверы устройств, ядра операционных систем или прошивки для микроконтроллеров, но для написания достаточно низкоуровневого server-side кода он вполне подходит.


      1. 0xd34df00d
        08.10.2015 19:06
        +8

        Должен проработать, пока не полюбит Go, очевидно же.


      1. vadimzz
        13.10.2015 12:35
        +1

        Видимо сей комментатор посчитал, что о языке можно писать лишь после его забвения. Через пять-десять лет мы получим первое поколение опытных АЛГОЛ-программистов и пойдут первые реально хорошие рецензии от опытных разработчиков. К 2030 ждем хороших рецензий на Паскаль, а Java столь молода, что на ней априори пишут лишь юниоры.


  1. lega
    08.10.2015 13:15
    +2

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


    1. hell0w0rd
      08.10.2015 14:43
      +2

      Что такое «сетевые» задачи? Автор поста пишет, что невозможно изменить параметры создания сокета, не используя syscall — это вообще что хрень такая-то? Нафига тогда го, если есть С?
      «Go нужен хорош для сетевого программирования» — мантра которую все повторяют, но видимо уже забыли, что это вообще значит.


      1. vintage
        08.10.2015 16:26

        Очевидно, имеется ввиду не столько «сетевое», сколько «многозадачное с долгими ожиданиями событий для продолжения задач», когда создавать по потоку на каждую задачу — дорого, а делать всё в один поток — медленно. Спасением тут является кооперативная многозадачность (горутины, гринлеты, волокна, легковесные потоки). Многие языки поддерживают её в той или иной мере: Go, NodeJS, Python, D, Rust, C# да в общем любой современный язык.


        1. lega
          08.10.2015 21:53

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

          Многие языки поддерживают её в той или иной мере
          Да, но не так хорошо: NodeJs, Python, D, Rust, C# — там либо async+await либо yield либо callback-hell. Хотя в Python есть gevent, но результат выходит гораздо медленнее чем на Go. Вот Erlang — конкурент, но он мне не очень нравится, может ещё какой-то язык подскажите? Вот Rust был бы не плох, но там нет микро-тредов либо с ними беда. Поэтому для меня решения на Go в качестве «сетевых тулзов» на первом месте, (для веба и тяжелых расчетов он уступает питону, с++ и другим).


          1. vintage
            08.10.2015 23:20
            -1

            Не вижу принципиальной разницы между await+async, go+chan и yield+run. Во всех упомянутых языках кооперативная многозадачность реализуются примерно одинаково.

            Кто бы сомневался, что Python медленнее Go.

            Подсказать могу — D на голову лучше Go. Когда наиграетесь в гопесочнице — добро пожаловать во взрослую джизнь :-)

            Насчёт легковесных потоков в Rust не знаю — он такой же как Go в том смысле, что дизайн крутится вокруг одной единственной фичи, а остальные не реализуются с отпиской «это сложно в реализации поэтому не нужно» (я про исключения, не говоря уж про лисповые условия).


            1. lega
              08.10.2015 23:59

              Не вижу принципиальной разницы между
              Разница есть, в await и yield, ф-ии и библиотеки разделяются на 2 типа, при этом есть проблемы вызова одних типов из других. В go только один тип, поэтому такой проблемы нет и не нужно городить «синтаксический мусор».

              Подсказать могу — D на голову лучше Go.
              В нем тот же yield, а С/С++ он не заменит из-за скорости (а если скорость не нужна тогда можно заюзать хоть питон).

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


              1. vintage
                09.10.2015 00:38

                1. Один тип легко преобразуется в другой.
                2. Далеко не во всех языка есть эта разница.

                1. Там те же волокна, что и в Go и нету костыльных «генераторов».
                2. С чего бы ему быть медленней, если он такой же компилируемый, с опциональным сборщиком мусора и кастомизируемыми аллокаторами памяти?


                1. lega
                  09.10.2015 04:19

                  1. Один тип легко преобразуется в другой.
                  Это не так, попробуйте преобразовать Django в async+await…
                  Какие-то небольшие библиотеки ещё можно преобразовать, но кто потом их будет поддерживать?, и опять же — раздвоение на 2 типа.

                  1. Там те же волокна
                  Вот это уже получше, попробовал — не плохо. Но раздвоение сохраняется, например vibe.d дублирует функционал стандартной библиотеки. Хотя для мелких проектов это не страшно. Надо будет проверить на сколько fiber быстрее/медленнее чем корутины от го.

                  2. С чего бы ему быть медленней,
                  Где то на dlang сайте вычитал — они рекомендуют использовать C если нужна бо'льшая скорость, хотя судя по мелким тестам пользователей он почти не отстает от c/c++.

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


                  1. vintage
                    09.10.2015 11:51
                    +2

                    > Это не так, попробуйте преобразовать Django в async+await…

                    Беглое гугление: http://media.codysoyland.com/pdf/django-on-gevent.pdf

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

                    А он-то тут при чём?

                    > Где то на dlang сайте вычитал — они рекомендуют использовать C если нужна бо'льшая скорость

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

                    > Вообщем, язык интересный, только похоже комьюнити очень маленькое

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


                    1. lega
                      09.10.2015 12:58

                      Беглое гугление
                      Это не то, не микро-треды, я специально написал «async+await», можете не гуглить, за это никто не возьмется.

                      А он-то тут при чём?
                      Я его попробовал в качестве асинхрононнго фреймворка работающего с сетью, дак вот он частично дублирует стандартную либу, про что я и говорил.
                      Если не vibe.d то что использовать для асинхронной работы с сетью?


                      1. vintage
                        09.10.2015 13:46

                        gevent — это те самые «микротреды», о которых шла речь в этой ветке http://www.gevent.org/
                        Что именно вы вкладываете в async-await мне не ведомо.

                        Там есть разные либы, но vibe.d наиболее богатая в этом плане. Это же хорошо, когда у вас есть выбор между несколькими реализациями одного функционала, конкуренция, все дела, разве нет? :-)


                  1. ik62
                    09.10.2015 12:08

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


                  1. lega
                    09.10.2015 20:04

                    Сделал docker для D lang, кто хочет попробовать, запускать так:
                    > docker run -it lega911/dlang
                    # dmd --version


              1. nwalker
                09.10.2015 04:56

                > В go только один тип, поэтому такой проблемы нет и не нужно городить «синтаксический мусор».
                Судя по короткому экскурсу в std.concurrency D — тамошние файберы работают как горутины и Fiber.yield возвращает с любого уровня вложенности вызовов => синтаксический мусор не нужен.


                1. lega
                  09.10.2015 09:32

                  Fiber.yield возвращает с любого уровня вложенности вызовов
                  Кстати в этом есть плюс — мы контролируем когда нам переключится, значит для глобальных/общих объектов в пределах потока локи не нужны в отличие от Го.


                  1. Mikanor
                    09.10.2015 10:07

                    И минус — вы должны четко понимать, кто за кем следует, дабы не допустить блокировки или лишнего ожидания корутин. По сути вы выполняете работу планировщика, только вручную. Более того, ваши коллеги должны быть крайне внимательны при работе с таким кодом — наличие незащищенного shared state не является потокобезопасным, но у вас возможна работа с ним из разных потоков управления, что вызывает вопросы. Лично я такое решение считаю не очень удачным, и крайне не устойчивым — есть большая вероятность отстрела ноги, а ловить такие баги потом крайне неприятно и долго.


                    1. lega
                      09.10.2015 10:22
                      -2

                      И минус — вы должны четко понимать, кто за кем следует
                      Да там полно минусов, поэтому горутины из Го — это значимая фича.


                    1. vintage
                      09.10.2015 12:22

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


                    1. nwalker
                      09.10.2015 16:27

                      Так в Go тоже же самое, просто эти yield-ы спрятаны внутрь операторов работы с каналами и код работы с сетевым i/o. Я же говорю, файберы из D _по сути_ идентичны горутинам.

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


            1. nwalker
              09.10.2015 04:48
              +4

              > D на голову лучше Go
              Не, ну давайте все же будем честны — в плане concurrent рантайма и интеграции его с event loop D до Go еще расти и расти, а кто будет за это платить — неясно.


              1. poxu
                09.10.2015 12:27

                Ну я так понимаю Александреску лично возглавит. С шашкой и на белом коне.


              1. vintage
                09.10.2015 12:29
                +1

                Что же в Go такого удивительного в рантайме и интеграции? Я вижу лишь небольшую разницу в синтаксисе.


                1. nwalker
                  09.10.2015 16:52

                  Ничего удивительного там нет, однако уже есть годный multicore планировщик с work stealing и уже написан неплохой враппер для асинхронного i/o на горутинах.

                  Повторюсь, для Go оно уже есть, для D — непонятно когда будет и будет ли. Вся разница в этом.


                  1. vintage
                    09.10.2015 18:04

                    Давно уже есть: https://gist.github.com/nin-jin/5f6969cb9063b1977769#file-coroutine-d — полный эквивалент горутин. Можно даже синтаксис сделать такой же приятный.
                    В Go варианте вывод какой-то странный — по две итерации каждой горутиной. В D в один поток они просто чередуются (в примере — два).


                    1. nwalker
                      09.10.2015 18:27

                      Не буду спорить, с D я не могу так навскидку разобраться, как там рантайм устроен.


                    1. Mikanor
                      09.10.2015 18:50

                      Честно говоря — тяжело читать, у D нет своего онлайн компилятора?

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

                      Я мельком глянул vibe.core.stream — как я понял, там для неблокирующей операции нужно опросить ОС сколько уже готово, вручную.


                      1. vintage
                        09.10.2015 21:25

                        Внезапно нашёл: http://dpaste.dzfl.pl/

                        Ну, запустите writeln в отдельном потоке.

                        Напишите один раз и вынесите в отдельную обобщённую функцию. А если ещё и опубликуете это модулем в репозитории, но получите плюс к карме. :-)


                    1. lega
                      09.10.2015 19:00

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

                      Разница такая — если одна горутина заблокируется (бесконечный цикл или блокирующее io), то D приложение встанет колом, когда в Го приложение будет работать, Mikanor про это отписался.


                      1. Mikanor
                        09.10.2015 19:16

                        Горутины выполняются параллельно, когда это возможно по мнению планировщика. Отсюда некая недетерминированность I/O. В примере на D sleep выполняются асинхронно, но друг за другом, в том время как в го асинхронно, но параллельно.


                        1. vintage
                          09.10.2015 21:39

                          В примере на D даже глобальные состояния разные. О чём вы?


                      1. vintage
                        09.10.2015 21:31

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

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


                        1. lega
                          11.10.2015 15:10

                          Для интереса сделал набросок балансировщика на dlang + vibe.d, тут не весь функционал и он уже отстает от версии на го на ~15-20% (запускал их в одном потоке + 10 клиентов и 10 ворекров). Может там нужно что-то «подтюнить»?


                          1. vintage
                            11.10.2015 20:03

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


                            1. lega
                              11.10.2015 20:44

                              Ох, как руки дойдут, но обещать не буду. Надо будет упростить скрипты, просто сделать проксирование.


                            1. lega
                              13.10.2015 01:03

                              Начал делать скрипт и с dlang беда какая-то — не возможно получить точное время, нашел рецепт, но он дает расхождения в 10 сек и более. Куда копать?


                              1. vintage
                                13.10.2015 01:50

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


                                1. lega
                                  13.10.2015 15:53

                                  С текущей версий тестов получились такие результаты:

                                  Dlang
                                  
                                  26572
                                  26607
                                  26678
                                  26678
                                  ...
                                  
                                  Go
                                  
                                  33764
                                  33292
                                  33787
                                  33403
                                  ...
                                  

                                  Го быстрее на 26%.


    1. Alesh
      10.10.2015 02:06

      А со скоростью как в этих сетевых задачах?


      1. lega
        10.10.2015 20:11

        У меня есть балансировщик для rpc на python + zeromq и аналогичный на golang, дак вот версия на golang в 3-4 раза производительней (что не удивительно). Кроме этого, не прямые конкурентные решения на C/C++ и Erlang работают медленнее (в разы), хотя в первую очередь это связано с набором фич, и производительность языков тут не сравнить.

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


        1. Scratch
          10.10.2015 20:42

          golang версия тоже через zeromq работает?


          1. lega
            11.10.2015 10:54

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


        1. Alesh
          10.10.2015 21:32

          , дак вот версия на golang в 3-4 раза производительней (что не удивительно)

          Это очень удивительно, ищите ошибки в архитектуре rpc на python + zeromq, такого не может быть.


          1. lega
            11.10.2015 10:58
            +2

            такого не может быть.
            Не может быть что питон медленнее чем golang? Я думаю это очевидно что питон медленнее. Вот код.


            1. Alesh
              11.10.2015 14:23

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

              Готов забрать свои слова назад, если представите адекватные тесты.


              1. lega
                11.10.2015 15:35

                Питон медленнее Го, но не в три-четыре раз
                Да, не в три-четыре, а больше, если сравнивать скорость исполнения питон-байткода.
                Например можете запустить у себя эти 2 цикла, у меня го выполняет в 100 раз быстрее. А в одном реальном проекте был расчет математики и я получил ускорение в 17 раз (и ещё больше при C++).
                А вот исходники тех самых балансировщиков, py и го.

                У Python'а много других достоинств, и Го там рядом не стоит. (Поэтому я на сервер-сайде использую Python, GoLang, C++ совместно для разных задач).


                1. Alesh
                  11.10.2015 15:47

                  Пустые циклы очень хорошо оптимизируются компиляторами, удивляюсь что только в 100 раз :)
                  Математика да, операции с плавающими числами в питоне медленные. Математику в питоне или не считают или считают с использованием специализированных пакетов типа numpy, насколько я знаю.

                  Скажите сколько ядер на машине, где вы сравнивали Go и Python код вышеприведенный?


                  1. lega
                    11.10.2015 16:14

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

                    Математику в питоне или не считают или считают с использованием специализированных пакетов типа numpy, насколько я знаю.
                    Да, питон достаточно быстрый для своих задач за счет того что многие модули написаны на C/C++.

                    Скажите сколько ядер на машине
                    2, но это не имеет значения для данного теста (Во всех тестах я делал с ограничением в одно ядро и без).


                    1. Alesh
                      11.10.2015 16:32
                      -2

                      но это не тот случай

                      Почему, очень похоже именно на этот случай.

                      Во всех тестах я делал с ограничением в одно ядро и без

                      А как вы добились того, что бы Go не форкался автоматом по числу ядер?


                      1. lega
                        11.10.2015 20:18

                        очень похоже именно на этот случай.
                        Если бы цикл вырезался, то приложение не задерживалось бы на 0.4 сек (на 4 сек при увеличении цикла в х10 раз). Для уверенности можете какую-нибудь сложную математику протестировать.

                        что бы Go не форкался автоматом по числу ядер?
                        Это управляется с помощью GOMAXPROCS


                        1. Alesh
                          11.10.2015 20:31

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

                          Как тестите эти два приложения? Есть такая штука github.com/joshmarshall/tornadorpc
                          было бы интересно сделать аналог на нем и посмотреть.


              1. AterCattus
                13.10.2015 13:31

                Погонял у себя примитивный тест lega (но с py версией с «while i < 1000000000»), Python вообще в 184 раза медленнее Go получился…


                1. vintage
                  13.10.2015 13:36

                  А вот это даже как-то странно.


                  1. AterCattus
                    13.10.2015 13:36

                    Я как раз с while и гонял, написал же.


                    1. vintage
                      13.10.2015 13:41

                      Сори, не внимательно прочитал сперва :-)


                      1. AterCattus
                        13.10.2015 13:47

                        Причем, 184 раза это python2.7. На python3.4 разница вобще в 275 раз.


                        1. lega
                          13.10.2015 13:55

                          Можете, ради интереса, попробовать запустить на pypy, — не будет отставать* от golang, если не обгонит.


                          1. AterCattus
                            13.10.2015 14:03

                            pypy медленнее Go в 14 раз…


                            1. lega
                              13.10.2015 14:14

                              Я чуть поправил py код:

                              import time
                              
                              def main():
                                  i = 0
                                  while i < 1000000000:
                                      i += 1
                              
                              start = time.time()
                              main()
                              finish = time.time()
                              print(finish-start)
                              


                              pypy 2.2: 650ms
                              golang: 405ms

                              т.е. pypy получился медленнее на ~40%


                              1. AterCattus
                                13.10.2015 15:01

                                Да, так уже лучше: у меня разница всего в два раза примерно (6.0 против 3.5).


                              1. AterCattus
                                13.10.2015 15:09

                                Добавил в циклы суммирование всех значений i:
                                go — 6сек
                                pypy — 165сек

                                Разница 27 раз. Ну я так не играю)


                                1. lega
                                  13.10.2015 15:47

                                  Возможно из за того, что в этом случае в Го используется long*, когда pypy думает что результат может выйти за 8 байт и переключается на «bigint», а он гораздо медленнее.


                                  1. AterCattus
                                    13.10.2015 16:01

                                    Скорее всего. Если не допустить выхода за пределы разница всего в полтора раза.


                                1. vintage
                                  13.10.2015 19:19

                                  А я добавил D — он в 2 раза быстрее чем Go отработал.

                                  https://gist.github.com/lega911/c4b627c3f17625f05d44#gistcomment-1595006


                                  1. AterCattus
                                    13.10.2015 20:22

                                    dub это уже скомпиленное? Может тогда и Go запускать уже скомпиленное?


                                    1. vintage
                                      13.10.2015 20:25

                                      dub — это пакетный менеджер. В данном случае, он устанавливает зависимости, компилирует, линкует и запускает.


                  1. lega
                    13.10.2015 13:52

                    Да вроде ожидаемо, на сложных задачах разрыв будет меньше (вон брокер сверху всего в 3-4 раза), а если будут сплошные вызовы расширений (numpy или математика на cext), то питон будет даже быстрее. Рассматривайте питон как медленный менеджер над быстрым С-кодом.


                    1. AterCattus
                      13.10.2015 13:59

                      Я сравнивал Go с C++ на несложных алгоритмах на массивах и хешах — по скорости вообще почти нет разницы.
                      Только в случаях совсем уж сложных вещей, которые хотят всяких -O3 -march и т.п.
                      Но Go он для сетевых сервисов все таки, а не считать Пи.

                      «всего в 3-4 раза» больше серверов надо…


                      1. lega
                        13.10.2015 14:18

                        Я на одной реальной, математической задаче получил х2 прирост на С, наверно за счет отсутствия GC и более быстрого map.


                      1. lega
                        13.10.2015 14:20

                        Но Go он для сетевых сервисов все таки, а не считать Пи.
                        Вот с этим я согласен, я с этого тред начал.


  1. oxpa
    08.10.2015 13:19
    +1

    Один в один мои впечатления от ГО. Правда, год писать я на нём не осилил: ощущение борьбы с языком так и не ушло.
    Добавлю так же, что система тэгов для полей структур — тоже очень странная. Выглядит как костылик подставленный опосля («О! А я ещё классную штуку вспомнил»). Соответственно, работа с xml и json заставляет периодически заниматься кодогенерацией, а не динамической генерацией структур.


  1. Olej
    08.10.2015 13:26
    -1

    Каналы и мьютексы МЕДЛЕННЫЕ. Добавление синхронизации через мьютексы на production настолько снизило скорость работы, что лучшим решением стал запуск процесса под daemontools и его перезапуск в случае падения.

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

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


    1. RPG18
      08.10.2015 18:11
      +1

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

      От каких ошибок?


      1. Olej
        08.10.2015 18:30
        -7

        От каких ошибок?

        От ваших ошибок… от кривых рук ;-)


        1. nwalker
          08.10.2015 18:48
          +9

          Ага, конечно. От кривых рук спасают иммутабельность(Haskell, Clojure), share nothing(Erlang) или move semantics(Rust, C++11+).
          В Go есть только соглашения и рекомендации, никакой реальной защиты они не предоставляют.


  1. Olej
    08.10.2015 13:46
    -7

    Я не могу понять смысл Go. Если мне нужен системный язык, я использую C/D/Rust. Если мне нужен язык с хорошей поддержкой параллелизма, то я использую Erlang или Haskell.

    Параллелизм и конкурентность — очень разные вещи, когда вы переходите к SMP и истинной многопроцессорности.
    Параллелизм Erlang или Haskell — кажущийся… логический, если хотите. Эффективное распараллеливание функциональных языков на мультипроцессоры — это больше теоретические изыски, чем практические достижения.
    Главная фишка Go — эффективное использование многопроцессорной среды за счёт лёгких goroutine.
    Опыт (тестовые результаты) показывает, что они быстрее и эффективнее pthread_t языка C и POSIX.
    Не говоря уже про Python и многие другие интерпретируемые языки, где параллельные ветви — это вообще только фикция, модель удобная для формализации и только… а реально они толкутся на одном процессоре только затрудняя выполнение.


    1. RomanArzumanyan
      08.10.2015 16:26
      +6

      Опыт (тестовые результаты) показывает, что они быстрее и эффективнее pthread_t языка C и POSIX.

      Сильное утверждение. Покажите тестовые результаты, пожалуйста.


      1. AterCattus
        08.10.2015 17:02
        +3

        Тесты сравнения горутин и pthread? Ну когда pthread можно будет запустить в одном процессе хотя бы сто тысяч штук, то можно будет сравнивать. А так это все-таки вещи под разные задачи, причем первые «внутри» работают как раз на вторых.


        1. RomanArzumanyan
          08.10.2015 17:05

          Если goroutine работает поверх posix thread, то по каким критетиям вы сравнивали их скорость и эффективность?


          1. AterCattus
            08.10.2015 17:14

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


            1. RomanArzumanyan
              08.10.2015 17:16

              А когда можно будет?


            1. nwalker
              08.10.2015 17:24
              +2

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


      1. poxu
        09.10.2015 12:34

        Посмотрите silver searcher и platinum searcher. Идут ноздря в ноздрю с незначительным перевесом в пользу Go.


        1. RomanArzumanyan
          09.10.2015 12:53

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


          1. poxu
            09.10.2015 13:19

            В readme к platinum searcher есть результаты измерений автором. Простенькие правда, но тем не менее.


    1. erlyvideo
      08.10.2015 17:05
      +12

      вы мягко говоря не в курсе о чём пишете.

      Параллелизм у Erlang основан на акторах, т.е. легковесных именованных процессах, которые обмениваются сообщениями через анонимные каналы.

      У Go это анонимные корутины, общающиеся через именованные каналы.

      Масштабирование эрланга по ядрам — это реальность, причем на много лет более реальная, чем существует Go. Не пишите того, о чём не знаете.


    1. Leeb
      08.10.2015 17:17
      +2

      Что вы понимаете под словом «эффективность»? Вы его употребляете в разных контекстах несколько раз.

      Параллелизм и конкурентность, действительно, вещи не эквивалентные. Erlang, например, про конкуретность (но, вроде как, Go с ним соперничает в этом). И тут же можно сразу поговорить о том, как работает планировщик в Erlang и в Go. У первого он обеспечивает действительно настоящюю вытесняющую многозадачность, чётко отводя процессам лимит времени (если быть совсем точно, то лимит инструкций) и переключая процессы по достижению этого лимита или раньше (но не позже!). Это обеспечивает невероятную плавность планирования (в купе с механизмами work stealing и настраиваемыми стратегиями распределения работы по планировщикам). Да, ценой некоторой потери в производительности (всё-таки виртуальная машина), но ведь тут речь про регулирование конкуретного доступа к ресурсам, а не числодробление. Я когда год назад искал информацию по тому, как именно работает планировщик в Go, не нашёл ничего, кроме упоминания, что переключение осуществляется на вызовах в runtime. Понятно, что на компилируемом в native-код языке трудно сделать честную вытесняющую многозадачность лёгких потоков, но это так же ставит вопрос, где всё-таки concurrency сделана эффективнее.

      Что касается наброса про параллелизм в Haskell, опять же, без определения слова «эффективность» это можно было бы оставить без внимания. Но я просто немного понедоумеваю. Haskell компилируется ровно в тот же самый native-код, что и Go. Треды ОС под планировщиком там ровно такие же. И ровно так же он способен параллельно выполнять код (именно параллельно, до стадии, пока не доделаю, а не пока не попросят освободить ядро). Инструменты для анализа есть. Книга, как делать правильно тоже есть. Где мне этот параллелизм кажется и где отсутствие практических достижений, объясните, пожалуйста?


    1. 0xd34df00d
      08.10.2015 19:10
      +5

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

      Ну, расскажите мне про это, пожалуйста.


  1. SOLON7
    08.10.2015 13:58

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


  1. SOLON7
    08.10.2015 13:59
    -4

    если бы у го был бы хороший mvc фрпймворк или rad платформа все бы сразу побежали бы туда!


    1. Olej
      08.10.2015 14:11
      -8

      это справедливо… но только с точки зрения того, кто ничего кроме Windows не видел ;-)


    1. shpaker
      08.10.2015 16:26

      Так многие и побежали или у вас ест сомнения что гоу вырвался из рамок экзотического языка?


  1. poxu
    08.10.2015 14:49
    +4

    Я либо сражаюсь с ограниченной системой типов с кастами всего в interface{} либо занимаюсь копипастой кода который делает практически одно и то же для разных типов.

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


    1. Olej
      08.10.2015 14:52
      -9

      Я вот пытаюсь понять,

      Ну и как? ;-)

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

      А почему и как (?!) компилируемый в машинный код язык может стать «новой Java», которая требует интерпретации байт-кода в JVM?


      1. poxu
        08.10.2015 15:01
        +1

        Ну и как? ;-)

        И пока не понимаю.
        А почему и как (?!) компилируемый в машинный код язык может стать «новой Java», которая требует интерпретации байт-кода в JVM?

        Ну Go станет новой Java, если там, где раньше использовали Java, начнут использовать Go. Вы думаете, что тот факт, что Go компилируется в машинный язык, этому как-то помешает?


    1. divan0
      08.10.2015 15:40
      +5

      В том-то и дело, что там не нужно делать такие манипуляции. Если человек все кастит в interface{}, значит он пытается перенести абсолютно чужие и крепко засевшие в голове паттерны туда, где они не нужны. Это печально, таких надо отсеивать на первом же собеседовании :)


      1. poxu
        08.10.2015 15:51
        +4

        Я слышал в Go нет дженериков. Как тогда делать контейнеры наподобие листов? Чтобы при вытаскивании не приходилось кастить элементы к нужному типу.


        1. nwalker
          08.10.2015 16:43

          Они нинужны же.


        1. divan0
          08.10.2015 16:47
          -5

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

          Если вам действительно интересна тема, рекомендую вот этот обзор дискуссий о дженериках в Go: docs.google.com/document/d/1vrAy9gMpMoS3uaVphB32uVXX4pi-HnNjkMEgyAHX4N4/edit#heading=h.vuko0u3txoew


          1. nwalker
            08.10.2015 16:51
            +1

            Вот, я же говорил, дженерики нинужны.

            BTW, https://gist.github.com/kachayev/21e7fe149bc5ae0bd878 — «Channels Are Not Enough or Why Pipelining Is Not That Easy», отличное чтиво, как раз по теме.


            1. divan0
              08.10.2015 16:54
              -2

              Качаев — знатный кложурщик и Go-хейтер, да )


              1. divan0
                08.10.2015 17:10
                +2

                Кложурщик — если что, это не ругательство :) Я с ним знаком лично, и человек даже на митапе про Go пытался всем навязывать Clojure и рассказывал, что Go и удобства в конкурентности, это не серебрянная пуля, потому что там нет иммутабельных структур, поэтому переходите на Clojure. :)


          1. poxu
            08.10.2015 17:02
            +2

            Ну давайте хотя бы с контейнерами разберёмся. Как в Go сделать параметризированный контейнер?


            1. divan0
              08.10.2015 17:13
              -2

              Да что ж там разбираться — храните interface{}, как в golang.org/pkg/container/list.

              С дженериками вопрос же о другом.


              1. poxu
                08.10.2015 17:19
                +9

                В том-то и дело, что там не нужно делать такие манипуляции. Если человек все кастит в interface{}, значит он пытается перенести абсолютно чужие и крепко засевшие в голове паттерны туда, где они не нужны. Это печально, таких надо отсеивать на первом же собеседовании :)

                Мне показалось, или за полтора часа язык программирования Go действительно радикально изменился?


                1. divan0
                  08.10.2015 17:41
                  -2

                  А вы не отличаете «постоянно сражаюсь с ограниченной системой типов с кастами всего в interface{}» от «как написать параметризованный контейнер»?

                  Я всё жду, пока вы дойдете до вопроса «А почему авторы Go считают, что в программировании есть что-то иное, кроме параметризованных контейнеров?». Или вы тоже каждый день пишете свои параметризованные контейнеры из года в год?


                  1. poxu
                    08.10.2015 18:11
                    +2

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


                    1. divan0
                      08.10.2015 18:30

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

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

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


                      1. Yuuri
                        08.10.2015 18:41
                        +3

                        «War is peace, generics are slavery, interface{} is bliss.»


                        1. divan0
                          08.10.2015 18:46

                          Ну Оруэлла все читали, давайте что-то по сути.


                          1. AlexanderG
                            08.10.2015 20:07
                            +3

                            Давайте по сути.

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

                            Какие паттерны предлагает Go взамен тех, которые «не хотят пересмотреть»?

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

                            Какой майндсет предлагает Go в таком случае?


                          1. Yuuri
                            08.10.2015 21:46
                            +5

                            Давайте.
                            Я вот на хаскеле пишу. Он ни разу не класс-ориентированный ОО-язык, и набор паттернов в нём тоже совершенно иной. Но параметрический полиморфизм (читайте «генерики») там используется в хвост и гриву, как мощное средство повышения выразительности, производительности и надёжности. Сценарии его использования далеко не ограничиваются контейнерами, полиморфный код можно найти практически в любой библиотеке. И тут вдруг приходят гоферы и говорят, что если достичь просветления, сразу понимаешь, что генерики нинужны; но наглядных примеров, как без них резко всё делается проще, почему-то не показывают. При этом порой забывают, что язык несколько захардкоженных полиморфных типов всё-таки предоставляет (массивы, каналы, что ещё?), только другим их делать не даёт.


                            1. divan0
                              08.10.2015 23:36
                              -3

                              Ну так давайте тогда называть вещи своими именами — вы пишете на языке Х, где жить нельзя без дженериков. Где-то вы читаете, что в другом языке дженериков (в привычном для вас понимании) нет, но при этом Google, Dropbox, CloudFlare и куча других компаний пишут высоконагруженный производительный софт.
                              Вместо того, чтобы задаться вопросом «Ага, видимо в других языках что-то немного иначе, чем в моем любимом Хаскеле, видимо нужно изучить вопрос повнимательнее» вы решаете просто «Язык — отстой, потому что там нет того и в том виде, к чему я привык в Хаскеле».
                              Ну окей, что тут скажешь.


                              1. Yuuri
                                09.10.2015 00:03
                                +3

                                И что? Высоконагруженный производительный софт и на С пишут – и уж явно поболее, чем на го. Только вот сишники не говорят «всё городите свои классы и интерфейсы, вместо того чтобы пересмотреть свой подход и изучить вопрос повнимательнее», кроме совсем старозакалочных. Кстати, многие там без генериков тоже страдают, и костылят что-то на макросах и void*.
                                Ну и не надо мне каких-то левых мнений про отстой приписывать. Насчёт «в других языках что-то немного иначе» – параметрический полиморфизм в том или ином виде есть в подавляющем большинстве современных статических языков. Хаскель я привёл лишь в качестве примера, отличного от ООП-мейнстрима. Так что в данном вопросе это не он, это го такой особенный.


                                1. divan0
                                  09.10.2015 01:21
                                  -3

                                  Высоконагруженный производительный софт и на С пишут

                                  Да на всем пишут. Вопрос — какой ценой.

                                  параметрический полиморфизм в том или ином виде есть в подавляющем большинстве современных статических языков

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

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


                                  1. 0xd34df00d
                                    09.10.2015 01:23

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

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


                                  1. lair
                                    09.10.2015 01:34

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

                                    А в статье, надо отметить, и написано совершенно честно: «поговорим о том, почему я не считаю Go полезным инструментом».

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

                                    If you’re not interested in my opinion, or are ending up here via some Go news aggregator or something and want to show me the error of my ways, you probably needn’t bother.


                                    Человек предлагает свое мнение, и предлагает он его по внешней просьбе.


                                    1. vindi
                                      09.10.2015 08:36
                                      +3

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


                                      1. lair
                                        09.10.2015 11:19
                                        +2

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


                                  1. Yuuri
                                    09.10.2015 02:43

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

                                    Да на всем пишут. Вопрос — какой ценой.

                                    Ну а я о чём. И без генериков пишут, и на го пишут. Только какой ценой? ;)


                                    1. divan0
                                      09.10.2015 02:45
                                      -1

                                      Ну а я о чём. И без генериков пишут, и на го пишут. Только какой ценой? ;)

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


                      1. poxu
                        09.10.2015 09:57
                        +2

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

                        Мне интересно как живётся без дженериков. Самое простое применение дженериков — параметризированные контейнеры. Интересно как с этим в Go.

                        А вы в ответ — храните interface{}. Я так понимаю это как в Java хранить Object. То есть ответ такой, что сделать параметризированный контейнер невозможно.

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

                        Я правильно понял?


                        1. Mikanor
                          09.10.2015 10:17
                          -1

                          Если мы так сильно требуем жесткую параметризацию, при этом у нас нет общего интерфейса(в случае го это означает, что у хранимых структур нету ни одного одинакового метода) для хранимых типов — то почему не использовать go generate на готовом шаблоне?


                          1. poxu
                            09.10.2015 10:44
                            +1

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


                            1. Slasyz
                              09.10.2015 11:24

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


                              1. poxu
                                09.10.2015 11:34
                                +4

                                Усложняют язык, или усложняют разработку компилятора?


                        1. divan0
                          09.10.2015 17:44
                          -1

                          Я правильно понял?

                          Со скрипом, да.

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

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

                          Мне интересно как живётся без дженериков.

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

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

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

                          docs.google.com/document/d/1vrAy9gMpMoS3uaVphB32uVXX4pi-HnNjkMEgyAHX4N4/edit#

                          И мой вопрос — как часто вы пишете свои типизированные контейнеры? Можно в % от основного кода, или сколько раз в день, или сколько типизированных контейнеров вы написали в прошлом месяце?


                          1. lair
                            09.10.2015 17:55
                            +2

                            И мой вопрос — как часто вы пишете свои типизированные контейнеры? Можно в % от основного кода, или сколько раз в день, или сколько типизированных контейнеров вы написали в прошлом месяце?

                            Это неправильная постановка вопроса. Правильная — «как часто вы пользуетесь параметризованным контейнером». Ответ — часто. Я вот — практически ежедневно.


                          1. poxu
                            09.10.2015 18:22

                            Поглядел документ про generics approaches в go

                            Pros

                            standardized complex types

                            В джаве куча стандартных параметризированных типо, они ведут себя предельно предсказуемо. И наличие дженериков этому не помешало.
                            smaller language/compiler (if there aren’t many generic types)

                            И таки да, это правда. Только вы почему-то утверждаете, что дело не в этом.
                            language constructs can be optimized for these types

                            Преимущество сомнительное, в С++ при необходимости оптимизации просто определяют специализацию шаблона.
                            the code is more concrete (because users can build less abstractions)

                            Преимущество опять же сомнительное, не хочешь абстракций — не делай их.


                            1. poxu
                              09.10.2015 18:31

                              Прошу прощения, половина поста случайно отправилась.

                              Cons

                              each generic type adds complication to compiler

                              Таки усложняет компилятор, если волшебных generic типов много

                              each generic type makes the language more complicated

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

                              the generic types must perform well in lots of cases

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

                              the language is less flexible (because users can build less abstractions)

                              Ну понятно в общем, чего коментировать.


                            1. vintage
                              09.10.2015 18:48
                              +1

                              Ну а я, давайте, Cons прокомментирую :-)

                              > each generic type adds complication to compiler

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

                              > each generic type makes the language more complicated

                              Ровно в той мере, что появляются плейсхолдеры для конкретных типов — не ахти какая сложность.

                              > the generic types must perform well in lots of cases

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

                              > the language is less flexible (because users can build less abstractions)

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


                              1. Mikanor
                                09.10.2015 19:01

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


                                1. divan0
                                  10.10.2015 00:04
                                  +2

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

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

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

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


                                  1. lair
                                    10.10.2015 01:30

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

                                    Если бы это было так, то не было бы архитекторов, а были бы сплошные программисты cum architect. Но нет.


                                  1. 0xd34df00d
                                    10.10.2015 01:38
                                    +1

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

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

                                    Тогда вопрос выбора языка не вызывает таких приступов хейтерства и такой неадекватности в суждениях.

                                    Не подменяйте понятий, пожалуйста. «Приступы хейтерства» вызывает не вопрос выбора языка, а конкретно вопрос выбора Go. Интересно, почему?

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

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

                                    Удобно!

                                    Подобно игре в шахматы с голубем с известным исходом.


                                  1. poxu
                                    10.10.2015 12:18
                                    +1

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

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

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

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

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


                                1. poxu
                                  10.10.2015 11:34

                                  vintage да, осуждает.
                                  Что касается меня, то посмотрите внимательнее, что я писал про Cons. Там в основном молчанивое согласие.
                                  А вот Pros, да, сомнительные.

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


                                1. vintage
                                  10.10.2015 12:39

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


                            1. Mikanor
                              09.10.2015 18:55

                              Преимущество сомнительное, в С++ при необходимости оптимизации просто определяют специализацию шаблона.

                              В С++ с этим связан SFINAE которой уж точно не ускоряет скорость компиляции.


          1. AlexanderG
            08.10.2015 20:06

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

            Если человек все кастит в interface{}, значит он пытается перенести абсолютно чужие и крепко засевшие в голове паттерны туда, где они не нужны.

            Пожалуйста, каков тогда «правильный» способ это сделать в Go?


            1. divan0
              08.10.2015 23:49
              -1

              Вы так и не ответили на вопрос

              Ответил выше.

              Пожалуйста, каков тогда «правильный» способ это сделать в Go?

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


              1. Yuuri
                09.10.2015 00:16

                Если человек все кастит в interface{}, значит он пытается перенести абсолютно чужие и крепко засевшие в голове паттерны туда, где они не нужны.

                Да что ж там разбираться — храните interface{}, как в golang.org/pkg/container/list.

                Таки в каких случаях пихать можно, а в каких – чужие паттерны?


                1. divan0
                  09.10.2015 00:43
                  -3

                  Таки в каких случаях пихать можно, а в каких – чужие паттерны?

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


              1. vintage
                09.10.2015 00:30

                Как следующий код переписать на Go? https://gist.github.com/nin-jin/5f6969cb9063b1977769#file-sorting-d


                1. divan0
                  09.10.2015 00:40
                  +2

                  1. vintage
                    09.10.2015 00:56
                    +4

                    Ну то есть 25% кода — копипаста. На каждую комбинацию «тип элемента» + «вид сортировки» требуется повторять по 9 строчек однотипного кода. И, кстати, вы потеряли юнит тесты.


                    1. divan0
                      09.10.2015 01:14

                      На каждую комбинацию «тип элемента» + «вид сортировки» требуется повторять по 9 строчек однотипного кода.

                      В вашем примере на D то же самое по сути, только более ограничено.


                      1. vintage
                        09.10.2015 01:29
                        +1

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


                        1. divan0
                          09.10.2015 01:46

                          Нет, вы все равно определяете функцию Less() для каждой комбинации «тип элемента» + «вид сортировки». Swap() и Len() всегда одинаковы для слайсов(массивов), но в более сложных вариациях тоже может понадобится переопределение и вам тоже придется это делать.

                          Ну и если вы три строчки экономии в данном конкретном примере готовы променять на все остальные преимущества, которые дает Go, то мне понятно, почему D так и не нашел свою нишу.


                          1. vintage
                            09.10.2015 01:57
                            +1

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

                            «Все остальные» — это какие? Именно преимущества перед D, а не архаичным С, с которым Go обычно сравнивают.


              1. AlexanderG
                09.10.2015 00:47
                +1

                Не понимаю. Конкретная проблема — реализация типизированных контейнеров. Вместо конкретного ответа вы уходите в общие рассуждения о «засевших в головах паттернах». Так как контейнер-то сделать?


                1. 0xd34df00d
                  09.10.2015 00:51
                  +2

                  Просто контейнеры — это тоже засевший в головах паттерн.


                1. divan0
                  09.10.2015 00:52
                  -1

                  Конкретная проблема — реализация типизированных контейнеров

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

                  Так как контейнер-то сделать?

                  Ответил выше. В третий раз буду игнорировать вопрос.


      1. 0xd34df00d
        08.10.2015 19:16
        +5

        Паттерны — это, конечно, хорошо. Ещё лучше вспоминать про их существование.

        Однако, было бы ещё неплохо понимать, какую общую идею несёт язык. Ну вот плюсы всякие там — это прямой доступ к железу и шаблонное безумство. Хаскель — иммутабельность, чистота, система типов. Agda — это хаскель с зависимыми типами. Coq — это прувер. Эрланг — хитрое и удобное взаимодействие между потоками. Rust — явно выраженная концепция владения и его передачи.

        А в Go что? Какая идея-то? Зачем мне его учить? Чем его изучение по вечерам и выходным сделает меня лучше?


        1. divan0
          08.10.2015 19:52
          -6

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

          То что вы описали — это не «общая идея», а «наиболее отличительная черта». У Go есть три таких черты:
          — уход от концепции управления потоками
          — convention over configuration — единый формат (go fmt) и тд
          — объекты, определяемые поведением (interfaces)

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


          1. 0xd34df00d
            08.10.2015 20:34
            +4

            уход от концепции управления потоками

            Написал я себе в хаскеле parMap rdeepseq вместо map и точно так же ушёл. Или в даже плюсах напихал тасков в boost.asio и ушёл.

            В эрланге, говорят, давно ушли вообще.

            convention over configuration — единый формат (go fmt) и тд

            Это, признаться, идея, весьма сомнительно подходящая на роль основной задающей.

            объекты, определяемые поведением

            Ad-hoc polymorphism что ли? Не ново. При определённой широте взглядов можно сюда хоть duck typing из питона или плюсовых шаблонов, хоть всякие ML'ные семейства систем типов приписать.

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

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

            Это сложно понять, пока не пишешь на Go, соглашусь.

            Вот в этом, вероятно, и проблема.


            1. divan0
              09.10.2015 00:06
              +1

              Вот в этом, вероятно, и проблема.

              Рад, что мы пришли к консенсусу. Собеседники, которые не могут что-то понять, пока не попробуют, а не пробуют, потому что не могут понять, это да, проблема.

              Ad-hoc polymorphism что ли? Не ново. При определённой широте взглядов можно сюда хоть duck typing из питона или плюсовых шаблонов, хоть всякие ML'ные семейства систем типов приписать.

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


              1. 0xd34df00d
                09.10.2015 00:51
                +2

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

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

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

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

                Я же ищу ответ на вопрос, который я уже написал комментарием ранее, на всякий случай процитирую: «Зачем мне его учить? Чем его изучение по вечерам и выходным сделает меня лучше?»

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


                1. divan0
                  09.10.2015 01:03

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


                  1. 0xd34df00d
                    09.10.2015 01:12
                    +1

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

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

                    Уж простите за отнимание времени, но ИМХО вполне нормальная реакция на язык с такой кучей шумихи вокруг него. Гугл! Докер! Легко писать новый код! Вы просто ничего не понимаете, и у вас старые заскорузлые паттерны!

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


                    1. divan0
                      09.10.2015 02:48
                      -1

                      Я вам так скажу — то время, которое вы потратили на написание комментариев тут, достаточно, чтобы освоиться с Go и написать какой-нибудь реальный код. Как только для вас процесс написания кода станет важнее процесса «освоения языков», вы поймете всё, о чём я писал выше :)


                      1. poxu
                        09.10.2015 11:38
                        +3

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


                      1. 0xd34df00d
                        09.10.2015 13:14

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

                        Более того, этого времени было бы достаточно, чтобы и освоить какой-нибудь экзотический ассемблер и написать и на нём какой-нибудь реальный код (ну, длину строки там посчитать, не знаю, или даже факториал). Но зачем?

                        Процесс написания кода как процесс тыканья пальцами в клавиатуру меня довольно давно не привлекает. Интереснее решать при этом ещё какие-то задачи.


                        1. poxu
                          09.10.2015 16:00
                          +1

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

                          Ну и не забываем о беспроблемной сборке под все поддерживаемые платформы. Всё, как советуют гуру CI.

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


                          1. 0xd34df00d
                            09.10.2015 16:10
                            +2

                            Я сейчас включу «уже есть в $langname», что может не понравиться знатокам Go, прошу уж простить.

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

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

                            Ну и не забываем о беспроблемной сборке под все поддерживаемые платформы. Всё, как советуют гуру CI.

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

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

                            Вот тут я ничего, к сожалению, сказать не могу, не большой специалист в сборке мусора :(


                            1. poxu
                              09.10.2015 16:44

                              Мой опыт общения с хаскелем, увы, ограничен слепой модификацией pandoc, с целью генерации хабраразметки из маркдауна. Хотя, говорят, вещь хорошая. Можно там пересобрать весь проект и прогнать тесты секунд за 10? Хотя понимаю конечно — зависит от величины проекта. Но хотя бы в субъективно небольшом проекте можно такое? REPL всё-таки не замена TDD.

                              Вообще в go каждый раз пересобирается всё, что нужно из стандартной библиотеки и все зависимости. То есть решена проблема долгой сборки и тема с необходимостью заранее собирать статистические библиотеки для C++. Ну и jar в java. Если компилятор для платформы есть — программа на Go соберётся без проблем и без разных ключей для разных платформ. Плюс получается один большой бинарник, а не набор файлов.

                              Сборщик мусора в java может остановить всё на неопределённый период времени и это больно. В Go такой пробемы нет — gc отработает за 10 ms.


                              1. 0xd34df00d
                                09.10.2015 16:49

                                Можно там пересобрать весь проект и прогнать тесты секунд за 10? Хотя понимаю конечно — зависит от величины проекта. Но хотя бы в субъективно небольшом проекте можно такое? REPL всё-таки не замена TDD.

                                Верно, зависит от величины проекта. За десяток секунд ИМХО вполне можно.

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

                                В Go такой пробемы нет — gc отработает за 10 ms.

                                Магия какая-то. А время следующего запуска сборщика как-то определено или нет?


                                1. poxu
                                  09.10.2015 17:04

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


                                  1. 0xd34df00d
                                    09.10.2015 17:19

                                    Тогда сценарий «gc работает 10 мс, потом 1 мс — пользовательский код, и так 10 раз» вполне легитимен и даже соответствует претензиям на детерминированность времени работы GC. Только чем оно принципиально лучше одной не очень детерминированной 100 мс задержки, не очень понятно (особенно если пользовательская задача занимает больше 10 мс при данных цифрах, которые сугубо иллюстративны, и вы можете подобрать соотношение gc/work на ваш вкус).


                                  1. Mikanor
                                    09.10.2015 17:25

                                    Ну тут вы не совсем правы — наложено лишь ограничение — не более 10ms каждые 50ms на GC. Поэтому если не справился за один подход — значит будет пытаться в следующие 50ms. И так далее…


                                    1. 0xd34df00d
                                      09.10.2015 17:37

                                      Это хорошо.

                                      А есть ли тогда какие-то оценки-ограничения на потребляемую память?


                                      1. poxu
                                        09.10.2015 17:43

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


                                        1. divan0
                                          09.10.2015 17:50

                                          Этот ползунок был с самого начала, GOGC называется. Он определяет порог роста хипа, после которого нужно запускать GC. GOGC=100 (по умолчанию) означает, что если размер кучи на 100% больше (тоесть, вдвое) количества занятой реальной памяти, то нужно запускать GC.
                                          Вот тут подробнее есть: habrahabr.ru/post/265833 и тут m0sth8.github.io/runtime-1/#1
                                          Ну и еще в подкасте golangshow.com периодически внутренности обсуждаются.


                                          1. 0xd34df00d
                                            09.10.2015 18:27

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

                                            Я даже слайды по второй ссылке в конце первой ссылки посмотрел (смищнявые слайды, ничего не скажешь, шутка про eye tracker удалась!), но там весьма общие слова, как всё будет хорошо.

                                            По второй ссылке в вашем комментарии только сиротливо висит «correctness proofs in literature (see me)» внизу 52-го слайда, но это не очень хорошая и вежливая отсылка на вопрос о конкретной задаче.


                                      1. Mikanor
                                        09.10.2015 17:58

                                        удалено, наверху верно ответили


  1. deep_orange
    08.10.2015 16:24
    +6

    Большинство критиков Go пишут, что-то вроде «тут нет фишки, которая нравилась мне в языке X». Я не понимаю. Есть тур. Есть документация по языку. Куча статей best practice и how to use. Нет так нет. И не надо пытаться писать на Go так как писал на языке X.

    Для того же бенчмарка количество иттераций настраивается ручками. Для разных задач разное число, зачем мне для простенькой задачки гонять проц 10 минут. Для чего нужен и как работает interface{} вообще мало кто из критиков (и не только) понимает.

    Про «сверхвысокую» информативность сообщений об ошибках я согласен. Проще в сорцах на github найти, чем в гугл. GCC со своим C в сравнении просто великолепен (в купе с google и SO).

    Для низкого уровня Go подходит плохо. Тому цена кроссплатформенность. Сейчас есть подвижки в эту сторону и пакет syscall более не развивается, вместо него лепят отдельно для каждой системы по пакету вот. Должно быть проще в перспективе. Я думаю что Go лучше сравнивать с Java. Если смотреть в веб — то c Ruby (revel+gorm хоть и отдалёно, но напоминают rails c его activerecord).


    1. deep_orange
      08.10.2015 16:39
      +4

      Да и кстати append всегда создаёт новый слайс. Но важно помнить, что часть одного слайса может быть так же частью другого. Если что есть copy. Да эта тема довольно проста и хорошо освещена, по крайней мере в англоязычном мире и не нужно хорошо знать язык, чтобы до неё дойти. Чувак просто не разобрался. Вот и всё.

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


  1. shpaker
    08.10.2015 16:32
    +1

    А мне доставляет удовольствие гоу хотя, как и автор статьи, периодически недоумеваю от местных указателей, и строк с []byte.


    1. divan0
      08.10.2015 16:38
      +1

      Зачем недоумевать, если можно на сайте Go прочитать про поинтеры: golang.org/doc/effective_go.html#pointers_vs_values


      1. shpaker
        08.10.2015 18:03
        +1

        Да как бы и так ничего нового, но все же… Я ж не программист, а маску на стройке нашёл.


  1. divan0
    08.10.2015 16:33
    +11

    Повеселила статья, которую правильно бы было назвать «Год с моей последней блогозаписи в Go».

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

    Собственно, автор всё сам объяснил вот тут:

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

    Каналы и мьютексы МЕДЛЕННЫЕ. Добавление синхронизации через мьютексы на production настолько снизило скорость работы, что лучшим решением стал запуск процесса под daemontools и его перезапуск в случае падения.
    Разумеется, когда каждый может написать за минуту бенчмарк и посмотреть реальную производительность мьютексов и каналов, цифры в посте отсутствуют, как класс. Расчет на то, что читатель все примет на веру и скажет — «да, действительно, раз даже капсом написано, то и вправду медленные».

    Строго говоря, утилита для анализа покрытия кода в Go — это хак.

    Не важно, что coverage report идет в Go из коробки, не важно, что дает возможность с нулевым усилием получить coverage percentage, не важно, что веб-страничка репорта дает возможность бегать по файлам и смотреть визуально, какие функции и как покрыты. Этот мелкий практический аспект не важен, ведь главное — что это можно назвать «хаком» и, неверно поняв, как работать с инструментом, написать «критику».

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

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

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

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

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

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

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

    Хороший вброс, одобряю.


    1. Scratch
      08.10.2015 17:21

      А можете пояснить начинающему, почему вообще происходит кастинг в interface{}? Зачем он нужен?



      1. divan0
        08.10.2015 17:37
        +4

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

        Но людям, которые привыкли к дженерикам, сложно поменять подход к проблеме, который, как известно, формируется инструментарием. Они пытаются в Go все засовывать в некое подобие дженерного типа (interface{} — пустой интерфейс, которому, по логике вещей, удовлетворяют все остальные типы-структуры), и работать с ними. Это очень печальный признак, потому что на Go так не пишут и так даже думают о проблеме.

        Вот одна из статей, объясняющая интерфейсы: go-book.appspot.com/interfaces.html


        1. poxu
          08.10.2015 18:19
          +1

          В Go несколько уникальный подход — есть структуры и интерфейсы, первые определяют данные, вторые — поведение.

          Я вот недавно читал книгу Чистый код, Роберта Мартина. Примеры чистого кода приведены на Джаве. И там то же самое, только интерфейсы заменены объектами. А ещё уникальным подходом это никто не называет.


          1. divan0
            08.10.2015 18:35

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


          1. Mikanor
            09.10.2015 09:46
            +3

            Вы правы, но лишь частично — в отличии от Go, в Java одинаковый набор методов у двух интерфейсов не означает типовое равенство этих интерфейсов. Как и в большинстве ОО языков. Таким образом, если другой человек написал класс и интерфейс к нему, то вам придется либо использовать его интерфейс в своем коде выполняющим с его объектами работу. Это удобно, но до тех пор, пока вы вдруг не понимаете, что у вас есть объекты обладающие похожими методами и код можно вынести в один. Дальше вариантов два — либо вы говорите, что ваши классы реализуют еще и этот «чужой» интерфейс, попутно реализуя заглушками возможные дополнительные методы (что скажем так, не красиво) — либо окольными путями приводите чужой код уже к вашему интерфейсу — например через делегирование.

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

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


            1. poxu
              09.10.2015 10:07
              +1

              Спасибо за пояснение.

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


              1. Optik
                09.10.2015 11:03

                Больше похоже на упрощенные (раз там отсутствует иерархия) примеси (mixins).


              1. vintage
                09.10.2015 12:58

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


              1. 0xd34df00d
                09.10.2015 13:16

                В С++ вроде что-то такое собираются ввести.

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

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


                1. poxu
                  09.10.2015 13:23

                  Я про этот proposal


                  1. 0xd34df00d
                    09.10.2015 13:25

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


                    1. poxu
                      09.10.2015 13:30

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


                      1. 0xd34df00d
                        09.10.2015 13:33

                        Да, в том числе, этакие extension methods.


                        1. Mikanor
                          09.10.2015 17:28

                          UCS очень спорная фича — там даже в коммитете не все до конца убеждены. Это введет кучу новых правил на resolution. Но после истории с концептами, с Бьёрном предпочитают соглашаться.


                          1. poxu
                            09.10.2015 17:31
                            +1

                            А что за история с концептами?


                          1. 0xd34df00d
                            09.10.2015 17:39

                            Не уверен насчёт кучи новых правил, в конце концов, запись x.f() означает поиск f(x) (и, согласно одному из двух пропозалов, обратно, ЕМНИП). Что это может действительно снизить, будучи применяемым бездумно — это читабельность кода. Ну так простите, C++ такой, это норма!


                            1. Mikanor
                              09.10.2015 19:42

                              UCS вносит интересные вещи в resolution методов. Хорошее обсуждение тут и было еще одно где-то. Например случай с вызовом swap внутри класса, который и сейчас не очень тривиальный.

                              Касаемо концептов — изначально предлагался еще и другой вариант, т.к. за концепты билось несколько предложений. Тот был более выразительный, но и более сложный к реализации. И в связи с тем, что с ним возились уже несколько лет к C++0x(будущий C++11) стандарту, Бьёрн раскритиковал и порезал эту идею — вынеся части в Concepts Lite(теперь уже просто Concepts) и сказав, что хватит. Части которого, впрочем, содержали скорее его идеи. Было ли это оправдано, или нет — большой вопрос, т.к. даже облегченные концепты не смогли привезти к 14ому стандарту.


                              1. 0xd34df00d
                                09.10.2015 19:44

                                А что со свопом внутри классов? Надо просто объявлять swap в том же неймспейсе, что и класс, а в точках использования писать

                                using std::swap;
                                swap(a, b);
                                

                                чтобы ADL подключился. И волосы будут мягкими и шелковистыми.

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


                                1. Mikanor
                                  09.10.2015 19:52

                                  А что будет, если у нас есть одновременно реализация swap как метода и swap как свободной функции? При этом на входе одни и те же аргументы (this неявно же передается).


                                  1. 0xd34df00d
                                    09.10.2015 20:00

                                    Должно выбраться что-то одно из них, разве нет? Надо смотреть в пропозал, какие там приоритеты, я не помню точно.


                1. Mikanor
                  09.10.2015 17:40

                  Именно — и то и другое накладывает список требований к поведению передаваемого объекта, но не требуя изменения его структуры. Побочным явлением того, что у Go это реализовано в рантайме является информация о типах во время исполнения и полноценный reflection с (почти) всеми фичами. Ну и минус это некая потеря в скорости исполнения, конечно — близкая к vtable. Такой подход не соответствует плюсам, где ты не платишь за то, что ты не используешь. С другой стороны споры вокруг RTTI все еще не прекращаются.


                  1. 0xd34df00d
                    09.10.2015 17:42
                    +1

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

                    Впрочем, значительная часть этого желания возникает от использования enable_if и прочего метапрограммирования со SFINAE.


                    1. Mikanor
                      09.10.2015 18:16

                      В смысле будут ли расширятся интерфейсы? Никто не знает — все возможно, определенные изменения в язык внести были предложения, но 1) пока нет достаточного мотивации со стороны сообщества и ядра 2) жесткая обратная совместимость в пределах 1ой версии 3) цель на простоту языка — а каждая новая фича это увеличение сложности.
                      Сейчас усилия сосредоточены на оптимизации итогового кода и поддержки сторонних платформ. Ядро сообщество сосредоточено на улучшении GC и Escape Analysis. Впрочем с учетом итерации — релиз раз в 6 месяцев — что будет через пару лет пока предсказать сложно. У плюсов например итерация 3 года.


      1. nwalker
        08.10.2015 17:55
        +8

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


        1. Mikanor
          09.10.2015 09:54

          void* в С не содержит информацию о типе переменной лежащей внутри, в отличии от Go, поэтому гарантированно узнать, что же там лежит внутри можно только если у вас любая структура содержит вспомогательное поле о ее типе
          interface{} это не спец тип — это обычный интерфейс, у которого нет требований по методам, а значит ему удовлетворяет любой тип. Сама по себе любая переменная интерфейсного типа в Го, это всегда пара указателей — один на саму переменную в памяти (далеко не всегда в хипе) а другая указатель на ее настоящий тип.


          1. Optik
            09.10.2015 11:17

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


            1. Mikanor
              09.10.2015 18:08

              Никто не говорил, что это красивое или хорошее решение. Насчет кодогенерации — пример (именно пример использования) от создателей.


    1. asm0dey
      08.10.2015 21:47

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


      1. divan0
        08.10.2015 23:58

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

        Метод? Вам достаточно в цикле переложить:
        for key, value := range map1 {
            map2[key] = value
        }
        

        Если сильно часто делаете подобное (интересно, зачем?), то можете создать функцию-обертку, да.


        1. 0xd34df00d
          09.10.2015 00:44

          Я, конечно, не знаю, что за pushAll и что внутри Map там (хэшмапа или дерево), но для дерева, например, ваш код имеет сложность O(n logn), тогда как если вспомнить, что ключи сортированные, можно эффективно строить мапу за O(n).

          logn — это мелочь, конечно, по сравнению с n, но всё-таки.


          1. divan0
            09.10.2015 02:34

            Это даже преждевременной оптимизацией не назовешь, настолько это неуместно )


            1. 0xd34df00d
              09.10.2015 13:22
              -1

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

              Тут был какой-то едкий комментарий про типичную разработку на Go, но я его вовремя стёр.


          1. Mikanor
            09.10.2015 05:43
            +1

            Go использует hashmap в качестве реализации map. Чуть подробнее вот здесь. Знание Go не обязательно, разработчики компилятора много усилий вкладывают в комментирование кода и обоснование тех или иных решений.

            А вот здесь есть более подробное обсуждение где рассказывается, что может быть от O(1) до O(N log N) — зависит от сложности ключа и количества его возможных вариантов (конечное\бесконечное).


            1. 0xd34df00d
              09.10.2015 13:24
              -1

              best case O(N log N) on average (since the keys have to be at least O(log N) in size on average to construct a hash table with N entries

              Это очень, как по мне, странное утверждение.

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


        1. asm0dey
          09.10.2015 07:23
          -1

          Ну вот есть у меня задача объединения двух Map'ов. Они бывают разных типов. Прошу прощения, метод в Java называется putAll, а не pushAll, конечно же. Но в джаве-то есть дженерики и этот метод принимает на вход другой Map только правильных типов, а в го так аписать нельзя. В каждом месте мне придётся городить вот этот вот цикл. Именно потому что функцию обёртку я написать не могу, потому что Map'ы разных типов у меня.


    1. defuz
      09.10.2015 09:46

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


      1. divan0
        10.10.2015 00:08

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

        Ну, это звучало в контексте Go, а не любых языков :)


  1. Mikanor
    09.10.2015 06:48
    +15

    Да… такая оживленность была только в комментариях к Оберону.

    Насчет generic\templates все очень просто — разработчики компилятора уже давно сами сказали, что не знают как его правильно сделать. Потому, что сделав такую вещь один раз — потом от нее уже не откажешься.
    Вариант C++ — полноценные шаблоны — не устраивает потерей скорости компиляции (которая является фичей Go) и существенным ростом сложности компилятора. D использует подобный подход, но иначе относится к SFINAE и имеет полноценную среду на этапе компиляции, что тоже является проблемой.
    Вариант Java — generic с потерей типа на этапе выполнения — не устраивает этим самым компромиссом. После такого типы map[string]string и map[string]notstring станут эквиваленты, что усложнит работу type switch в Go и вообще является плохим решением.
    Вариант C# — generic без потери — возможен только в C# — шаблонизированный код остается таким даже в IL и превращается в конечные реализации только на этапе первого запуска функций, так как у шарпа нет интерпретатора (в отличии от явы) и JIT сработает при вызове, а не после определенного числа итераций. Поэтому затраты на компиляцию растягиваются по времени выполнения программы. В го используется компиляция для всего на этапе сборки.

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

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

    На самом деле, внутри компилятора, уже есть протипы обобщенных типов (map\slice\chan) и обобщенных функций(make\new), но они требуют к себе особого пиетета и используют несколько достаточно грязных, для обобщенного программирования, трюков. Все это доступно в исходниках, для тех кто желает ознакомится. Во вторых есть go:generate, а в go 1.6\1.7 хотят переделать пакет ast, что бы им стало приятно и удобно пользоваться для кодогенерации — это было и остается хорошим решением для языка, и продвигается ядром сообщества. Для тех кому не нравится кодогенерация, есть примеры обобщенных функций с использованием reflection.

    Наконец последнее — по опыту работы тех, кто берет го, необходимость в них возникает достаточно редко. Почти никто из крупных игроков использующих язык (такие как cloudflare, amazon, dropbox) жаловались совсем на другие, чаще всего детсткие, проблемы языка. А facebook выпустил вот такой «пакет» (осторожно юмор).

    Главная фича Го — асинхронность сияет не на каналах, а на неблокирующем IO которое программист видит и пишет как блокирующее. Большинство блокирующих I/O операций реализованы внутри с использованием epoll\WaitForMultipleObjects в специальной горутине. Этот подход близок к подходу C# c async/await, но за счет того, что у горутин полностью свой планировщик, есть определенные преимущества по скорости и возможным оптимизациям, а самое главное не приходиться явно указывать, что функция асинхронная. В случае когда есть необходимость в своей, нативной, блокирующей операции и необходима скорость, неплохим решением будет прикрепить (такое возможно) горутину к потоку ОС и сделать из нее менеджера раздающего данные по каналам. Хотя опять же, необходимость в таком возникает достаточно редко.

    В заключении — у Go хорошая и легкая спецификация. Изучается язык буквально за пару вечеров — целиком. Поэтому обоснованность решения в пользу или против го для каждого проекта стоит сделать самостоятельно. По словам Роба Пайка — одного из создателей языка — простота и некая топорность была ключевым требованием т.к. требовалось, что бы новые программисты могли как можно быстрее входить в курс дела. Как тут насмешливо сказали «язык для второкурсников» — и это недалеко от истины. Плохо ли это? Как показал опыт больших компаний и успех явы — элегантные и красивые решения чаще всего не самые удачные, стоят много денег и их тяжело поддерживать. Хотя и звучит это довольно грустно. Впрочем никто не собирается выкидывать существующие языки из тех сфер где они действительно применяются правильно. Даже гугл лишь добавил го к списку одобренных внутри компании языков — у них по прежнему есть новые проекты на C++\Java\Python.


    1. vintage
      09.10.2015 13:38

      «Полноценные шаблоны», они же «гетерогенная компиляция обобщённого кода» — это оптимизированная версия кодогенерации, инкапсулированая в компиляторе. Так что go:generate и go:ast не может быть быстрее толково реализованного go:generics. Другое дело, что для этого нужно приложить чуть больше умственных усилий.

      Отрывок из книги «Язык программирования D», от Александреску:

      В настоящее время наиболее распространены два подхода к генерации кода для параметризации типов:

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

      • Гетерогенная трансляция: при каждом вызове find с различными аргументами типов (int, double, string и т.д.) компилятор генерирует отдельную версию find для каждого использованного типа.

      Гомогенная трансляция подразумевает, что язык обязан предоставить универсальный интерфейс доступа к данным, которым воспользуется find. А гетерогенная трансляция больше напоминает помощника, пишущего по одному варианту функции find для каждого формата данных, который вам может встретиться, при этом все варианты он строит по одной заготовке. Очевидно, что у обоих этих подходов есть как преимущества, так и недостатки, о чем нередко ведутся жаркие споры в разных программистских сообществах. Плюсы гомогенной трансляции – универсальность, простота и компактность сгенерированного кода. Например, в чисто функциональных языках все представляется в виде списков, а во многих чисто объектно-ориентированных языках – в виде объектов; в обоих случаях предлагается универсальный доступ к данным. Тем не менее гомогенной трансляции свойственны такие недостатки, как строгость, недостаток выразительности и неэффективность.

      Гетерогенная трансляция, напротив, отличается специализированностью, выразительной мощью и скоростью сгенерированного кода. Плата за это – распухание готового кода, усложнение языка и неуклюжая модель компиляции (обычный упрек в адрес гетерогенных подходов – что они представляют собой «возвеличенный макрос» [вздох]; а поскольку благодаря C макрос считается чем-то нехорошим, этот ярлык придает гетерогенной компиляции сильный негативный оттенок).

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

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

      D использует гетерогенную трансляцию (внимание, ожидается бомбардировка техническими терминами) с поиском статически определенных идентификаторов и отложенной проверкой типов. Это означает, что, встретив определение обобщенной функции find, компилятор D выполняет синтаксический разбор ее тела, сохраняет результаты, запоминает место определения функции – и больше ничего, до тех пор пока кто-нибудь не вызовет find. В этот момент компилятор извлекает разобранное определение find и пытается скомпилировать его, подставив тип, который инициатор вызова передал взамен T. Если функция использует идентификаторы (символы), компилятор ищет их в том контексте, где была определена эта функция.


      1. Mikanor
        09.10.2015 18:32

        Если мне не изменяет память — то D даже позволяет генерировать код из текстовых констант. Вплоть до вставки mixin'ов из текста. Это может стать красивым решением в руках действительно хорошего разработчика, или жутких кошмаром в руках неопытного, и это тяжело читать и отлаживать. Даже boost покажется легким развлечением при попытке отладки такого кода.
        Второе — такие слабые ограничения на времени компиляции делают невозможным серьезный code-assist и хороший автокомплит. Насколько я знаю — эту проблему до сих пор не решили.

        Разницы скорости итогового кода при грамотных «заготовках» в случае go:generate не будет — как и при грамотных шаблонах. А если мы говорим про скорость компиляции, то такое сравнение не совсем корректно — т.к. условия на вызов кодогенерации можно повесить куда более сложные, чем на шаблоны. Однако это вызывает необходимость следить за изменением кода уже самому\с помощью сторонних средств.

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

        П.С. К Александреску, даже в мире плюсов с использованием шаблонов на полную катушку, относятся чуть с поднятой бровью. Идея с метапрограммированием хороша ровно до тех пор, пока вы понимаете, что из зачем пишет ваш коллега. У Александреску коллега это Уолтер Брайт — ему повезло…


        1. vintage
          09.10.2015 21:01
          -1

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

          https://habrastorage.org/files/d1e/52b/7c4/d1e52b7c487b4587a6315aa8c8dd48a0.png

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

          Например?

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

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

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

          Потому что к плюсам метапрограммирование было прикручено сбоку, а в D вокруг него строился весь дизайн языка. https://gist.github.com/nin-jin/e52e51a68e5a6b17c6fb#file-template-mixin-runtime-error-d