javascript backend developer
0,0
рейтинг
8 октября 2015 в 09:34

Разработка → Перевод: Один год с Go перевод

Под катом — перевод статьи опытного разработчика о его опыте практического применения 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.
Перевод: Andrew Thompson
Михаил @vindi
карма
34,0
рейтинг 0,0
javascript backend developer
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

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

  • +4
    Ну а мнение уважаемого переводчика каково?
    • +18
      Я не переводчик, добавлю от себя.

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

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


      В целом, язык интересный, но для себя достоинств я пока не увидел.
      • +6
        Аналогично, в основном на работе пишу на C#, тогда как хобби C++\Qt\QML. И те же самые замечания! К LINQ очень быстро привыкаешь, к генерикам, к честным ссылкам, к нормальной работе со строками в конце концов (А то в Go это то ли функции из «bytes», то ли «strings», и непонятно, выстрелит ли это в плане локализации)! Хотя некоторые вещи вроде «go» и «defer» хороши.
        • 0
          Dim0FF, QtRoS go-linq пробовали?
          • 0
             From(students).
             Where(func (s T) (bool, error){
                        return s.(*Student).age >= 20, nil
                }).
            


            Я правильно понимаю, что (а) внутри Where используется делегат и (б) в этом делегате входной параметр приводится к нужному типу?
            • 0
              Import your []*Student.
              Find those over 20. Note T is an alias for interface{}. So we make type assertion to our input type.

              Да.
              • 0
                Мда. Боль и печаль.
                • 0
                  Dim0FF RomanPyr lair Ну есть менее печальные варианты , хотя далеко и не идеальные.
                  • 0
                    Все равно же делегаты, да?
                    • 0
                      Нет — в gen используются конкретные типы, поэтому приводить ничего не нужно.
                      • 0
                        Я не спрашивал, есть ли приведение типов (я вижу, что нет), я говорю, что аргумент Where — делегат. Это ведь так?
                        • 0
                          А — является ли аргумент Where функтором(лямбдой, замыканием, функциональным обьектом — как хотите) — да является. Честно говоря сложно представить реализацию без функтора.
                          • 0
                            • +1
                              Либо я чего-то не понимаю в C#, либо в
                              fruits.AsQueryable().Where(fruit => fruit.Length < 6);
                              


                              fruit => fruit.Length < 6
                              


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

                                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.
                                • 0
                                  Черная магия .Net (:

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

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

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

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

                                    Ну это так, к выразительности языка.
                                    • 0
                                      Как раз здесь уже не провайдер, а полноценная решение на метапрограммировании шаблонами. Т.е. в данном случае не конечная реализация подстраивается под код, а работает условная «генерация» реализации из требований.
                                      • 0
                                        Однако же, язык позволяет это выразить. И про это-то и речь!
                                        • 0
                                          В выразительности плюсов никто никогда не сомневался. Вопрос в отладке таких шаблонов (концепты привет) и времени компиляции этого дела.

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

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

                                            Спирит прекрасен, конечно. Хаскелевский parsec/attoparsec-код можно переносить практически не думая.
                                  • 0
                                    Не знал про такое — но это свидетельствует скорее о умном компиляторе IL кода, нежели выразительности самого языка.

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

                                    Это не макрос, это совсем другого рода развлечение, очень мощное, по-своему.
          • 0
            Спасибо, попробую.
          • +1
            Не, ну это как раз-таки та вещь, которую тут почти единогласно осуждают — использовать привычные для одного языка подходы в другом, где они совсем «неродные».
            • 0
              вот именно.
      • +3
        Вот смотрите, вы же в C# понимаете отличия struct от object? Где они располагаются, как передаются в качестве параметра? Также, думаю, вам вполне понятны значения модификаторов ref и out? А давайте добавим сюда еще unmanaged код, где можно проводить операции с указателями, stackallock и fixed. Получается что в C# тоже не все просто. Кому-то тоже это может не нравится, а кто-то настолько привык, что даже не замечает. Видимо дело в привычке.
      • +2
        Каналы — удобно, но мне они нужны для параллельной обработки массивов данных. В C# это решается проще, Parallel.ForEach и вперёд

        Каналы вместе с горутинами по-идее призваны избавиться от callback-hell, который присутствует в некоторых языках.
        • 0
          В C# от него защищают async/await, если я все правильно понимаю.
          • +1
            На C# не пишу, почитал сейчас немного про acyns/await. Насколько успел разобраться, это все же разные подходы.
            Го меня цепляет тем, что можно просто писать plain-код. Тот же async/await будет работать не с любой функцией, она должна это поддерживать, а в го можно любое действие дернуть через go… и оно не будет блокировать остальные потоки выполнения. Т.е., тут не асинхронная модель.
            В совокупности с каналами и особенно с такой фичей как «select» это позволяет очень легко писать сложную логику управления кучей параллельных задач. Но за это мы платим тем, что нужно следить за потокобезопасностью кода, в го у нас нет гарантий, что в середине функции планировщик не переключится на выполнение другой функции.
            • +1
              Есть.
              «Планировщик, я закончил на пока, дай другим поработать в моей треде» горутина говорит либо явно (есть спец функция), либо делая блокирующую операцию (чтение из канала). Примечательно, что если совершается системный вызов, то горутина зависает вместе со всей тредой и планировщик вынужден либо ждать, либо родить еще одну треду. Такие пироги.
              Очевидно, что рядом работают в других тредах другие горутины и они могут начать писать туда, куда пишем мы. Но единственный язык, где об этом не нужно думать, это Rust.
              • +1
                > единственный язык, где об этом не нужно думать, это Rust.
                Ну почему же. Есть Erlang, Haskell, Clojure, где об этом точно не надо думать.

                А рантайм Erlang-а, например, достаточно умен, чтобы выполнять блокирующие системные вызовы на отдельном пуле тредов, что делает работу системы еще более предсказуемой.
              • +1
                Дак вот как раз если горутина слишком долго тупит (это может быть и не системный вызов), то создается еще тред, в который запихиваются другие горутины. Вот тогда мы и получаем возможные проблемы с одновременной записью в map, например, если не учтем этого.
                Вот довольно тупой пример, иллюстрирующий ситуацию. pastebin.com/jkH1Nvp2
                $ go run check.go
                Count 10000; 25.437204715 - 25.484347422
                Count 20000; 25.437177393 - 25.605745478
                End
                

                Как видим, горутины тут пересекаются по времени выполнения, хотя никаких блокирующих операций не делается.
                • 0
                  В Go 1.5 GOMAXPROCS по дефолту ставится равным числу ядер, соответственно, горутины выполняются на нескольких тредах по умолчанию.
                  То есть, ваш пример не демонстрирует ничего, кроме стандартного поведения.
                  • 0
                    Я и хотел показать стандартное поведение, что у нас нет гарантии того, что в середину одной горутины не может врезаться другая, например в середине записи в map попытаться тоже получить доступ к этому мапу. Если мы об этом не позаботились.
                    • 0
                      А, ну ок, я не тот мессидж прочитал.

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

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

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

                  > Вот тогда мы и получаем возможные проблемы с одновременной записью в map, например, если не учтем этого.
                  Я просто не представляю, как можно не учесть этого. Невнимательность? Да, но а как же иначе? Если язык будет это за нас учитывать (не методами разделения ресурсов аля Rust, а блокировками) то мы, возможно, получим потери в скорости, где нам бы этого не хотелось.
                  • 0
                    Да, я некорректно выразился насчет остановки. Но технически такое может произойти если два треда попадут на одно ядро. Их будет переключать планировщик ОС.
                    • 0
                      Да, это конечно так :)
    • 0
      Я считаю, что синтаксис и текущая реализация языка программирования — вторичны по отношению к экосистеме и сообществу. Где был javascript? А потом пришли ребята с V8, другие ребята с node.js — и все поменялось в течении пары лет. В дизайне самого языка есть спорные момент: GOROOT, отказ от классов, ручное управление контейнерами, контроль ошибок через возвращаемые значения — но все это сделано с определенными целями — серверная разработка «чтобы не текло и не падало». У меня нет большого практического опыта работы с Go. Что видел — работает быстро, но программисты жалуются что много ручной работы на низком уровне. Время покажет куда он будет развиваться и какое вокруг него сформируется сообщество.
      • +13
        Не согласен со вторичностью. У разработчиков экосистемы должна быть мотивация её развивать. Чтобы написать node.js надо угорать по языку и мечтать засунуть его всюду.
        • +3
          Тут, по-моему, не угадаешь. Как показывает практика, небольшая группа энтузиастов может угорать по чему угодно, сообщество формируются слабо прогнозируемым способом.
      • +12
        а чего поменялось то? Как была лапша с коллбеками и промисами, так она там же и осталась
        • 0
          В том-то и магия. Ничего по сути не поменялось — а популярность растет. И разработчики думают над способами борьбы с лапшой. Генераторы и async await вот сделали :)
          • +2
            На самом деле, тут все достаточно просто объяснимо, по крайней мере, постфактум.
            1. Случайно образовался JS в браузере. Пусть достаточно случайное явление, но язык не повернется назвать магическим.
            2. Жесткая конкуренция за растущий пирог случайно привела к тому, что он оказался во всех современных браузерах. Вот это магия, на мой взгляд. Условия рынка сложились достаточно специфические, здесь было вариантов пока еще много. Дальше все строго предсказуемо.
            3. Пирог веба вырос настолько, что браузеры стали использоваться почти всеми цивилизованными людьми чуть ли не каждый день. Оно и понятно: почти мгновенная коммуникация — лучшее изобретение человечества пока что.

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

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

            Так что, думаю, популярность растет просто потому что до сих пор не уперлась в потолок, но не просто так, а потому что JS-интерпретатор — самый распространенный на планете интерпретатор/компилятор.
      • +3
        Для javascript особо альтернативы не было по-моему. И, увы, никто так и не создал адекватной альтернативы (а еще — лучше замены связки HTML+JS+CSS) и теперь приходится с этим жить.
  • +4
    Хороший перевод. Но я еще ожидал немного Вашего мнения по теме, ибо его несоответствие с мнением автора особенно выделено перед переводом.
    • +39
      Это дисклеймер, чтобы фанаты Go не слили переводчику карму.
      • +10
        В целом да :). На Хабре не все читатели замечают что какая-то статья является переводом и начинает обращаться к переводчику как к автору. А у переводчика нет года практического опыта работы с Go
  • +8
    Еще одна мелочь в Go, которая меня дико раздражает, — это отсутствие optional arguments. Ну ничего, подумал я, можно ведь выкрутиться через дефолтные значения. Но и они, кто бы мог подумать, не поддерживаются, приходится строить подпорки.

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

        Авторы могут считать как угодно. Я не собираюсь говорить им как они должны делать свой язык. просто меня раздражает отсутствие возможности сделать что-то в стиле
        func f(n int := 0) {
            // pass
        }
        

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

        Особенно после распаковки аргументов в Python (*args, **kwargs), с которым Go часто сравнивают.
        • –2
          Вы совершаете ту же ошибку, что и автор статьи — вы боретесь с языком. Вместо того, чтобы понять, как с его помощью решать проблему, вы пытаетесь понять, как с его помощью сделать так, как я привык в других языках.
          Не нужно делать из variadic parameters попытку симулировать argument overloading. Поймите, что решить задачу (реальную задачу, которую должна решать программа) можно сделать несколько иным способом, кроме как «найти любой ценой способ передавать дефолтные значения». И ценой вашего болезненного раздражительного «отвыкания» будет более ясный и читабельный для других код.
    • +1
      Optional arguments можно реализовать через структуру с инициализацией с именованными полями.
  • +4
    Пишу на питоне когда нет особых требований к скорости исполнения, или на D — когда они есть. Счастлив в обоих случаях. Попытка освоить Go окончилась неудачей по причине отсутствия удовольствния при написании кода.
  • +4
    Пишу на го пол года, до этого где то год назад всё в нем не нравилось (первый подход )), но появился проект в котором нужно было написать сложную бизнес логику, работающую по крайней мере не медленно, и всё это за 4 месяца. На java писать не хотел, на Си не умел, нужен был язык который изучишь быстро, в итоге выбор пал на го, и я не разочарован. Как оказалось на го писать легко и приятно, есть возможности профилирования памяти и процессора, быстрая компиляция, стандартная библиотека которая охватывает почти всё. Среду разработки использую LiteIDE, выглядит страшновато, зато работает быстро и всё что нужно есть. Писать тесты на нем легко и приятно. Ну и то что он активно развивается и имеет отзывчивое сообщество это также на мой взгляд огромный плюс. Пока я работал над проектом они выпустили новую версию GC которая уменьшила задержки до неприлично малых значений. Проект в итогде в продакшене, будем смотреть :)
  • 0
    Я меня практический опыт работы с GO всего пару месяцев. Пока вообще далек от проблем в статье, и не факт, что когда-то они передо мной встанут. Сейчас пишу веб-приложение для одного сайта и в целом очень доволен.
    Отмечу плюсы:
    — язык очень простой
    — довольно строгие правила синтаксиса, я понимаю все чужие исходники и думаю другие легко будут понимать, что написал я
    — доступны исходники стандартных библиотек
    — компилируемость, отпадает потребность хранить исходники на сервере
    Из минусов:
    — не хватает оператора ( условие? выражение: выражение )
    — не такие большие сообщество и база знаний. Не всегда удается найти готовые решения или ответы.
    • +3
      — не такие большие сообщество и база знаний. Не всегда удается найти готовые решения или ответы.

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

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


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

    Статья — бред!
    … обиженной девки, надувшей губки: «я такая красивая, а он меня не любит...»
    • +9
      А аргументы кроме ad hominem у вас есть?
      • –30
        аргументы в том, что 1 год — это не тот опыт чтобы рот раскрывать?
        • +20
          Во-первых, учитывая, что Go всего три года — это вполне ощутимый срок.
          Во-вторых, за год можно получить достаточное количество как положительных, так и отрицательных впечатлений о языке и инструментарии, которые и изложить в статье.

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

            не 3, а 6
            • +5
              Go 1 вышел в марте 2012. Но даже если шесть — это все равно не меняет остальной аргументации.
    • –32
      Вань! Ты посмотри какие клоуны — рот хоть завязочки пришей!


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

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

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


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

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

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

            Поэтому, если уж дискутировать о позиционировании, давайте озвучим факт, что под этим термином разные люди понимают разные вещи. Кому-то кажется, что они должны писать собственные аллокаторы, а кому-то важно писать продуктивные программы для облаков.
            • 0
              Кстати в Go реально написать свой аллокатор, с помощью syscall.Mmap и unsafe.Pointer например.
            • –1
              Под «системным языком» можно понимать что угодно, но есть чёткие определения, что такое «прикладное ПО» и «системное ПО». На Go пишут прикладное ПО.

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


                Нука, нука… Определение — в студию.
                Желательно со ссылкой на авторитетный источник.
                • +1
                  Я понимаю, что за 40 лет можно всё забыть, в том числе всякие скучные определения, но как искать в гугле, я думаю, вы помните. Выжпрограммист.
                  • 0
                    Вы не правы. Вам выше привели ссылку на то, где авторы 4х системных языков объясняют, что определения размыты и подразумевают разные вещи.
                    Зачем писать «четкие определения», если они заведомо не четкие, и их нет, и даже ссылки на субъективные определения, справедливые для какой-то одной эпохи, вы не можете нагуглить?
                    • +1
                      Хорошо, если вам не нравится слово «чёткие», пусть они будут просто «определениями». Вы о чем спорите вообще, что хотите сказать? В любую, так называемую эпоху были программы, которые обеспечивали работу других программ.

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

                      (если что, минус не мой :)
          • 0
            Я не защитник гоу, но все таки считаю что ваш аргумент про системный язык требует аргументации.
            • 0
              Я же написал, что «системный язык не получился». Эту мысль можно проследить из этого интервью: 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 кода он вполне подходит.
      • +8
        Должен проработать, пока не полюбит Go, очевидно же.
      • +1
        Видимо сей комментатор посчитал, что о языке можно писать лишь после его забвения. Через пять-десять лет мы получим первое поколение опытных АЛГОЛ-программистов и пойдут первые реально хорошие рецензии от опытных разработчиков. К 2030 ждем хороших рецензий на Паскаль, а Java столь молода, что на ней априори пишут лишь юниоры.
  • +2
    Я не считаю GoLang — инструментом для всего подряд, в нем есть полезные вещи как горутины и каналы, поэтому сетевые задачи на нем решать удобно, а в других задачах он уступает другим инструментам.
    • +2
      Что такое «сетевые» задачи? Автор поста пишет, что невозможно изменить параметры создания сокета, не используя syscall — это вообще что хрень такая-то? Нафига тогда го, если есть С?
      «Go нужен хорош для сетевого программирования» — мантра которую все повторяют, но видимо уже забыли, что это вообще значит.
      • 0
        Очевидно, имеется ввиду не столько «сетевое», сколько «многозадачное с долгими ожиданиями событий для продолжения задач», когда создавать по потоку на каждую задачу — дорого, а делать всё в один поток — медленно. Спасением тут является кооперативная многозадачность (горутины, гринлеты, волокна, легковесные потоки). Многие языки поддерживают её в той или иной мере: Go, NodeJS, Python, D, Rust, C# да в общем любой современный язык.
        • 0
          Очевидно, имеется ввиду не столько «сетевое», сколько «многозадачное с долгими ожиданиями событий для продолжения задач», когда создавать по потоку на каждую задачу — дорого, а делать всё в один поток — медленно.
          Это само собой.

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

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

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

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

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

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

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

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

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

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

                  Вообщем, язык интересный, только похоже комьюнити очень маленькое, проблема с докой и примерами, возможно попробую его на какой-нибудь мелкой задаче.
                  • +2
                    > Это не так, попробуйте преобразовать Django в async+await…

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

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

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

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

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

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

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

                      А он-то тут при чём?
                      Я его попробовал в качестве асинхрононнго фреймворка работающего с сетью, дак вот он частично дублирует стандартную либу, про что я и говорил.
                      Если не vibe.d то что использовать для асинхронной работы с сетью?
                      • 0
                        gevent — это те самые «микротреды», о которых шла речь в этой ветке http://www.gevent.org/
                        Что именно вы вкладываете в async-await мне не ведомо.

                        Там есть разные либы, но vibe.d наиболее богатая в этом плане. Это же хорошо, когда у вас есть выбор между несколькими реализациями одного функционала, конкуренция, все дела, разве нет? :-)
                  • 0
                    Основная проблема с D, которая я вижу — отсутствие продвижения языка каким-нибудь монстром. Из этой проблемы вытекают более мелкие, но не критичные: слабый выбор IDE, органиченный выбор сторонних библиотек и фреймворков,. Однако качество языка и стандартных библиотек продаёт само себя, поэтому надеюсь что в ближайшее время ситуация исправится.
                  • 0
                    Сделал docker для D lang, кто хочет попробовать, запускать так:
                    > docker run -it lega911/dlang
                    # dmd --version
              • 0
                > В go только один тип, поэтому такой проблемы нет и не нужно городить «синтаксический мусор».
                Судя по короткому экскурсу в std.concurrency D — тамошние файберы работают как горутины и Fiber.yield возвращает с любого уровня вложенности вызовов => синтаксический мусор не нужен.
                • 0
                  Fiber.yield возвращает с любого уровня вложенности вызовов
                  Кстати в этом есть плюс — мы контролируем когда нам переключится, значит для глобальных/общих объектов в пределах потока локи не нужны в отличие от Го.
                  • 0
                    И минус — вы должны четко понимать, кто за кем следует, дабы не допустить блокировки или лишнего ожидания корутин. По сути вы выполняете работу планировщика, только вручную. Более того, ваши коллеги должны быть крайне внимательны при работе с таким кодом — наличие незащищенного shared state не является потокобезопасным, но у вас возможна работа с ним из разных потоков управления, что вызывает вопросы. Лично я такое решение считаю не очень удачным, и крайне не устойчивым — есть большая вероятность отстрела ноги, а ловить такие баги потом крайне неприятно и долго.
                    • –2
                      И минус — вы должны четко понимать, кто за кем следует
                      Да там полно минусов, поэтому горутины из Го — это значимая фича.
                    • 0
                      В D состояние по умолчанию не разделяется между потоками. Правда реализация передачи сообщений между ними использует блокировки. Не знаю, почему не реализовали неблокирующую очередь сообщений.
                    • 0
                      Так в Go тоже же самое, просто эти yield-ы спрятаны внутрь операторов работы с каналами и код работы с сетевым i/o. Я же говорю, файберы из D _по сути_ идентичны горутинам.

                      Там могут быть различия в реализации, но суть та же.
            • +4
              > D на голову лучше Go
              Не, ну давайте все же будем честны — в плане concurrent рантайма и интеграции его с event loop D до Go еще расти и расти, а кто будет за это платить — неясно.
              • 0
                Ну я так понимаю Александреску лично возглавит. С шашкой и на белом коне.
              • +1
                Что же в Go такого удивительного в рантайме и интеграции? Я вижу лишь небольшую разницу в синтаксисе.
                • 0
                  Ничего удивительного там нет, однако уже есть годный multicore планировщик с work stealing и уже написан неплохой враппер для асинхронного i/o на горутинах.

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

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

                      Я мельком глянул vibe.core.stream — как я понял, там для неблокирующей операции нужно опросить ОС сколько уже готово, вручную.
                      • 0
                        Внезапно нашёл: http://dpaste.dzfl.pl/

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

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

                      Разница такая — если одна горутина заблокируется (бесконечный цикл или блокирующее io), то D приложение встанет колом, когда в Го приложение будет работать, Mikanor про это отписался.
                      • 0
                        Горутины выполняются параллельно, когда это возможно по мнению планировщика. Отсюда некая недетерминированность I/O. В примере на D sleep выполняются асинхронно, но друг за другом, в том время как в го асинхронно, но параллельно.
                        • 0
                          В примере на D даже глобальные состояния разные. О чём вы?
                      • 0
                        Судя по цифрам — они либо в одном потоке, которого вполне хватает для таких задач, либо в разных, но разделяют одно состояние, что ещё хуже.

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

                        • 0
                          Для интереса сделал набросок балансировщика на dlang + vibe.d, тут не весь функционал и он уже отстает от версии на го на ~15-20% (запускал их в одном потоке + 10 клиентов и 10 ворекров). Может там нужно что-то «подтюнить»?
                          • 0
                            Не очень понял что там происходит. Может целиком бенчмарк выложите, чтобы я его мог у себя погонять?
                            • 0
                              Ох, как руки дойдут, но обещать не буду. Надо будет упростить скрипты, просто сделать проксирование.
                            • 0
                              Начал делать скрипт и с dlang беда какая-то — не возможно получить точное время, нашел рецепт, но он дает расхождения в 10 сек и более. Куда копать?
                              • 0
                                Подозреваю дело в том, что там считается ещё и время вывода в консоль, лови пул-реквест.
                                • 0
                                  С текущей версий тестов получились такие результаты:
                                  Dlang
                                  
                                  26572
                                  26607
                                  26678
                                  26678
                                  ...
                                  
                                  Go
                                  
                                  33764
                                  33292
                                  33787
                                  33403
                                  ...
                                  

                                  Го быстрее на 26%.
                                  • 0
                                    Какой компилятор для D использовался?
                                    • 0

                                      dmd, очевидно.

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

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

        Вполне возможно на С++ написать ещё более быструю версию, но возится с асинхронностью и процессами, что берет на себя GoLang из коробки, для меня не оправдано.
        • 0
          golang версия тоже через zeromq работает?
          • 0
            Нет, но основная логика приложения та же, (не думаю что ручная работа с сокетами и селектами в питоне даст больший профит чем через zmq).
        • 0
          , дак вот версия на golang в 3-4 раза производительней (что не удивительно)

          Это очень удивительно, ищите ошибки в архитектуре rpc на python + zeromq, такого не может быть.
          • +2
            такого не может быть.
            Не может быть что питон медленнее чем golang? Я думаю это очевидно что питон медленнее. Вот код.
            • 0
              Питон медленнее Го, но не в три-четыре раз, плюс речь идет о сетевом приложении, где основные тормоза это ожидание готовности ввода/вывода. И если у вас похожая архитектура, во всяком случае и там, и там асинхронная обработка сетевых подключение, то 3-4 раза очень и очень сомнительно.

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

                У Python'а много других достоинств, и Го там рядом не стоит. (Поэтому я на сервер-сайде использую Python, GoLang, C++ совместно для разных задач).
                • 0
                  Пустые циклы очень хорошо оптимизируются компиляторами, удивляюсь что только в 100 раз :)
                  Математика да, операции с плавающими числами в питоне медленные. Математику в питоне или не считают или считают с использованием специализированных пакетов типа numpy, насколько я знаю.

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

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

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

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

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

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

                        что бы Go не форкался автоматом по числу ядер?
                        Это управляется с помощью GOMAXPROCS
                        • 0
                          Для уверенности можете какую-нибудь сложную математику протестировать.
                          Математику не стоит, она очень плоха в питоне из коробки, просто делайте что-то в цикле, хотя бы просто инкременируйте переменную.

                          Как тестите эти два приложения? Есть такая штука github.com/joshmarshall/tornadorpc
                          было бы интересно сделать аналог на нем и посмотреть.
              • 0
                Погонял у себя примитивный тест lega (но с py версией с «while i < 1000000000»), Python вообще в 184 раза медленнее Go получился…
                • 0
                  А вот это даже как-то странно.
                  • 0
                    Я как раз с while и гонял, написал же.
                    • 0
                      Сори, не внимательно прочитал сперва :-)
                      • 0
                        Причем, 184 раза это python2.7. На python3.4 разница вобще в 275 раз.
                        • 0
                          Можете, ради интереса, попробовать запустить на pypy, — не будет отставать* от golang, если не обгонит.
                          • 0
                            pypy медленнее Go в 14 раз…
                            • 0
                              Я чуть поправил 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%
                              • 0
                                Да, так уже лучше: у меня разница всего в два раза примерно (6.0 против 3.5).
                              • 0
                                Добавил в циклы суммирование всех значений i:
                                go — 6сек
                                pypy — 165сек

                                Разница 27 раз. Ну я так не играю)
                                • 0
                                  Возможно из за того, что в этом случае в Го используется long*, когда pypy думает что результат может выйти за 8 байт и переключается на «bigint», а он гораздо медленнее.
                                  • 0
                                    Скорее всего. Если не допустить выхода за пределы разница всего в полтора раза.
                                • 0
                                  А я добавил D — он в 2 раза быстрее чем Go отработал.

                                  https://gist.github.com/lega911/c4b627c3f17625f05d44#gistcomment-1595006
                                  • 0
                                    dub это уже скомпиленное? Может тогда и Go запускать уже скомпиленное?
                                    • 0
                                      dub — это пакетный менеджер. В данном случае, он устанавливает зависимости, компилирует, линкует и запускает.
                                    • 0
                                      Причём тут скомпилированное или нет, если замер делается во время исполнения?
                  • 0
                    Да вроде ожидаемо, на сложных задачах разрыв будет меньше (вон брокер сверху всего в 3-4 раза), а если будут сплошные вызовы расширений (numpy или математика на cext), то питон будет даже быстрее. Рассматривайте питон как медленный менеджер над быстрым С-кодом.
                    • 0
                      Я сравнивал Go с C++ на несложных алгоритмах на массивах и хешах — по скорости вообще почти нет разницы.
                      Только в случаях совсем уж сложных вещей, которые хотят всяких -O3 -march и т.п.
                      Но Go он для сетевых сервисов все таки, а не считать Пи.

                      «всего в 3-4 раза» больше серверов надо…
                      • 0
                        Я на одной реальной, математической задаче получил х2 прирост на С, наверно за счет отсутствия GC и более быстрого map.
                      • 0
                        Но Go он для сетевых сервисов все таки, а не считать Пи.
                        Вот с этим я согласен, я с этого тред начал.
  • +1
    Один в один мои впечатления от ГО. Правда, год писать я на нём не осилил: ощущение борьбы с языком так и не ушло.
    Добавлю так же, что система тэгов для полей структур — тоже очень странная. Выглядит как костылик подставленный опосля («О! А я ещё классную штуку вспомнил»). Соответственно, работа с xml и json заставляет периодически заниматься кодогенерацией, а не динамической генерацией структур.
  • –1
    Каналы и мьютексы МЕДЛЕННЫЕ. Добавление синхронизации через мьютексы на production настолько снизило скорость работы, что лучшим решением стал запуск процесса под daemontools и его перезапуск в случае падения.

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

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

      От каких ошибок?
      • –7
        От каких ошибок?

        От ваших ошибок… от кривых рук ;-)
        • +9
          Ага, конечно. От кривых рук спасают иммутабельность(Haskell, Clojure), share nothing(Erlang) или move semantics(Rust, C++11+).
          В Go есть только соглашения и рекомендации, никакой реальной защиты они не предоставляют.
  • –7
    Я не могу понять смысл Go. Если мне нужен системный язык, я использую C/D/Rust. Если мне нужен язык с хорошей поддержкой параллелизма, то я использую Erlang или Haskell.

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

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

      Сильное утверждение. Покажите тестовые результаты, пожалуйста.
      • +3
        Тесты сравнения горутин и pthread? Ну когда pthread можно будет запустить в одном процессе хотя бы сто тысяч штук, то можно будет сравнивать. А так это все-таки вещи под разные задачи, причем первые «внутри» работают как раз на вторых.
        • 0
          Если goroutine работает поверх posix thread, то по каким критетиям вы сравнивали их скорость и эффективность?
          • 0
            Их сейчас нельзя сравнивать по скорости. Я не понимаю, как Olej смог их сравнить именно в категории «быстрее и эффективнее».
            Сравнивать можно разве что в контексте удобства использования и потребления ресурсов каждой из сущностей.
            • 0
              А когда можно будет?
            • +2
              Еще можно сравнить скорость переключения, но ежу понятно, выиграют зеленые треды, где нет трипов в ядро на переключение контекста, они для этого и придуманы.
      • 0
        Посмотрите silver searcher и platinum searcher. Идут ноздря в ноздрю с незначительным перевесом в пользу Go.
        • 0
          Спасибо за ссылки. Честно говоря, хотелось бы посмотреть на готовые результаты. Данный тред, безусловно, интересен, но на самостоятельную сборку и тестирование уйдёт слишком много времени.
          • 0
            В readme к platinum searcher есть результаты измерений автором. Простенькие правда, но тем не менее.
    • +12
      вы мягко говоря не в курсе о чём пишете.

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

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

      Масштабирование эрланга по ядрам — это реальность, причем на много лет более реальная, чем существует Go. Не пишите того, о чём не знаете.
    • +2
      Что вы понимаете под словом «эффективность»? Вы его употребляете в разных контекстах несколько раз.

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

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

      Ну, расскажите мне про это, пожалуйста.
  • 0
    обычно не язык или технология решает, а платформа вокруг которой построен язык, взять тот же самый дельфи и си#
  • –4
    если бы у го был бы хороший mvc фрпймворк или rad платформа все бы сразу побежали бы туда!
    • –8
      это справедливо… но только с точки зрения того, кто ничего кроме Windows не видел ;-)
    • 0
      Так многие и побежали или у вас ест сомнения что гоу вырвался из рамок экзотического языка?
  • +4
    Я либо сражаюсь с ограниченной системой типов с кастами всего в interface{} либо занимаюсь копипастой кода который делает практически одно и то же для разных типов.

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

      Ну и как? ;-)

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

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

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

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

    • +5
      В том-то и дело, что там не нужно делать такие манипуляции. Если человек все кастит в interface{}, значит он пытается перенести абсолютно чужие и крепко засевшие в голове паттерны туда, где они не нужны. Это печально, таких надо отсеивать на первом же собеседовании :)
      • +4
        Я слышал в Go нет дженериков. Как тогда делать контейнеры наподобие листов? Чтобы при вытаскивании не приходилось кастить элементы к нужному типу.
        • 0
          Они нинужны же.
        • –5
          Дженерики — это не только параметризированные контейнеры, и их важность для реальной разработки программистами из других языков сильно переоценена и приводит к тому, что дженерики используются по поводу и без.

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

            BTW, https://gist.github.com/kachayev/21e7fe149bc5ae0bd878 — «Channels Are Not Enough or Why Pipelining Is Not That Easy», отличное чтиво, как раз по теме.
            • –2
              Качаев — знатный кложурщик и Go-хейтер, да )
              • +2
                Кложурщик — если что, это не ругательство :) Я с ним знаком лично, и человек даже на митапе про Go пытался всем навязывать Clojure и рассказывал, что Go и удобства в конкурентности, это не серебрянная пуля, потому что там нет иммутабельных структур, поэтому переходите на Clojure. :)
          • +2
            Ну давайте хотя бы с контейнерами разберёмся. Как в Go сделать параметризированный контейнер?
            • –2
              Да что ж там разбираться — храните interface{}, как в golang.org/pkg/container/list.

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

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

                  Я всё жду, пока вы дойдете до вопроса «А почему авторы Go считают, что в программировании есть что-то иное, кроме параметризованных контейнеров?». Или вы тоже каждый день пишете свои параметризованные контейнеры из года в год?
                  • +2
                    Ну вроде речь сейчас идёт о параметризированных контейнерах. И, как я понял всё, что туда кладёшь надо кастить в interface{}, а потом обратно. И это следствие ограниченности системы типов.
                    • 0
                      Ну это вы о контейнерах, а я о шаблонах и паттернах которые человек не хочет или не может пересмотреть по мере того, как он пытается освоить новый язык. Начиная с того, что кастят в interface{} некоторые новички в массе других ситуацией, и заканчивая тем, что параметризация очень часто используется там, где она 100 лет не нужна.

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

                      Другими словами, если человек привык ездить в Икарусе, и ему неудобно без поручней в Мазерати (не за что держаться стоя), то это не недостаток Мазерати, это недостаток человека, что он так долго адаптируется к новым для себя реалиям.
                      • +3
                        «War is peace, generics are slavery, interface{} is bliss.»
                        • 0
                          Ну Оруэлла все читали, давайте что-то по сути.
                          • +3
                            Давайте по сути.
                            а я о шаблонах и паттернах которые человек не хочет или не может пересмотреть по мере того, как он пытается освоить новый язык

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

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

                            Какой майндсет предлагает Go в таком случае?
                          • +5
                            Давайте.
                            Я вот на хаскеле пишу. Он ни разу не класс-ориентированный ОО-язык, и набор паттернов в нём тоже совершенно иной. Но параметрический полиморфизм (читайте «генерики») там используется в хвост и гриву, как мощное средство повышения выразительности, производительности и надёжности. Сценарии его использования далеко не ограничиваются контейнерами, полиморфный код можно найти практически в любой библиотеке. И тут вдруг приходят гоферы и говорят, что если достичь просветления, сразу понимаешь, что генерики нинужны; но наглядных примеров, как без них резко всё делается проще, почему-то не показывают. При этом порой забывают, что язык несколько захардкоженных полиморфных типов всё-таки предоставляет (массивы, каналы, что ещё?), только другим их делать не даёт.
                            • –3
                              Ну так давайте тогда называть вещи своими именами — вы пишете на языке Х, где жить нельзя без дженериков. Где-то вы читаете, что в другом языке дженериков (в привычном для вас понимании) нет, но при этом Google, Dropbox, CloudFlare и куча других компаний пишут высоконагруженный производительный софт.
                              Вместо того, чтобы задаться вопросом «Ага, видимо в других языках что-то немного иначе, чем в моем любимом Хаскеле, видимо нужно изучить вопрос повнимательнее» вы решаете просто «Язык — отстой, потому что там нет того и в том виде, к чему я привык в Хаскеле».
                              Ну окей, что тут скажешь.
                              • +3
                                И что? Высоконагруженный производительный софт и на С пишут – и уж явно поболее, чем на го. Только вот сишники не говорят «всё городите свои классы и интерфейсы, вместо того чтобы пересмотреть свой подход и изучить вопрос повнимательнее», кроме совсем старозакалочных. Кстати, многие там без генериков тоже страдают, и костылят что-то на макросах и void*.
                                Ну и не надо мне каких-то левых мнений про отстой приписывать. Насчёт «в других языках что-то немного иначе» – параметрический полиморфизм в том или ином виде есть в подавляющем большинстве современных статических языков. Хаскель я привёл лишь в качестве примера, отличного от ООП-мейнстрима. Так что в данном вопросе это не он, это го такой особенный.
                                • –3
                                  Высоконагруженный производительный софт и на С пишут

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

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

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

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

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

                                    А в статье, надо отметить, и написано совершенно честно: «поговорим о том, почему я не считаю 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.


                                    Человек предлагает свое мнение, и предлагает он его по внешней просьбе.
                                    • +3
                                      В русском переводе это звучало бы как пассивная агрессия. Разница в менталитете, вот это все. Нейтральный тон ftw!
                                      • +2
                                        Угу, нейтральный тон, а что получилось — видно. Впрочем, было предсказуемо.
                                  • 0
                                    Не знаю, в каком порядке вы читали мой комментарий, но страдания были в абзаце про сишку, в которую полиморфизьма тоже не завезли, а не про подавляющее большинство.
                                    Да на всем пишут. Вопрос — какой ценой.

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

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

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

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

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

                        Я правильно понял?
                        • –1
                          Если мы так сильно требуем жесткую параметризацию, при этом у нас нет общего интерфейса(в случае го это означает, что у хранимых структур нету ни одного одинакового метода) для хранимых типов — то почему не использовать go generate на готовом шаблоне?
                          • +1
                            А какие преимущества приносит отказ от дженериков? Чем их отсутствие улучшает жизнь настолько, что вы готовы пойти на использование генераторов кода?
                            • 0
                              Создатели языка говорят, что дженерики заметно усложняют язык и они пока не придумали достойную реализацию.
                              • +4
                                Усложняют язык, или усложняют разработку компилятора?
                        • –1
                          Я правильно понял?

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

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

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

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

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

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

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

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

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

                            Это неправильная постановка вопроса. Правильная — «как часто вы пользуетесь параметризованным контейнером». Ответ — часто. Я вот — практически ежедневно.
                          • 0
                            Поглядел документ про 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)

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

                              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
                              Ну а я, давайте, 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)

                              Меньше абстракций, как и меньше ключевиков — глупый аргумент. Тем более, что обобщённое программирование наоборот повышает гибкость языка. А вот необходимость копипасты или постоянного приведения типов говорит как раз о костности языка.
                              • 0
                                vintage poxu — вы ведь понимаете, что вы счас осудили осуждение текущей реализации. Никто не говорит, что текущий подход это идеал — он просто есть, со своими плюсами и минусами, который наглядно выставили.
                                • +2
                                  Mikanor, они не понимают. У них есть мнение о том, с чем они не знакомы, и они тратят колоссальное количество сил и времени, чтобы это мнение насадить и рассказать окружающим.

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

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

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

                                    Если бы это было так, то не было бы архитекторов, а были бы сплошные программисты cum architect. Но нет.
                                  • +1
                                    Язык — это инструмент решения задачи, и одна из обязанностей любого программиста — уметь правильно оценивать и выбирать инструменты.

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

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

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

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

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

                                    Удобно!

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

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

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

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

                                    Ну и конечно когда человек, обвиняющий окружающих в хейтерстве переходит на личности первым — это пять.
                                • 0
                                  vintage да, осуждает.
                                  Что касается меня, то посмотрите внимательнее, что я писал про Cons. Там в основном молчанивое согласие.
                                  А вот Pros, да, сомнительные.

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

                              В С++ с этим связан SFINAE которой уж точно не ускоряет скорость компиляции.
          • 0
            Вы так и не ответили на вопрос. Как в Go сделать типизированный контейнер, которым можно пользоваться без кастов? Я вот в гугле нашел только или советы писать всё ручками, или делать генераторы кода.
            Если человек все кастит в interface{}, значит он пытается перенести абсолютно чужие и крепко засевшие в голове паттерны туда, где они не нужны.

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

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

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

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

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

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

                  Вы ждете ответ на такой вопрос в одном комментарии?
                  Мне странно объяснять такие простые вещи — сам по себе кастинг интерфейсных типов это ни плохо, ни хорошо. Иногда он нужен, чаще — нет. Любой (со средним соображением), кто не полениться потратить вечер-два, чтобы освоить основу языка, поймет, где нужно «пихать», а где не нужно.
              • 0
                Как следующий код переписать на Go? https://gist.github.com/nin-jin/5f6969cb9063b1977769#file-sorting-d
                • +2
                  • +4
                    Ну то есть 25% кода — копипаста. На каждую комбинацию «тип элемента» + «вид сортировки» требуется повторять по 9 строчек однотипного кода. И, кстати, вы потеряли юнит тесты.
                    • 0
                      На каждую комбинацию «тип элемента» + «вид сортировки» требуется повторять по 9 строчек однотипного кода.

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

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

                            «Все остальные» — это какие? Именно преимущества перед D, а не архаичным С, с которым Go обычно сравнивают.
              • +1
                Не понимаю. Конкретная проблема — реализация типизированных контейнеров. Вместо конкретного ответа вы уходите в общие рассуждения о «засевших в головах паттернах». Так как контейнер-то сделать?
                • +2
                  Просто контейнеры — это тоже засевший в головах паттерн.
                • –1
                  Конкретная проблема — реализация типизированных контейнеров

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

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

                  Ответил выше. В третий раз буду игнорировать вопрос.
      • +5
        Паттерны — это, конечно, хорошо. Ещё лучше вспоминать про их существование.

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

        А в Go что? Какая идея-то? Зачем мне его учить? Чем его изучение по вечерам и выходным сделает меня лучше?
        • –6
          Паттерны — это плохо, особенно, когда человек не способен за их рамки выходить. Есть даже известная фраза, что «Паттерны — это баг-репорт на ваш язык».

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    Признаться, по прочтению всяких статей начинает складываться впечатление, что Go — язык, создающийся под задачу «поддерживать написание кода вчера ушедшими со второго курса джуниорами, чтобы было адекватно». Ну, вполне себе ниша, что уж, только всё равно непонятно, почему так помпезно преподносится.
                    • –1
                      Я вам так скажу — то время, которое вы потратили на написание комментариев тут, достаточно, чтобы освоиться с Go и написать какой-нибудь реальный код. Как только для вас процесс написания кода станет важнее процесса «освоения языков», вы поймете всё, о чём я писал выше :)
                      • +3
                        У меня создаётся впечатление, что после вечера, проведённого в комментариях, я могу рассказать чем хорош Go лучше чем вы. Это при том, что кода на нём я пока что не писал. По моему каждая минута этого времени для меня уже окупилась в тройном размере.
                      • 0
                        Я даже на вопрос «зачем сра дискутировать о языках в комментариях» могу себе ответить (потому что это ненапряжное переключение мозга, пока мой плюсокод что-то считает минутку-другую), а вот на вопрос, зачем мне осваивать Go — до сих пор нет.

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

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

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

                          И это при том, что сборщик мусора есть и он работает с гарантированной задержкой. Всё как мечтают гуру JAVA.
                          • +2
                            Я сейчас включу «уже есть в $langname», что может не понравиться знатокам Go, прошу уж простить.

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

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

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

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

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

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

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

                              Сборщик мусора в java может остановить всё на неопределённый период времени и это больно. В Go такой пробемы нет — gc отработает за 10 ms.
                              • 0
                                Можно там пересобрать весь проект и прогнать тесты секунд за 10? Хотя понимаю конечно — зависит от величины проекта. Но хотя бы в субъективно небольшом проекте можно такое? REPL всё-таки не замена TDD.

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

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

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

                                Магия какая-то. А время следующего запуска сборщика как-то определено или нет?
                                • 0
                                  Насколько я понимаю нет, но я не углублялся в вопрос.
                                  • 0
                                    Тогда сценарий «gc работает 10 мс, потом 1 мс — пользовательский код, и так 10 раз» вполне легитимен и даже соответствует претензиям на детерминированность времени работы GC. Только чем оно принципиально лучше одной не очень детерминированной 100 мс задержки, не очень понятно (особенно если пользовательская задача занимает больше 10 мс при данных цифрах, которые сугубо иллюстративны, и вы можете подобрать соотношение gc/work на ваш вкус).
                                  • 0
                                    Ну тут вы не совсем правы — наложено лишь ограничение — не более 10ms каждые 50ms на GC. Поэтому если не справился за один подход — значит будет пытаться в следующие 50ms. И так далее…
                                    • 0
                                      Это хорошо.

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

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

                                            По второй ссылке в вашем комментарии только сиротливо висит «correctness proofs in literature (see me)» внизу 52-го слайда, но это не очень хорошая и вежливая отсылка на вопрос о конкретной задаче.
                                      • 0
                                        удалено, наверху верно ответили
  • +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).
    • +4
      Да и кстати append всегда создаёт новый слайс. Но важно помнить, что часть одного слайса может быть так же частью другого. Если что есть copy. Да эта тема довольно проста и хорошо освещена, по крайней мере в англоязычном мире и не нужно хорошо знать язык, чтобы до неё дойти. Чувак просто не разобрался. Вот и всё.

      Собственно я том, что не стоит винить язык за свои ожидания в его поведении, если документацию изучить не досуг.
  • +1
    А мне доставляет удовольствие гоу хотя, как и автор статьи, периодически недоумеваю от местных указателей, и строк с []byte.
    • +1
      Зачем недоумевать, если можно на сайте Go прочитать про поинтеры: golang.org/doc/effective_go.html#pointers_vs_values
      • +1
        Да как бы и так ничего нового, но все же… Я ж не программист, а маску на стройке нашёл.
  • +11
    Повеселила статья, которую правильно бы было назвать «Год с моей последней блогозаписи в Go».

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

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

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

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

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

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

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

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

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

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

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

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

    Хороший вброс, одобряю.
    • 0
      А можете пояснить начинающему, почему вообще происходит кастинг в interface{}? Зачем он нужен?
      • 0
      • +4
        В Go несколько уникальный подход — есть структуры и интерфейсы, первые определяют данные, вторые — поведение. При этом любая структура с данными может неявно реализовать какое-то поведение (интерфейс), просто имея нужные методы с нужной сигнатурой.
        И тут начинается интересное — если понять эту парадигму, особенно после class-ориентированных «ооп» языков, то многие вещи начинают быть проще и понятней. Становится более ясно, когда мы работает с данными, а когда логикой и можно передавать аргументы функциям как через типы-структуры, так и через типы-интерфейсы. Тоесть один тип может быть и структурой и интерфейсом одновременно.

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

        Вот одна из статей, объясняющая интерфейсы: go-book.appspot.com/interfaces.html
        • +1
          В Go несколько уникальный подход — есть структуры и интерфейсы, первые определяют данные, вторые — поведение.

          Я вот недавно читал книгу Чистый код, Роберта Мартина. Примеры чистого кода приведены на Джаве. И там то же самое, только интерфейсы заменены объектами. А ещё уникальным подходом это никто не называет.
          • 0
            По идее, после этой книги, вы должны легко отличать «тоже можно сделать» от «основа дизайна языка».
          • +3
            Вы правы, но лишь частично — в отличии от Go, в Java одинаковый набор методов у двух интерфейсов не означает типовое равенство этих интерфейсов. Как и в большинстве ОО языков. Таким образом, если другой человек написал класс и интерфейс к нему, то вам придется либо использовать его интерфейс в своем коде выполняющим с его объектами работу. Это удобно, но до тех пор, пока вы вдруг не понимаете, что у вас есть объекты обладающие похожими методами и код можно вынести в один. Дальше вариантов два — либо вы говорите, что ваши классы реализуют еще и этот «чужой» интерфейс, попутно реализуя заглушками возможные дополнительные методы (что скажем так, не красиво) — либо окольными путями приводите чужой код уже к вашему интерфейсу — например через делегирование.

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

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

              Если я правильно понял, то вы говорите об утиной типизации. Вещь хорошая, но уникальной её не назовёшь. Хотя если говорить о языках со статистической типизацией, то я больше такого не припомню. В С++ вроде что-то такое собираются ввести.
              • 0
                Больше похоже на упрощенные (раз там отсутствует иерархия) примеси (mixins).
              • 0
                Это называется «структурная типизация». Она меняет проблему порождения подтипа стороннего типа, на проблему семантического конфликта структурно идентичных интерфейсов. Грубо говоря: волк одевает шкуру овцы, блеет как овца, а когда вы уходите — выплёвывает сено и съедает настоящую овцу. Оба решения так себе. Я бы предпочёл номинативную типизацию с возможностью ручного приведения к структурно идентичному типу.
              • 0
                В С++ вроде что-то такое собираются ввести.

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

                Собственно, насколько я понимаю, можно провести некоторую аналогию между Go'шными интерфейсами (только на уровне кода времени исполнения) и между плюсовыми концептами (только на уровне компиляции).
                • 0
                  Я про этот proposal
                  • 0
                    А, не, это таки не утиная типизация, это, если хотите, расширение алгоритма поиска функций для вызова. Типы всё так же строго определены.
                    • 0
                      Ну я так понимаю, что в связке с шаблонами это позволяет достичь эффекта, похожего на тот, что есть в Go. Расширения типов стандартной библиотеки без правки кода непосредственно в ней.
                      • 0
                        Да, в том числе, этакие extension methods.
                        • 0
                          UCS очень спорная фича — там даже в коммитете не все до конца убеждены. Это введет кучу новых правил на resolution. Но после истории с концептами, с Бьёрном предпочитают соглашаться.
                          • +1
                            А что за история с концептами?
                          • 0
                            Не уверен насчёт кучи новых правил, в конце концов, запись x.f() означает поиск f(x) (и, согласно одному из двух пропозалов, обратно, ЕМНИП). Что это может действительно снизить, будучи применяемым бездумно — это читабельность кода. Ну так простите, C++ такой, это норма!
                            • 0
                              UCS вносит интересные вещи в resolution методов. Хорошее обсуждение тут и было еще одно где-то. Например случай с вызовом swap внутри класса, который и сейчас не очень тривиальный.

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

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

                                Спасибо за экскурс в социальную часть, я ей традиционно не интересовался. Пойду теперь дискуссию на реддите почитаю.
                                • 0
                                  А что будет, если у нас есть одновременно реализация swap как метода и swap как свободной функции? При этом на входе одни и те же аргументы (this неявно же передается).
                                  • 0
                                    Должно выбраться что-то одно из них, разве нет? Надо смотреть в пропозал, какие там приоритеты, я не помню точно.
                • 0
                  Именно — и то и другое накладывает список требований к поведению передаваемого объекта, но не требуя изменения его структуры. Побочным явлением того, что у Go это реализовано в рантайме является информация о типах во время исполнения и полноценный reflection с (почти) всеми фичами. Ну и минус это некая потеря в скорости исполнения, конечно — близкая к vtable. Такой подход не соответствует плюсам, где ты не платишь за то, что ты не используешь. С другой стороны споры вокруг RTTI все еще не прекращаются.
                  • +1
                    Однако, конкретно плюсовая реализация утиной типизации в шаблонах и многолетний опыт работы с ней заставляют меня желать концепты яростно, страстно, стремительно! Не окажется ли чего такого с гошных интерфейсами?

                    Впрочем, значительная часть этого желания возникает от использования enable_if и прочего метапрограммирования со SFINAE.
                    • 0
                      В смысле будут ли расширятся интерфейсы? Никто не знает — все возможно, определенные изменения в язык внести были предложения, но 1) пока нет достаточного мотивации со стороны сообщества и ядра 2) жесткая обратная совместимость в пределах 1ой версии 3) цель на простоту языка — а каждая новая фича это увеличение сложности.
                      Сейчас усилия сосредоточены на оптимизации итогового кода и поддержки сторонних платформ. Ядро сообщество сосредоточено на улучшении GC и Escape Analysis. Впрочем с учетом итерации — релиз раз в 6 месяцев — что будет через пару лет пока предсказать сложно. У плюсов например итерация 3 года.
      • +8
        Затем, что это единственный способ абстрагироваться от типа обрабатываемых данных. interface{} в Go, это как void* в С.
        В языках с более развитой системой типов для этого существуют дженерики, но в Go они нинужны, это все знают.
        • 0
          void* в С не содержит информацию о типе переменной лежащей внутри, в отличии от Go, поэтому гарантированно узнать, что же там лежит внутри можно только если у вас любая структура содержит вспомогательное поле о ее типе
          interface{} это не спец тип — это обычный интерфейс, у которого нет требований по методам, а значит ему удовлетворяет любой тип. Сама по себе любая переменная интерфейсного типа в Го, это всегда пара указателей — один на саму переменную в памяти (далеко не всегда в хипе) а другая указатель на ее настоящий тип.
          • 0
            В языке со строгой статической типизацией делать переход от специфичного множества к множеству, включающему всё, — это путь к ошибкам. Выше вы упоминали про кодогенерацию, можете пример дать?
            • 0
              Никто не говорил, что это красивое или хорошее решение. Насчет кодогенерации — пример (именно пример использования) от создателей.
    • 0
      У меня вот такой вот вопрос. Как вообще нормально с Map работать? Там же нету метода из серии pushAll. Я правильно понимаю, что для каждого отдельного случая перекладывания данных из одного Map в другой я должен реализовать свой собственный метод?
      • 0
        Я правильно понимаю, что для каждого отдельного случая перекладывания данных из одного Map в другой я должен реализовать свой собственный метод?

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

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

          logn — это мелочь, конечно, по сравнению с n, но всё-таки.
          • 0
            Это даже преждевременной оптимизацией не назовешь, настолько это неуместно )
            • –1
              Неуместно думать, в какой регистр что запихнётся. А думать о временных сложностях алгоритмов всегда уместно.

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