На протяжении последних месяцев я использую Go для имплементаций Proof of Concept (прим.пер.: код для проверки работоспособности идеи) в свободное время, отчасти для изучения самого языка программирования. Программы сами по себе очень просты и не являются целью написания статьи, но сам опыт использования Go заслуживает того, чтобы сказать о нем пару слов. Go обещает быть (прим.пер.: статья написана в 2015) массовым языком для серьезного масштабируемого кода. Язык создан в Google, в котором активно им пользуются. Подведя черту, я искренне считаю, что дизайн языка Go плох для умных программистов.


Создан для слабых программистов?


Go очень просто научиться, настолько просто, что введение заняло у меня один вечер, после чего уже мог продуктивно писать код. Книга по которой я изучал Go называется An Introduction to Programming in Go (перевод), она доступна в сети. Книгу, как и сам исходный код на Go, легко читать, в ней есть хорошие примеры кода, она содержит порядка 150 страниц, которые можно прочесть за раз. Сначала эта простота действует освежающе, особенно в мире программирования, полного переусложненных технологий. Но в итоге рано или поздно возникает мысль: "Так ли это на самом деле?"


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


Так для чего же он был создан таким простым? Вот пара цитат Роба Пайка (прим.пер.: один из соавторов языка Go):


Ключевой момент здесь, что наши программисты (прим.пер.: гуглеры) не исследователи. Они, как правило, весьма молоды, идут к нам после учебы, возможно изучали Java, или C/C++, или Python. Они не в состоянии понять выдающийся язык, но в то же время мы хотим, чтобы они создавали хорошее ПО. Именно поэтому их язык должен прост им для понимания и изучения.
 
Он должен быть знакомым, грубо говоря похожим на Си. Программисты работающие в Google рано начинают свою карьеру и в большинстве своем знакомы с процедурными языками, в частности семейства Си. Требование в скорой продуктивности на новом языке программирования означает, что язык не должен быть слишком радикальным.

Что? Так Роб Пайк в сущности говорит, что разработчики в Google не столь хороши, потому они и создали язык для идиотов (прим.пер.: dumbed down), так чтобы они были в состоянии что-то сделать. Что за высокомерный взгляд на собственных коллег? Я всегда считал, что разработчики Google отобраны из самых ярких и лучших на Земле. Конечно они могут справиться с чем-то посложнее?


Артефакты чрезмерной простоты


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


Не очень выразительный


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


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


package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
)

func main() {

    flag.Parse()
    flags := flag.Args()

    var text string
    var scanner *bufio.Scanner
    var err error

    if len(flags) > 0 {

        file, err := os.Open(flags[0])

        if err != nil {
            log.Fatal(err)
        }

        scanner = bufio.NewScanner(file)

    } else {
        scanner = bufio.NewScanner(os.Stdin)
    }

    for scanner.Scan() {
        text += scanner.Text()
    }

    err = scanner.Err()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(text)
}

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


Вот, к примеру, решение той же задачи на D:


import std.stdio, std.array, std.conv;

void main(string[] args)
{
    try
    {
        auto source = args.length > 1 ? File(args[1], "r") : stdin;
        auto text   = source.byLine.join.to!(string);

        writeln(text);
    }
    catch (Exception ex)
    {
        writeln(ex.msg);
    }
}

И кто теперь более читабельный? Я отдам свой голос D. Его код куда более читаемый, так как он более явно описывает действия. В D используются концепции куда сложнее (прим.пер.: альтернативный вызов функций и шаблоны), чем в примере с Go, но на самом деле нет ничего сложного в том, чтобы разобраться в них.


Ад копирования


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


package main

import "fmt"

func int64Sum(list []int64) (uint64) {
    var result int64 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int32Sum(list []int32) (uint64) {
    var result int32 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int16Sum(list []int16) (uint64) {
    var result int16 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int8Sum(list []int8) (uint64) {
    var result int8 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func main() {

    list8  := []int8 {1, 2, 3, 4, 5}
    list16 := []int16{1, 2, 3, 4, 5}
    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(int8Sum(list8))
    fmt.Println(int16Sum(list16))
    fmt.Println(int32Sum(list32))
    fmt.Println(int64Sum(list64))
}

И этот пример даже не работает для знаковых типов. Такой подход полностью нарушает принцип не повторять себя (DRY), один из наиболее известных и очевидных принципов, игнорирование которого является источником многих ошибок. Зачем Go это делает? Это ужасный аспект языка.


Тот же пример на D:


import std.stdio;
import std.algorithm;

void main(string[] args)
{
    [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}

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


Простой обход системы типов


Я полагаю, читая это, программисты Go будут с пеной во рту кричать: "Ты делаешь это не так!". Что же, есть еще один способ сделать обобщенную функцию и типы, но это полностью разрушает систему типов!


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


package main

import "fmt"
import "reflect"

func Reduce(in interface{}, memo interface{}, fn func(interface{}, interface{}) interface{}) interface{} {
    val := reflect.ValueOf(in)

    for i := 0; i < val.Len(); i++ {
        memo = fn(val.Index(i).Interface(), memo)
    }

    return memo
}

func main() {

    list := []int{1, 2, 3, 4, 5}

    result := Reduce(list, 0, func(val interface{}, memo interface{}) interface{} {
        return memo.(int) + val.(int)
    })

    fmt.Println(result)
}

Эта имплементация Reduce была позаимствована из статьи Idiomatic generics in Go (прим.пер.: перевод не нашел, буду рад, если поможете с этим). Что же, если это идиоматично, я бы не хотел увидеть не идиоматичный пример. Использование interface{} — фарс, и в языке он нужен лишь для обхода типизации. Это пустой интерфейс и все типы его реализуют, позволяя полную свободу для всех. Этот стиль программирования до ужаса безобразен, и это еще не все. Для подобных акробатических трюков требуется использовать рефлексию времени выполнения. Даже Робу Пайку не нравятся индивиды, злоупотребляющие этим, о чем он упоминал в одном из своих докладов.


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

Я бы взял шаблоны D вместо этой чепухи. Как кто-то может сказать, что interface{} более читаем или даже типобезопасен?


Горе управления зависимостями


У Go есть встроенная система зависимостей, построенная поверх популярных хостингов VCS. Поставляемые с Go инструменты знают об этим сервисах и могут скачивать, собирать и устанавливать из них код одним махом. Хотя это и здорово, есть крупная оплошность с версионированием! Да действительно, можно получить исходный код из сервисов вроде github или bitbucket с помощью инструментов Go, но нельзя указать версию. И снова простота в ущерб полезности. Я не в состоянии понять логику подобного решения.


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


Культурный багаж из Си


По-моему мнению, Go был разработан людьми, которые использовали Си всю свою жизнь и теми, кто не хотел попытаться использовать что-то новое. Язык можно описать как Си с дополнительными колесиками(ориг.: training wheels). В нем нет новых идей, кроме поддержки параллелизма (который, кстати, прекрасен) и это обидно. У вас есть отличная параллельность в едва ли годном к употреблению, хромающем языке.


Еще одна скрипучая проблема в том, что Go — это процедурный язык (подобно тихому ужасу Си). В итоге начинаешь писать код в процедурном стиле, который ощущается архаичным и устаревшим. Я знаю, что объектно-ориентированное программирование — это не серебряная пуля, но было бы здорово иметь возможность абстрагировать детали в типы и обеспечить инкапсуляцию.


Простота для собственной выгоды


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


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


Спасибо mersinvald за правки

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


  1. SirEdvin
    10.12.2017 23:42

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


    1. Hokum
      10.12.2017 23:56

      Не такая она и ужасная. Местами очень даже полезная, взять тоже Thrift. Всему есть место, кроме копипасты. Копипасте тоже есть место, но очень редко и в исключительных случаях.


      1. SirEdvin
        11.12.2017 02:23

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


        1. Dair_Targ
          11.12.2017 03:27

          У нас в проектах java immutables (которая практически кодогенерация) крайне помогает. Кроме того практически весь современный front-end js построен фактически на кодогенерации (babel, es6 support, react jsx)


          1. MooNDeaR
            11.12.2017 09:39

            Что ни разу не облегчает отладку)


            1. Dair_Targ
              11.12.2017 13:11

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

              Про babel/es6/jsx — есть же source maps, один раз на проект настроил и отлаживай себе.


          1. SirEdvin
            11.12.2017 10:28

            А еще есть lombok. И мне почему-то, кажется, что оба эти проекта подходят под пункт: "Мы боремся с косяками языка".


            А с js ситуация еще хуже, потому что там у людей еще и выбора нет.


            1. Dair_Targ
              11.12.2017 13:13

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


          1. Psychosynthesis
            14.12.2017 05:00

            Современный «front-end js» это настоящий ад, между делом.


          1. Areso
            14.12.2017 08:21

            И потом этот «кодосгенерированный» front-end js адски тормозит на клиентских устройствах.


        1. Hokum
          11.12.2017 13:26

          Клиент и сервер могут быть написаны на одном языке, но быть независимыми проектами и разрабатываться разными командами. И тогда Thrift будет их стыковать. Т.е. и клиент, и сервер будут зависеть от некоторого третьего продукта, который будет представлять собой набор файлов Thrift.


          1. SirEdvin
            11.12.2017 13:28

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


            1. Hokum
              11.12.2017 13:53

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


              1. SirEdvin
                11.12.2017 14:53

                Возможно, вы и правы. Мне кажется, что все-таки удобнее на одном языке, но задачи бывают разные.


        1. Hokum
          11.12.2017 13:42

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


    1. khim
      11.12.2017 01:56
      +1

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

      Разработчики Go — не были фанатами IDE и потому использовали «старый стиль», когда кодогенерация является одним из инструментов, а не «табу», с которым борются всеми возможными способами…


      1. SirEdvin
        11.12.2017 02:22

        Это где же в современных ide кодогенерация?


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


        1. unsafePtr
          11.12.2017 03:25

          Могу вспомнить как минимум resource файл в VisualStudio. Можно статично через диалоговое коно указать путь к файлу. IDE ещё на прекомпиляции проверит что такой файл существует и сгенерирует статичный класс. Очень удобно например вынести все sql файлы в такой ресурс, а потом в месте использования заявки написать что то вроде:

          var result = await db.Query(SQLResources.GetProducts);


        1. l4l Автор
          11.12.2017 03:28

          e.g: IDEA


        1. khim
          11.12.2017 03:56
          +1

          Это где же в современных ide кодогенерация?
          Везде. Начиная от автоматического создания кучи бойлерплейта Wizard'ами, до вполне себе «классической» кодогенерации вещей типа R.java.

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

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


          1. SirEdvin
            11.12.2017 10:30

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

            Я так не считаю. Разве что в случае с ресурсными файлами, как мне указали правильно, и, например, настройкой GUI через стороннее приложение.


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


            1. khim
              11.12.2017 16:22

              Разве что в случае с ресурсными файлами, как мне указали правильно, и, например, настройкой GUI через стороннее приложение.
              А чем ресурсные файлы уникальны? Чем ORM, RPC, FSM хуже? Тем, что ваша IDE их не знает? Ну так научите! Или успокойтесь уже и признайте, что «магическая лицензия» для кодогенерации не нужна.

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

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


              1. SirEdvin
                11.12.2017 16:26

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


                Опять же, вы приписываете мне какую-то странную приверженность IDE и "магической лицензии", но я просто считаю кодогенерацию не очень удобной и стараюсь ее избегать как можно чаще. Особенно в рамках одного языка, где казалось бы фич языка должно хватить. Но вот господам с Go и Java приходится страдать.


              1. SirEdvin
                11.12.2017 16:52

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

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


                if err != nil {
                    return nil, err;
                }


              1. SirEdvin
                11.12.2017 17:02

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

                Берите любой крупных проект на go и попробуйте сделать grep "interface{}" -R . в его репозитории. Я не эксперт, но мой взгляд, почти каждый interface{} будет из-за проблемы с отсутствием дженериков. Я вот только что грепнул alertmanager и prometheus. И даже в alertmanager нашлось место этому чуду:


                ./template/template.go:func (t *Template) ExecuteTextString(text string, data interface{}) (string, error) {
                ./template/template.go:func (t *Template) ExecuteHTMLString(html string, data interface{}) (string, error) {
                ./template/template.go:type FuncMap map[string]interface{}
                ./template/internal/deftmpl/bindata.go:func (fi bindataFileInfo) Sys() interface{} {


              1. JekaMas
                11.12.2017 17:26
                +1

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


          1. aamonster
            11.12.2017 13:33

            Я всегда считал, что наоборот: код, сгенерированный визардами и т.п. — это плохо. Во первых, если внести в него изменения — при повторной генерации они пропадут. Во вторых, сгенерённый код не должен попадать в version control. В третьих, это вообще что-то вроде obj-файла, в нормальных условиях мне не надо его видеть.
            Короче: кодогенерация на этапе сборки — нормально, кодогенерация при написании кода — фу-фу-фу.


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


  1. wOvAN
    11.12.2017 00:04

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

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


    1. sheknitrtch
      11.12.2017 00:43

      Попробуйте язык D, который приводится в качестве примера в статье. Нативный код с GC, нет зоопарка разных компиляторов. Я использую его для решения задач из HackerRank.com и мне D показался отличным языком для написания алгоритмов.


      1. mersinvald
        11.12.2017 00:51

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


        Компилятор, как и stdlib всё еще имеют баги, которые препятствуют использованию D в продакшне. Увы, это язык скорее "для души" нежели для работы.


        1. Temtaime
          11.12.2017 10:49

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


          1. mersinvald
            11.12.2017 11:11

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


            1. Temtaime
              11.12.2017 13:31

              У меня есть крупный проект клиента MMORPG на OpenGL на D.
              В начале разработки(4-5 лет назад) постоянно натыкался на баги в компиляторе/стандартной библиотеке. За последний год если только несколько багов в новой функциональности нашёл.
              Единственная проблема крупная на данный момент — консервативный GC, который в моём клиенте умудряется течь, чем несказанно портит жизнь.
              Главная проблема комьюнити — они любят трепаться о всяких новых технологиях, но никто не хочет тот же самый GC сделать precise.


              1. jacob1237
                11.12.2017 20:35

                У Вас клиент наверное под x86 без 64?


                1. Temtaime
                  11.12.2017 21:50

                  Под x86_64.


                  1. jacob1237
                    12.12.2017 15:07

                    Странно что он течет под x86-64, т.к. по идее проблема "фальшивых" указателей на этой платформе стоит не так остро как на 32 разрядных системах.
                    Жаль это слышать, надеюсь они наконец-то дотестят и сольют пулл реквест precise gc с мастером.


                    А сколько примерно объектов в памяти у Вас в среднем? Просто для статистики, хочу лучше понять масштаб проблемы уктечек на стандартном GC


      1. khim
        11.12.2017 01:58

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

        Это один из важгейших вопросов — но я не понимаю что разработчики D вообще про него думают…


    1. Yardanico
      11.12.2017 09:24

      Можете попробовать Nim, там тоже нативный код с опциональным GC, к тому же ведётся работа над деструкторами, кросс-компиляция как в Си (Nim компилируется в Си), никаких виртуальных машин и максимальная производительность (на уровне близком к чистому Си при правильном использовании языка)


      1. antonksa
        13.12.2017 00:49

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


  1. CodeRush
    11.12.2017 01:04

    Автор не понимает целей и задач Гугла при разработке этого языка, поэтому сетует на то, что Go — это такой «С для дураков», а надо было вместо него внедрять что другое, с нативным ООП, с шаблонами, с выводом типов. D, например, или Rust, или вообще ЯФП какой-нибудь.
    Так вот, примерно 90% задач гугла вполне решается на этом самом «С для дураков» без использования кодогенерации, рефлексии, шаблонов, ООП и чего либо еще, и самое главное, что в итоге написанный разработчиками любого уровня код на Go смогут понять любые другие разработчики, даже если они в компании работают сутки и пришли сразу после ВУЗа.
    Более того, при уходе всех оригинальных разработчиков из команды проект не придется выбрасывать весь, потому что в нем никто не может разобраться, а получится передать другой команде обычных программистов, и они смогут подхватить его в относительно короткие сроки.
    Простота поддержки, простота отладки и поиска ошибок, доступность даже для новичков, и минимальные шансы выстрелить себе в ногу — вот что нужно компаниям уровня Гугла для большей части их кода. А оставшуюся меньшую часть можно писать на чем угодно, хоть на ассемблере, если есть такая необходимость.


    1. third112
      11.12.2017 02:01

      примерно 90% задач гугла вполне решается на этом самом «С для дураков»

      Откуда такая цифра «90%»? Всякие intelligent personal assistant'ы, беспилотные автомобили и другие AI-проекты, которыми так годится Гугл, входят в эти 90% задач? А Google Chrome?


      1. CodeRush
        11.12.2017 02:09

        Грубая оценка по опыту работы в другой большой компании похожего уровня.
        Из всего вышеперечисленного только Chrome уже написан, и браться его переписывать на Go с нуля нет никакого смысла, все остальное — почему нет? Для хардкорной математики все равно будут использованы готовые библиотеки на С или Фортране (FFI у языка есть, сопряжение хоть и не без проблем, но работает), а для основной grunt work язык Go вполне подходит. Они на нем теперь даже initramfs пишут, так что я не удивлюсь, если напишут и что-нибудь из ML (AI все же слишком сильный термин, на мой взгляд).


        1. third112
          11.12.2017 02:20

          Из всего вышеперечисленного только Chrome уже написан, и браться его переписывать на Go с нуля нет никакого смысла
          Помимо смысла: писать хороший GUI без богатого ООП очень трудно, хотя и возможно.
          AI все же слишком сильный термин, на мой взгляд
          Если assistant по замыслу не просто «болталка», вроде Элизы, то AI там нужен мощнее, чем сегодня доступен. Т.о. существующих библиотек явно недостаточно. Нужны собственные научные разработки. Аналогично про беспилотный автомобиль. (Или есть способ прятать внутри живого пилота :)


          1. khim
            11.12.2017 03:58

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

            Но GUI в Chrome в основном на JavaScript всё равно, так что тут скорее проблема в специфике продукта, а не в том, что GUI на Go сложно писать…


            1. TheShock
              11.12.2017 04:27

              в Go для написания GUI подходит куда больше

              Когда в руках молоток, все вокруг — гвозди


              1. khim
                11.12.2017 04:42

                Причём тут молоток? При создании GUI вам регулярно нужно связывать между собой разнородные обьекты.

                Что в модели ООП пропогандируемой С++/C#/Java сделать не так-то просто: недаром все C++ библиотеки так или иначе завязаны на кодогенерацию. Явную (как в MFC или Qt) или неявную (как в WTL — через шаблоны). В CLOS этой проблемы нет и, собственно, своременный GUI разрабатывался на этой обьектной модели ещё до того, как его увидел Jobs.


                1. mayorovp
                  11.12.2017 10:36

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


                  1. khim
                    11.12.2017 16:39

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

                    ООП в стиле CLOS, принятый в Go решает эту проблему абсолютно естественным способом: так как интерфейсы и их реализация напрямую не связаны с типами, которые их реализуют, то страшные трюки в стиле WTL (когда у вас обьект-предок приходится делать шаблонным, чтобы он мог как-то обратиться к потомку) не нужны.

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


                    1. mayorovp
                      11.12.2017 21:21
                      +1

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


                      1. khim
                        11.12.2017 21:52
                        +1

                        Замечание принято. Да, пожалуй в C# этой проблемы нет. Там среди прочего всякого добра напихано и решение этой проблемы тоже.


    1. daiver19
      11.12.2017 04:30

      Так вот, примерно 90% задач гугла вполне решается на этом самом «С для дураков» без использования кодогенерации, рефлексии, шаблонов, ООП и чего либо еще, и самое главное, что в итоге написанный разработчиками любого уровня код на Go смогут понять любые другие разработчики, даже если они в компании работают сутки и пришли сразу после ВУЗа.

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


    1. mersinvald
      11.12.2017 10:42
      +1

      Простота поддержки
      Спагетти-кода, который го провоцирует?

      простота отладки
      В копипасте?

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


    1. Source
      11.12.2017 22:35

      минимальные шансы выстрелить себе в ногу

      Ну да, как же… Gotchas and common mistakes in Go
      По количеству WAT Go может влёгкую побороться за второе место после JavaScript.


      1. khim
        11.12.2017 22:54

        По количеству WAT Go может влёгкую побороться за второе место после JavaScript.
        Только за третье и то не факт. Первое-второе места забиты намертво за JavaScript'ом и PHP, которые всё никак не выяснят какой из них кривее.


        1. batyrmastyr
          12.12.2017 09:09
          +1

          Хотите сказать кто вообще способен хотя бы догнать С++ и PL/1? Что-то во времена студенческие я не видел ни одного учебника по С++ (в особенности от авторов языка) в котором хотя бы 4/5 примеров компилировались, а с тех пор в язык только добавляют и добавляют новые способы стрельнуть себе в ногу.


          1. khim
            12.12.2017 11:00
            -3

            Что-то во времена студенческие я не видел ни одного учебника по С++ (в особенности от авторов языка) в котором хотя бы 4/5 примеров компилировались
            Если что-то не скомпилировалось — так это ж хорошо: вы увидите проблему и её исправите. Это вообще не проблема.

            А вот если оно скомпилировалось и делает не то, что ожидалось… это бяда. В этом отношении JavaScript и PHP не переплюнуть… хотя C++ и старается, да.


            1. mayorovp
              12.12.2017 11:01
              +2

              Пример-то я исправлю, но я не могу исправить учебник. А кто-то по нему учится…


            1. VolCh
              12.12.2017 14:38

              Если что-то не скомпилировалось — так это ж хорошо: вы увидите проблему и её исправите. Это вообще не проблема.

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


              1. khim
                12.12.2017 16:52

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


                1. VolCh
                  12.12.2017 16:57

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


                  1. khim
                    12.12.2017 18:25
                    +1

                    Несомненно. Но с учётом того, что у меня есть знакомый, который отличненько осваивал курс, написанный под Turbo C 2.0 с использованием последней версии GCC и Clion… я думаю что проблема-таки в издателях… Ну или в горе-программистах, которые в учебных примерах используют всякие <conio.h>, которые большинством компиляторов никогда не поддерживались.


            1. sumanai
              12.12.2017 19:48
              +1

              В этом отношении JavaScript и PHP не переплюнуть… хотя C++ и старается, да.

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


              1. khim
                13.12.2017 08:43

                Теоретически — да. А практически — в типичном web-магазинчике будут десятки миллионов строк кода на C/C++ (не только ядро операционной системы, но и всякие SQL-базы данных, акселераторы и прочее — это ведь всё на C/C++ написано), а сверху — тысяч сто строк на PHP или Ruby. При этом на каждую дыру в ядре будет пара SQL-уязвимостей в движке.

                Так что да — указатели они, конечно, ужасны и опасны, но до уровня JavaScript/PHP — не дотягивают…


                1. sumanai
                  13.12.2017 16:09

                  Вы серьёзно сравниваете вылизанный код ОС, интерпретатора и БД, используемый на миллионах инсталяций, с уникальным наколеночным кодом студента на подработке (утрирую)?


            1. batyrmastyr
              13.12.2017 11:13

              Это был толстый намёк, что даже авторы стандарта не знают его от и до и (sic!) раз даже простой пример набрать без ошибок не могут. А без полноценного понимания языка говорить о совместимости его функций (= отсутствии косяков в дизайне) как-то смешно.
              В этом смысле php намного лучше — пространства для косяков меньше, дефекты дизайна постепенно исправляются, глупости перестают интерпретироваться (в отличие от С++).


  1. creker
    11.12.2017 01:05

    И кто теперь более читабельный? Я отдам свой голос D. Его код куда более читаемый, так как он более явно описывает действия.

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

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

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

    Из всей статьи только дженерики адекватная критика. Их недостает и interface{} нужно всеми силами как-то выпиливать из стандартной библиотеки. «культурный багаж Си» так вообще ересь. Инкапсуляция и абстракция достигается через интерфейсы. Еще большая ересь это критика процедурного стиля. Какая разница как он ощущается, если этот стиль программирования понятен и прост для чтения?

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


    1. SirEdvin
      11.12.2017 01:08

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


      1. creker
        11.12.2017 01:16

        Потому что нормальная система пакетов обычно зависит от стороннего сервиса, на который надеяться себе же дороже. Не так давно уже была забавная история с node.js что ли, когда удалили безобидный пакет. Банально интернет может не работать и что, вся компания будет сидеть и ждать его возвращения? В конечном итоге приходит понимание, что наверное стоит поднять тот же самый сервер локально, чтобы он хотя бы кэшировал зависимости. Либо окончательное прозрение, что стоит все зависимости тащить с собой в репозиторий в отдельной папочке «vendor». Судя по всему, компании уровня Гугл и даже куда меньше именно к последнему и приходят. Конечно, не идеал и не удобно бывает, но вариантов других особо нет.


        1. SirEdvin
          11.12.2017 01:59

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


          1. arteast
            11.12.2017 09:22

            Видимо, гугл считает, что им удобнее вот так. У них, к примеру, весь C++ код хранится в едином репозитории и собирается целиком. Казалось бы, милое дело — выделить модули, каждый модуль разрабатывать независимо в своем репозитории (и секюрность, и размер репо и билда уменьшить, и команды друг другу мержи и билды ломать не будут), стабильные оттестированные релизы пакетировать и выкладывать на тот же внутренний сервер — красота, все по святцам! Но нет, гуглу оказалось объективно лучше держать все в одной куче и жить на "острие".
            Есть такая поговорка "ты не гугл". То, что может казаться (и быть) хорошим и приятным для нас с вами, для компании такого размера может был плохим и вредным. В частности, таким вредным они считают версионирование пакетов. Что логично — нетрудно обеспечить совместимость версии, если у тебя собирается пакет, зависящий от еще пары. Когда у тебя собираются тысячи и десятки тысяч пакетов, зависящих друг от друга, то менеджмент совместимых версий превращается в ад.


            1. SirEdvin
              11.12.2017 10:26

              Когда у вас так много пакетов, у вас все равно ад.


              Лично мне кажется, это потому, что google в целом может положить большой болт и тестировать новый функционал на 10% клиентов. Далеко не все компании так могут, так как не монополисты все-таки :)


            1. bogolt
              11.12.2017 10:50

              размер билда? В плюсах же по идее ты не платишь за то что не используешь.


              1. arteast
                11.12.2017 14:32

                Я о суммарном размере билда. Если кто-то изменяет библиотеку в модульной архитектуре, то им надо только проверить, что она собирается; сборка, проверка вышестоящих библиотек — это задача тех, кто будет обновлять зависимости. Если кто-то изменяет библиотеку в гугле, то им надо собрать всё, что ее использует, и поправить всё сломавшееся. Гугл, НЯЗ, использует виртуальную ФЗ (как ClearCase MVFS, чтобы не убивать место на HDD и время программистов миллионами файлов из репо), распределенные билды и хитрые билд-системы, чтобы скорость билдов была адекватной, но билды все равно должны быть сделаны и артефакты все равно должны куда-то упасть.


                1. khim
                  11.12.2017 16:48

                  Если кто-то изменяет библиотеку в модульной архитектуре, то им надо только проверить, что она собирается
                  А работоспособность кто проверять будет? Пушкин?

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

                  Когда у вас между проектами — административная граница, то у вас, в общем-то, нет выбора. Но если её нет — общий репозиторий лучше. Собственно все большие проекты так всегда и собирались — и UNIX, и OS/360 и многие их последователи.

                  Только GNU/Linux, по политическим причинам, устроен не так. Ну так то — вынужденная мера, а не то, к чему стоит стремиться.

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


                  1. arteast
                    11.12.2017 18:03

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

                    Но если её нет — общий репозиторий лучше.
                    Я с этим спорю, что ли? Я говорю, что для "нас с вами" (use-case типичный опен-сорс проектик) удобнее релизы и версионируемость. Для гугла — удобнее монорепозиторий и жизнь на "голове". Go — язык гугла для гугла; логично, что они использовали для зависимостей в Go ту же философию. Поэтому и статья в целом ("мне Go не нравится, а я знаю D умный программист => Go не для умных программистов"), и тот комментарий, на который я отвечал ("для меня пакеты удобнее => Go нужны зависимости в пакетах, а не голова репозитория"), мне кажутся наивными. Я попытался намекнуть, что у гугла может быть точка зрения, отличная от ТЗ типичного Васи Пупкина, но это не оценили.

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


          1. arvitaly
            11.12.2017 09:48

            С версиями вот такие рассуждения.

            У нас есть некий код, допустим он типизирован и есть внешний интерфейс у импортируемого модуля.
            Что в таком случае будет означать изменение версии?
            Изменение API модуля? Совсем не обязательно (в semver это предполагает лишь в мажорных версиях). А что тогда? Непонятно, все равно придется проверять, что же изменилось вручную.
            Получается, что система версий не типизируется, а значит не автоматизируется.
            А значит, весь вопрос уже заключается в том, как вести для людей лог изменений модуля, и я вовсе не уверен что безликие 3 циферки что-то значат.
            И логика без цифр такая.
            Если это внутреннее изменение (ну, фикс безопасности, к примеру), то и не нужны никакие новые цифры. Если изменение API, то, опять же, компилятор должен ругнуться. Если изменения API нет, но поведение изменилось — нужно менять название пакета, а старый оставить в покое, обратная совместимость, все дела.
            Привязка же к коммитам удобна при параллельной разработке, но внутри одной компании.

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


            1. SirEdvin
              11.12.2017 10:24
              +1

              Версионность выполняет ровно две функции:


              • Человекочитаемость. Когда я вижу, что пакет версии 2.1.5, а я использую версию 0.5.1, то мне надо обновится (и вполне вероятно, поиметь проблем). А когда я вижу, что использую коммит 249f069bdf09be30258c604be27fdce51694706f вместо 249f069bdf09be30258c604be27fdce51694706f это мне ни о чем не говорит.
              • Исправность. Есть такая штука, что далеко не у всех людей каждый коммит содержит код, который вообще собирается. А каждая версия программы должна собираться, без этого никак.

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


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


              1. atomAltera
                11.12.2017 14:49

                Вы специально одинаковые хэши написали?


                1. SirEdvin
                  11.12.2017 14:50

                  Хм… нет, криво скопировал.


              1. khim
                11.12.2017 16:52

                Есть такая штука, что далеко не у всех людей каждый коммит содержит код, который вообще собирается.
                И вот «с этой штукой» и нужно бороться. Trybots для этого и существуют.

                Более того, версионность позволяет не только жестко фиксировать версии, но так же и задавать диапазоны версионности, что бы у вас не возникало по три-пять разных версий пакетов в одном и тот же проекте.
                Откуда у вас возьмутся «три-пять» версий пакетов (и вообще пакеты, как таковые) при использовании одного репозитория? Или вы про master/release/release-stable и т.п. ветки? Ну так они «внутри себя» все согласованы…


                1. SirEdvin
                  11.12.2017 16:55

                  Откуда у вас возьмутся «три-пять» версий пакетов (и вообще пакеты, как таковые) при использовании одного репозитория? Или вы про master/release/release-stable и т.п. ветки? Ну так они «внутри себя» все согласованы…

                  Давайте начнем с простого. Если вы работаете в google/facebook/another company где все проекты лежат в одном репозитории (на самом деле в google и facebook это уже тоже не так, у них есть open source) и вообще никак не завязаны на open source либы — я за вас рад.


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


                  1. khim
                    14.12.2017 08:40
                    -3

                    на самом деле в google и facebook это уже тоже не так, у них есть open source
                    Угу — и это позволяет посмотреть как всё устроено.

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

                    Когда вы скачиваете себе два разных проекта к себе в репозиторий, то они обязаны работать с той версией пакетов, что у вас есть. Можете посмотреть в Chrome или Android: пакеты там не дублируются (за исключением резко патологических случаях типа AngularJS vs Angular, или Pel5 vs Perl6 где разные «версии» лучше рассматривать не как разные версии одного и того же, а два совершенно разных продукта).

                    Вот чтобы такую проблему не решать Go по умолчанию и берёт всё из trunk'а. Если ваши пакеты, в результате, не заведутся и не заработают — ну да, можно попробовать накостылить что-нибудь. Но по умолчанию — все пакеты должны использовать одной версии. Самой последней.


                    1. TheShock
                      14.12.2017 08:46
                      +3

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


                      1. arvitaly
                        14.12.2017 09:20

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


                        1. TheShock
                          14.12.2017 09:56
                          +4

                          Я разрабатываю какой-то продукт и использую множество библиотек. Делаю `go get` и скачиваю из транка новые версии библиотек. Оказывается, что в одной зависимости нескольких моих зависимостей сломалась совместимость. Теперь моя разработка стоит пока все эти библиотеки не пофиксят совместимость с той, что внесла изменения?

                          Обращу внимание, что gitflow не отрицает изменений, ломающих совместимость. То есть в мастер вполне может прилететь такая версия.


                          1. khim
                            14.12.2017 12:53
                            -2

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

                            Обращу внимание, что gitflow не отрицает изменений, ломающих совместимость. То есть в мастер вполне может прилететь такая версия.
                            Ничего не знаю про gitflow. Знаю что в gerrit есть кнопочка rollback, которая откатывает изменения без вытаскивания их в клиент и прочего. Вот именно на случай, когда в trunk попало что-то, что сломает кучу клиентов.


            1. mersinvald
              11.12.2017 10:45

              SemVer.


            1. vintage
              11.12.2017 11:16

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


              unsafePtr у шарпа и явы дженерики — это не шаблоны, а полиморфные типы.


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


      1. JekaMas
        11.12.2017 01:35

        Потому что создателям go "далеко за ..." и многое им видится "ненужным, излишним", после проходят годики и начинаются писаться статьи вроде Dave Chany и техническом долге go и том, что если язык назвался mainstream, то от него ждут определенных вещей: управление зависимостями, generics. Но создатели языка действуют в формате "если мы сомневаемся, то не делаем ничего и ждем".
        Язык golang великолепен в большом поле задач и за год вполне можно взгрустнуть об отсутствии обобщенных типов лишь раз или два(грусть чаще накатывает от фанатов golang). Но вот станет ли язык mainstream — вопрос открытый.
        По мне, несмотря на все громкие заявления о том, как будут вводиться изменения в язык (а таких заявлений была масса в 2017 году), развитие языка в 2017 провалилось: невнятный и непродуманный контекст, поломанные плагины (эпичная "бага" с тем, что они не работают нигде, кроме unix), алиасы, sync.map — это скорее недоразумения, чем развитие языка.
        Но время покажет.


      1. Rasifiel
        11.12.2017 05:56

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


    1. Idot
      11.12.2017 08:20

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

      А можно, пожалуйста, подробнее для тех кто не в курсе?


    1. acmnu
      11.12.2017 12:03

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

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


  1. TexxTyRe
    11.12.2017 01:23

    Не понял: в статье ругают Go или рекламируют D? Объясните, я просто dumbed down (из Google).


    1. mrobespierre
      11.12.2017 03:11

      ругают Go или рекламируют D?

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


      1. mrobespierre
        12.12.2017 17:04

        [offtop]
        минусующие (как здесь, так и в карме) могли бы и высказать в чём я не прав, аргументами меня задавить, а не так — плюнул в спину и убежал
        [/offtop]


        1. VolCh
          12.12.2017 17:05
          +4

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


          1. mrobespierre
            13.12.2017 04:04

            [offtop]
            Спасибо, мил человек, никогда бы и в голову не пришло, что на Хабре есть целый профсоюз «Защиты британских троллей от оскорблений за откровенно тупые набросы с интами». Буду знать.
            [/offtop]


  1. m68k
    11.12.2017 01:25

    Как можно было, например, написать утилиту:

    Заголовок спойлера
    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    	"os"
    )
    
    func main() {
    	var err error
    	reader := os.Stdin
    	if len(os.Args) > 1 {
    		if reader, err = os.Open(os.Args[1]); err != nil {
    			panic(err)
    		}
    	}
    	text, err := ioutil.ReadAll(reader)
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(string(text))
    }
    


    1. JekaMas
      11.12.2017 01:42

      Вам доводилось пользоваться кодогенерацией в своих проектах? Довольно муторное, ненадежное и небыстрое занятие. По мне, это сваливание ответственности с компилятора на пользователей, особенно в части гарантий работы.
      Стоит в проекте появиться 5-10 активно используемым кодогенераторам и появляется чувство, что он обложен черными ящиками, в которых могут быть ошибки, подчас трудно отлавливаемые — разбирать сгенеренный код бывает нелегко. Вместо одного гарантированного решения задачи с обобщенными типами получается зоопарк из разных пользовательских решений, которые надо поддерживать. Это банально дорого.
      Кодогенерация, на мой взгляд, это не решение, скорее затычка "вы так хотели generics — нате!"


      1. khim
        11.12.2017 02:06

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

        И 5-10 кодогенераторов — это 5-10 скриптов, которые что-то генерируют или 5-10 типов кодогенераторов (ну там ragel, bison, flex и т.д. и т.п.)? 5-10 типов (каждый со своим языком и описанием) — это уже перебор… собственно Go потому и появился чтобы всякие бесконечные Sawzallы не генерить в бешенных количествах…


        1. SirEdvin
          11.12.2017 02:25

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


          1. Falstaff
            11.12.2017 02:34

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


            1. SirEdvin
              11.12.2017 02:42

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


              1. Falstaff
                11.12.2017 03:04

                Зависит от кодогенерации (мы ведь просто о дженериках говорим). Я не настолько хорошо знаю Go, но вроде там есть какой-то инструментарий кодогенерации прямо из коробки. Понятно что, чем сложнее генерация, тем сложнее поддерживать, но вопрос инструментария — это уже частности, я просто говорил, что под капотом разницы нет, в C++ тоже кодогенерация, и программист сгенерированный код не читает, ему приходится пользоваться головой и инструментами, какие есть. Причём и там не всё радужно, шаблонный код часто совсем неподдерживаемый а сообщения об ошибках в шаблонном коде — нечитаемая портянка на весь экран. :)


                1. l4l Автор
                  11.12.2017 03:10

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

                  Каша из логов шаблонного кода со временем превращается в понятное (пусть и все еще большое) чтиво, сам в это когда-то не верил. Ну и вообще говоря можно получить код с инстанциированными шаблонами (e.g clang -Xclang -ast-print -fsyntax-only ...), вдобавок отладчики уже давно выводят типы


                  1. Falstaff
                    11.12.2017 03:18

                    Ну, весь вопрос — сколько времени понадобится, чтобы превратилась в понятное чтиво. :) По сути это тоже перенос нагрузки на мозг разработчика. Поддержка тоже местами хромает — в CLion у меня, например, целая куча красного кода из-за С++14, если говорить об IDE.


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


                  1. unsafePtr
                    11.12.2017 04:14

                    Для сравнения возьмите дженерики из c#, нету там всяких танцев с бубном.


                  1. 0xd34df00d
                    12.12.2017 00:03

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

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

                    вдобавок отладчики уже давно выводят типы

                    Это если у вас код таки собрался.


                1. alexeykuzmin0
                  12.12.2017 18:08

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


            1. l4l Автор
              11.12.2017 02:52

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


            1. 0xd34df00d
              11.12.2017 23:58

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

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


              1. Falstaff
                12.12.2017 15:34

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


                1. 0xd34df00d
                  12.12.2017 19:33

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


        1. JekaMas
          11.12.2017 02:56

          Неправда ли любопытно: кодогенерация — это рекомендуемый путь, но стоит им пойти и начинаются проблемы.
          Так в прошлом проекте использовались генераторы: msgpack для aerospike, easyjson, для клонирования объектов, локальный типизированный кэш, генератор клиента на основе api. Некоторые проекты использовали большее число.
          Иногда в сгенерированном коде находились ошибки и тут приходится читать этот код. Но кодогенераторы пишут кто во что горазд (в общем-то и понятно — это просто сторонние пакеты, стандарта на них нет) и разбираться в таком хозяйстве долго и дорого.
          Для меня, кодогенерация — это перекладывание ответственности и гарантий с больной головы на здоровую.


          1. khim
            11.12.2017 04:07

            Для меня, кодогенерация — это перекладывание ответственности и гарантий с больной головы на здоровую.
            А какая альтернатива? Шаблоны? Ну так это то же самое, только ещё хуже. Потому что там всё точно также генерируется — только неявно. Причём в случае с кодогенерацией вы можете увидеть и понять — что происходит просто открыв сгенерированный код. А если при открытии сгенерированного файла у вас IDE сжирает несколько гиг памяти, то сразу возникает вопрос: а оно точно нам нада — то при использовании шаблонов можно заметить что «что-то пошло не так», только обнаружив, что линкеру 16GB памяти не хватает и нужно ставить 32GB только чтобы получить один бинарник на гигабайт…

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


            1. 0xd34df00d
              12.12.2017 00:08

              Дженерики как в хаскеле. Это не шаблоны в смысле плюсов и не template haskell в смысле полноценной компил-тайм-манипуляции AST, а просто реализация наблюдения, что типы данных обычно изоморфны рекурсивным кортежам. Через это можно и хеши делать, и операции сравнения, и вывод на экран, и жсон, и БД, и вообще большую часть того, что надо от кода, претендующего на манипуляции с AST и всяким таким.

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


    1. Zanak
      11.12.2017 12:58
      +1

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

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


      1. mayorovp
        11.12.2017 12:59

        Более того, пример javascript убедительно показывает, что именно инкапсуляция-то в ООП и вовсе оказалась необязательна :-)


        1. VolCh
          12.12.2017 06:54

          Вы про активное использование штук типа bind?


          1. mayorovp
            12.12.2017 07:00

            Нет, про отсутствие приватных свойств у классов.


            1. Aleosha
              12.12.2017 11:31

              Incapsulation в JS используется, просто всякими Module Design Pattern'ами и прочими трюками с closure'ами.


              1. mayorovp
                12.12.2017 12:21

                Используется-то используется, но не требуется.


            1. VolCh
              12.12.2017 14:38

              Я слонен разделять инкапсуляцию и сокрытие.


        1. Zanak
          12.12.2017 13:52

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


  1. truebest
    11.12.2017 01:25

    Самым главным в программировании я считаю это умение решать задачи. Для решения задачи есть инструменты, и язык это инструмент, в частности, go тот язык, которым быстро можно овладеть. С моей точки зрения нужно использовать инструмент, который быстрее приведёт вас к решению задачи. Кроме того есть ряд известных преимуществ языка GO, например производительность, в отличие от JAVA.
    Предположим что вы решаете задачу, ту, которую до вас не решал никто, на каком языке она будет решена — неважно, важно что решена, именно это и определяет потенциал человека. Простой пример, это гений Перельман, который блестяще решил теорему Пуанкаре. В вашем же случае, умные программисты — это программисты с завышенным ЧСВ. Или как это сейчас модно, знающие лайфхаки, в языках, из разряда, как сделать чтобы коврик в туалете не уезжал из под ног. Именно этот набор знаний, вы и выдаёте за ум.


    Более 8-ми лет я пишу прошивки под разные микроконтроллеры, и конечно же на си, который я знаю также, как истинные верующие отченаш. Когда нужно организовать простенький сервер, для приема и обработки данных с железки, я часто пользуюсь Go. И здесь вопроси умения возникает мало. Другое дело, когда нужно помочь с реализацией на Java, или Android. Из-за ООП, мне гораздо сложнее, тк мне необходимо продумать по сути архитектуру и структуру классов. Это даётся мне сложнее, но только по тому что это не основной мой навык.


    1. third112
      11.12.2017 02:40

      конечно же на си

      А почему не на ассемблере? Значит для Вас важен язык. Это, на мой взгляд, противоречит Вашим словам:
      на каком языке она будет решена — неважно


      1. EvilBeaver
        11.12.2017 06:19

        Си — это и есть кроссжелезочный ассесблер


        1. youlose
          11.12.2017 09:51

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


          1. humbug
            11.12.2017 11:03

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


      1. truebest
        11.12.2017 11:12

        Можно и на ассемблере, только у каждой архитектуры свой набор команд. А это время. Если в задача — максимально короткое и эффективное время исполнения (лучше чем скомпилировал бы компилятор си), я использую ассемблер. Сейчас любой компилятор позволяет комбинировать си и асм, опять же для удобства и быстроты реализации задачи.
        Время это очень ценный ресурс.
        Поэтому для меня важно умение решать сложные задачи за максимально короткое время. Поэтому в Go я гораздо быстрее разберусь чем в JAVA


      1. bevice
        12.12.2017 12:30

        На С потому что для микроконтроллеров это без вариантов, если вы не хотите заниматься извращениями и нужна хорошая производительность. Не плюсы, потому что ABI нужно дописывать, он платформозависим. Asm для критически-важных (по скорости) секций, хоть это и значит, что запас минимален и кристалл выбран неправильно.
        Да, можно сейчас на LUA писать «прошивки», но когда нужна прямая работа с памятью (записать такой-то бит в ячейку с таким-то адресом), или когда на практике знаешь, зачем нужны volatile-переменные, С просто удобнее.



  1. third112
    11.12.2017 01:44

    Еще одна скрипучая проблема в том, что Go — это процедурный язык (подобно тихому ужасу Си). В итоге начинаешь писать код в процедурном стиле, который чувствуется архаичным и устаревшим. Я знаю, что объектно-ориентированное программирование — это не серебряная пуля, но это было бы здорово иметь возможность абстрагировать детали в сами типы и обеспечить инкапсуляцию.
    Интересно, что и в упомянутой книге (перевод) слово «объект» встречается три раза, а слово «класс» — только два: первый раз не по делу, а второй раз:
    В Go есть несколько различных типов для представления чисел. Вообще, мы
    разделим числа на два различных класса: целые числа и числа с плавающей
    точкой. (С.15)
    Но если верить Википедии, Go — ОО язык (в отличае от Си):
    Специальное ключевое слово для объявления класса в Go отсутствует, но для любого именованного типа, включая структуры и базовые типы вроде int, можно определить методы, так что в смысле ООП все такие типы являются классами.
    Из дальнейшего текста вики видно, что принципы ООП понимаются в этом языке довольно своеобразно.


    1. khim
      11.12.2017 02:14
      +1

      Из дальнейшего текста вики видно, что принципы ООП понимаются в этом языке довольно своеобразно.
      Они понимаются примерно как в CLOS. Который является вполне себе ООП-языком — и гораздо более гибким, чем C++/C#/Java…


  1. lynch513
    11.12.2017 03:21

    Вот взять например язык для «умных» и выразить вторую задачу:

    putStrLn $ show $ foldl1 (+) [1, 2, 3.3]
    

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

    Хорошо решим первую задачу:
    import System.Environment
    import Data.Char
    main = getArgs >>= printFile
        where printFile (x:_) = readFile x >>= putStr
                   printFile [] = getContents >>= 
                       readFile . filter (not . isControl) >>= 
                           putStr
    

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


    1. l4l Автор
      11.12.2017 03:41

      Первый пример крайне просто читается, даже человеком со знанием английского (при условии, что он догадается, что str -> string и foldl -> fold).
      Второе уже требует знания монад и ФП, тогда не должно являться большой проблемой.


      А что касается времени на написание — то ФП, это, по моему опыту, совсем другие дебри. "Что-то накидать хоть немного работающее и сделать это быстро" — явно не про оное. Так что думаю сравнение не очень уместно. Впрочем, мой опыт может быть и не столь обширен


      1. 0xd34df00d
        12.12.2017 00:21

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


    1. 0xd34df00d
      12.12.2017 00:21

      Зачем foldl1 (+), когда есть sum, который уже давно работает поверх произвольного Foldable?

      И я бы второй пример переструктурировал немножко:

      main = getArgs >>= file >>= readFile >>= putStr
          where file (x:_) = pure x
                file [] = filter (not . isControl) <$> getContents
      


      1. lynch513
        12.12.2017 19:37

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

        main = do
            args <- getArgs
            stdIn <- getContents
            let file = if null args
                            then filter (not . isControl) stdIn
                            else head args
            content <- readFile file
            putStr content
        

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


        1. 0xd34df00d
          12.12.2017 19:50

          Только сколько людей могут предложить такой вариант?

          Всё дело в эстетике :) У вас вот putStr в обоих ветвях повторяется, поэтому естественный вопрос: а можно ли его как-то оттуда вынести и обобщить, например? Вынесли, теперь readFile повторяется. И так далее.

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

          Любой, кто знает, что такое монада (когда я только изучал хаскель во времена ghc 6 и задолго до applicative/monad proposal, равно как и задолго до моего упарывания теоркатом, помню, сильно удивлялся, почему Monad не является субклассом Applicative). Но да, я согласен, таких людей меньше, чем программистов на Go.

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

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


        1. humbug
          12.12.2017 19:59

          Ребят, а как такое тестировать?


          1. 0xd34df00d
            12.12.2017 20:01
            +1

            А что именно тут тестировать?


          1. TheShock
            13.12.2017 03:08

            Никак, люди так пищущие — не допускают ошибок


            1. humbug
              14.12.2017 07:48
              +1

              Ну-ну. Самоуверенные и самовлюбленные нарциссы.


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


              1. TheShock
                14.12.2017 08:27
                +1

                Эх, неужели это было слишком тонко?


  1. Terras
    11.12.2017 06:04

    Go изначально разрабатывался для того, чтобы переписать тормознутые сервисы на python/php/perl, и не отстрелить себе ноги на (C/C++). Что этот язык и сделал. То, что из него стали делать вундервафлю под все задачи (как это в свое время делали из node.js) — просто хайп.

    Что касается сравнения GO с другими языками, в частности Java, то Google разработала Go и начала его активно использовать, чтобы отказаться от зависимости от Oracle. Заметьте одну вещь.

    • Oracle — Java
    • Microsoft — C#
    • Google — Go
    • Facebook — php (php Hack)
    • Apple — Object-C/Swift


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

    Сейчас Google замкнет всю свою систему на GO и станет таким же вендор локом, как и Microsoft, как Apple и прочее =)


    1. AngReload
      11.12.2017 10:31
      +1

      Можно ли дополнить список Mozilla с её Rust? Кажется, новые языки создают все кто может.


    1. JekaMas
      11.12.2017 11:21

      У go не получилось в этом смысле — проект go-mobile скорее мертвый, чем живой, и сам Google для мобильной разработки советует Kotlin.


      1. dmbreaker
        11.12.2017 12:31

        Устарело.
        Гугл для мобильной разработки советует Dart


        1. JekaMas
          11.12.2017 12:56

          Ок, скажем тогда иначе, «что угодно, но не go-mobile».


        1. Divers
          11.12.2017 15:28
          +1

          Где и кому они такое советуют?


        1. vopper
          11.12.2017 19:30

          можно по подробней?


          1. dmbreaker
            13.12.2017 19:14

            flutter.io


    1. ffriend
      11.12.2017 17:35

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

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


      К тому же, потребность в своём собственном языке никак не влияет на дизайн этого языка. Задачи Google не так сильно отличаются от задач тысяч других компаний — (микро)сервисы с максимальной утилизацией CPU и памяти. Это объясняет горутины, например. Стремление к простоте изучения и близости к C тоже понятна, учитывая тысячи работающих у них студентов, хотя для многих других компаний это свойство языка может быть совершенно ненужным или неуместным. А вот замена дженериков на кодогенерацию или использование зависимостей без чёткого версионирования лично для меня ну совсем непонятны.


  1. Bookvarenko
    11.12.2017 07:17

    Отлично! Как-раз искал что-то вроде С для дураков. Ещё и с книжкой сразу. Спасибо!


    1. mrobespierre
      11.12.2017 07:47
      +1

      Если нужна книжка по Go — смотрите в сторону Кернигана (а вот его сишную лучше не читать).


      1. Bookvarenko
        11.12.2017 12:43

        Спасибо! А библиотеку для обмазывания цветом и рамочками вывода в консоль какую лучше использовать?


        1. mrobespierre
          11.12.2017 16:24

          Если я вас правильно понял, то вы хотите ncurses для Go. Так вот, его нет. Попытки были, но когда я пробовал — всё было не оч. Если сильно хочется некомандный интерфейс, то стоит смотреть в сторону http. Серьёзно, 5 минут делов, всё необходимое уже есть в стандартной библиотеке, нет проблем с переносимостью. Если не устраивает — стоит спросить другие варианты у коллективного разума в русском Go Slack сообществе.


          1. Bookvarenko
            11.12.2017 17:01

            Спасибо! Попробую непременно оба совета.



      1. eliduvid
        11.12.2017 21:07
        +1

        А что не так с сишной?


  1. linuxover
    11.12.2017 09:48
    +1

    Вот, к примеру, решение той же задачи на D:

    вот к примеру решение той же задачи на Perl:


    while (my $line = <>) {
        print $line;
    }

    или даже короче:


    while (<>) {
       print;
    }


    1. cdump
      11.12.2017 11:21

      print while(<>);


      1. linuxover
        11.12.2017 11:45

        тогда уж без скобок. :)


        print while <>;


  1. vintage
    11.12.2017 10:05

    void main(string[] args)
    {
        try
        {
            auto source = args.length > 1 ? File(args[1], "r") : stdin;
            auto text   = source.byLine.join.to!(string);
    
            writeln(text);
        }
        catch (Exception ex)
        {
            writeln(ex.msg);
        }
    }

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


    void main(string[] args)
    {
        auto source = args.length > 1 ? File(args[1], "r") : stdin;
        source.byLine.writeln;
    }



    void main(string[] args)
    {
        [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
    }

    Этот код можно ещё упростить:


    void main(string[] args)
    {
        [1, 2, 3, 4, 5].reduce!q{ a + b }.writeln;
    }

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


    void main(string[] args)
    {
        [1, 2, 3, 4, 5].sum.writeln;
    }


  1. UA3MQJ
    11.12.2017 10:13

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


    1. linuxover
      11.12.2017 11:50

      а с чем?


      если говорить об утилизации одного CPU и читабельности кода, то все рано или поздно приходят к тому что калбек-лапша это хелл, приходят к переключению контекста руками — yield/cede, корутины.


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


      если говорить о соединении двух подходов — получаем примерно то же самое: сопрограммы/корутины (чтоб читабельно) + каналы (чтоб межпроцессно). Что Go из коробки и предоставляет.


      да у Go море недостатков, но Вы говорите — есть лучшие альтернативы.
      лучшие это какие?
      python, perl, прочие — это все языки одного CPU. прекрасные, но одного CPU
      Erlang — язык прекрасный, но порог вхождения ужасен. Как объяснить кому-то что понятия переменная нет и это хорошо — хз.
      Хацкель — это уже совсем фанатам.


      что еще?


      1. UA3MQJ
        11.12.2017 12:59
        +1

        А если не переключить контекст руками — он так и будет принадлежать горутине, пока она его не отдаст (не вызовет yield либо внешнюю функцию). Есть возможность зациклить горутину и потерять один тред насовсем.
        Не планируется ли введение в рантайм каких то механизмов для идентификации процессов горутин с возможностью их принудительного завершения работы?
        По поводу каналов — да, это типичное решение для обмена. Но мне ближе обмен сообщениями между процессами с почтовыми ящиками (заумно — модель акторов). Я не критикую каналы, просто CSP и Акторы — это разные вещи, со своими особенностями. Мне в каналах не нравится то, что канал — это дополнительная сущность; факт того, что отправляющий процесс блокируется, если на той стороне канала не читают, умерла горутина.
        Да, я в курсе, что в Go это стараются решить. И я буду рад узнать о том, что решили.
        Альтернативы всегда есть, но всегда можно найти причины, по которым эти альтернативы вам не подойдут.


        1. linuxover
          11.12.2017 13:26

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

          и это же хорошо. Ну а безо всяких go пользователь на любом языке может написать while true; do nothing(); done и отстрелить тред/процесс насовсем. Но мы же обсуждаем языки, а не тех кто этими языками себе что-то отстреливает?


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

          не очень я понял при чем тут акторы. я говорил о транспорте данных между процессами. при обмене данными между процессами: можно класть их в shared memory около которой mutex. Можно гнать данные через канал/пайп/сокет. Больше способов не придумали пока.
          А как оно оформлено поверх транспорта — актор там или не актор — дело десятое


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

          дык каналы с заданным размером решат эту проблему. Или даже резиновые каналы.


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


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

          задача стоит IPC между процессами. Вариантов всего два: mutex (варианты) + shared memory. Здесь в полный рост проблема стоит взаимных блокировок, производительности, сетевого масштабирования. Второй вариант — пайпы (сокеты/каналы итп). Здесь та же проблема взаимных блокировок (что Вам не нравится) + буфферизации каналов (появляется понятие "данные в пути").


          есть еще какие-то альтернативы?


          1. UA3MQJ
            11.12.2017 14:00

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


            1. linuxover
              11.12.2017 14:06

              1. исправить код вызывающий ошибки (за разработчика это никто не сделает)
              2. перезапустить (написать перезапускатор), опять же за разработчика никто это не сделает

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


              1. UA3MQJ
                11.12.2017 14:07

                То есть, перезапустить всё приложение целиком. Я понял, спасибо.


                1. linuxover
                  11.12.2017 14:11

                  горутину можно перезапускать по критериям же.


                  1. UA3MQJ
                    11.12.2017 14:27

                    Направьте, пожалуйста, где почитать.


                    1. linuxover
                      11.12.2017 14:29
                      +1

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


              1. JekaMas
                11.12.2017 16:03

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


                1. koluchiy01
                  13.12.2017 13:47

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


                  1. JekaMas
                    13.12.2017 13:50

                    Оно так не работает)
                    Попробуйте набросать пример — будет любопытно посмотреть.


                    1. koluchiy01
                      13.12.2017 15:38

                      Все верно, завершать работу, должна уметь горутина.


                  1. JekaMas
                    13.12.2017 14:35

                    Попробовал набросать пример на основе документации на context — play.golang.org/p/7BHDtAgVMn
                    Попробуйте запустить на локальной машине и посмотреть итог (в песочнице должен быть deadlock поскольку там только один thread и он будет сразу заблокирован).
                    Context.Cancel может оповестить горутины о том, что пора `Done()`, но он не может прервать их выполнения. Такого механизма в go нет.

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


                1. GeckoGreen
                  13.12.2017 14:39

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


                  1. JekaMas
                    13.12.2017 14:56

                    Не совсем верно, до 1.5 вполне была возможность прерывать выполнение горутины. Да, через unsafe, но была, после ее убрали.
                    Время от времени проверять можно, если операцию можно разбить на отдельные части, между которыми делать проверки. Но как итог мы усложняем код на порядок.
                    Как правило остается только смириться с тем, что механизма для early stop и сохранения ресурсов нет и не будет.


                    1. khim
                      13.12.2017 16:06
                      +1

                      Как правило остается только смириться с тем, что механизма для early stop и сохранения ресурсов нет и не будет.
                      И слава богу. В C++ мире от pthread_cancel тоже, в общем, отказались.

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


          1. UA3MQJ
            11.12.2017 14:06

            не очень я понял при чем тут акторы. я говорил о транспорте данных между процессами.
            arild.github.io/csp-presentation
            Слайды 10, 11, 12.


            1. linuxover
              11.12.2017 14:10

              на слайде 10 справа нарисован аналог канала, ага.
              на транспортном уровне все сводится к двум вариантам:


              1. shared memory + mutex
              2. pipe

              а "актор" или "канал" или "lock" — это надстройки над тем или иным транспортом


          1. 0xd34df00d
            12.12.2017 00:28

            есть еще какие-то альтернативы?

            Distributed STM. Она все эти пайпы-шмемы прячет под капотом.


        1. RPG18
          11.12.2017 14:20
          +1

          Как показывает опыт Elrang, с акторами то же бывают проблемы.


          факт того, что отправляющий процесс блокируется

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


          1. linuxover
            11.12.2017 14:22

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

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


            1. RPG18
              11.12.2017 14:29

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


              1. linuxover
                11.12.2017 14:33

                > Проблема ли это?

                конечно

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

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

                мало того с какого-то момента пользователи начинают «видеть» лаг исполнения поставленных ими задач. То есть факап происходит даже еще ДО достижения мемори-лимита.

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


                1. RPG18
                  11.12.2017 14:41

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

                  Только это порой выглядит как костыль. Как например mutex в Erlang'е.


              1. linuxover
                11.12.2017 14:44

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

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


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

                от модели акторов отличается тем что


                1. в явном виде отсутствует адресат-получатель
                2. подписчиков может быть множество
                3. единый резиновый (но с fixed MAX size, fixed ttl) maildir для всех событий

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


                1. RPG18
                  11.12.2017 15:22

                  И тут спрашивается причем тут теория взаимодействующих процессов с CSP, акторами и т.д.?


                  1. linuxover
                    11.12.2017 15:25

                    не понял я вопроса.


                    есть проблема (1 штука)
                    есть несколько ее решений:


                    1. заблокировать нафиг писателя пока читатель не прочитает (Go из коробки, Erlang — с телодвижениями) — набор проблем 1
                    2. не блокировать (Erlang из коробки, Go — с телодвиженияи) — набор проблем 2
                    3. промежуточный (Erlang с телодвижениями, Go — с телодвижениями) — набор проблем 3

                    кому какой вариант нужен — тот такой и выбирает.
                    а теория она при каждом варианте :D


                    1. RPG18
                      11.12.2017 15:50

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


      1. gatoazul
        11.12.2017 22:57

        Perl 6. Высокоуровневые вещи для параллельного программирования вставлены прямо в язык.


        1. linuxover
          12.12.2017 12:55

          я последние 15 лет программирую в основном только на Perl 5. Очень люблю этот язык.


          смотрел на Perl 6 — крайне отрицательные ощущения: да в язык воткнули многопоточность и асинхронность, но зачем так сильно ломать обратную совместимость?
          вот например регекспы: люди их пишут 100 лет одинаковые. Развивать? развивай!
          но зачем скобки например тасовать причем по кругу? Добавили треугольные, ок, зачем менять смысл у других скобок? чем варианты старые не устраивали?


          и так все. Perl 6 от Perl практически ничего не взял кроме какого-то ОЧЕНЬ ОБЩЕГО подхода. Поэтому хорошо бы ему не называться Perl и у него будет все хорошо.


      1. 0xd34df00d
        12.12.2017 00:26

        Фанатам вот сейчас было обидно.


        Конкуретность и параллельность отличная, от тупого parMap rdeepseq через Par-монаду к STM и async. А STM — божественная штука, вы просто пишете код, и он просто работает. Без дедлоков, без всего этого вот.


  1. Daar
    11.12.2017 10:38

    Использую Go последние лет 6 уже если не больше, и так привык, что практически перестал что-то писать на других языках, так немного на JavaScript еще для фронта пишу, и то уже WebAsm не за горами, думаю и его на Go можно будет компилить.
    Очень сильно устраивает простота языка и еще главное независимость от кучи библиотек. Скомпилировал 1 файл, раскидал по серверам и полетело, не надо кучу зависимостей тащить и потом отлавливать конфликты или баги обновлений.


    1. JekaMas
      11.12.2017 11:24

      Если не используются гошные плагины ;)


      1. Daar
        11.12.2017 12:43

        Думали :) Но потом отказались, ушли в сторону микросервисов.


        1. JekaMas
          11.12.2017 12:55

          И правильно сделали)
          * Я просто к тому, что go дает теперь не обязательно один бинарь на выходе. Эту особенность языка можно вычеркивать.


          1. Daar
            11.12.2017 13:08

            Ну под Windows он один :) Плагины там не пашут… еще :)


    1. danforth
      13.12.2017 14:40

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


  1. Symphel
    11.12.2017 10:51

    Каждый раз одни и те же тезисы в разных статьях о минусах Go, просто переформулированные.
    > Не очень выразительный
    Я не знаю, какие еще конструкции имел в виду автор, но в пример он привел исключения. В Go нет исключений, в FAQ есть пункт почему, нет и соответствующих кострукций. Возвращается ошибка, ее надо обработать. В C хотя бы были макросы, чтобы не копипастить, но в Go их нет. Кроме того, в Go у интерфейса error нет даже метода, который вернет код, только строковое представление. Так что если хочешь среагировать на конкретную ошибку — найди ее реализацтию и проверь type cast'ом. Или сравни текст и надейся, что не будет ложного срабатывания на другие ошибки с похожим текстом. Конечно, внутри приложения обычно все-таки используются типизированные ошибки, а не интерфейс error.
    В сравнении с исключениями, где тебе достаточно знать тип исключения, на который ты хочешь среагировать, выглядит уныло. С другой стороны, ты не обязан знать, что конкретно может пойти не так, и ловить все ошибки по типу, а реагировать на фейл конкретного метода.
    > Ад копирования
    В Go нет типообезопасного обобщенного программирования. Когда будет — неизвестно. Копипаста, боль, страдания.
    > Простой обход системы типов
    Увы, если нет обобщенного программирования на этапе компиляции, оно будет на этапе исполнения. Ничего удивительного.
    > Горе управления зависимостями
    > нельзя указать версию
    В стандартном инструменте go get нельзя указать версию, в менеджерах зависимостей glide и govendor — можно. Скоро обещают ввести стандартный менеджер зависимостей. Зависимости выкачиваются в поддиректорию /vendor для каждого пакета. Тут как раз все удобно.
    > Культурный багаж из Си
    > нет новых идей, кроме поддержки параллелизма
    Непонятно, новых по сравнению с C или со всеми другими языками. Утиная типизация в компилируемом языке? Cтатически слинкованная стандартная библиотека и GC без зависимостей на libc размером в ~1МБ? Трансляциия в язык ассемблера целевой платформы, благодаря чему кросс-компиляция встроена в стандартную поставку? Отличий от С еще больше.
    > Простота для собственной выгоды
    Мы тут горшки обжигаем. После кода на Go, приятно сесть и написать, например, немного обощенного кода на C++. Но потом, возможно, его перепишут другие люди, и не раз. Которые тоже горшки обжигают, и у них дедлайны, и голова болит, и дома надо быть в 8. И мне придется его отлаживать.


    1. Bonart
      11.12.2017 11:28

      В Go есть исключения в виде defer-panic-recover.
      Но сахара для обработки ошибок кот наплакал и в результате на одну строку полезного кода приходится три шаблонного.


  1. TimsTims
    11.12.2017 11:11

    А разве в первом примерно когда идет считывание файла, не происходит ли там передача потока в другую goroutine? Сам go ещё не знаю, но насколько мне представляется схожесть с nodejs, во время считывания файла, и ожидания ответа от HDD, возможно фоновое выполнение другой подзадачи. И в таком случае, go сильно выигрывает у D и у C, т.к. передачу контекста там реализовывать сложнее чем в го.


    1. snuk182
      11.12.2017 11:37
      +1

      Нет. Пример абсолютно однопоточный.
      Go с Javascript (и нодой) сравнивать по языковым конструкциям некорректно, поскольку в JS многопоточность не подразумевалась, и авторам пришлось совать в язык неявные async-костыли, чтобы не вешать нарисованный в том же потоке интерфейс. А у Go многопоточность самая обычная — ее нет, если явно в коде не попросить.
      (Ну да, если придираться, то системных потоков там несколько, но у программиста к управлению ими доступа почти нет, и с точки зрения программы логический поток у нее один)


      1. JekaMas
        11.12.2017 16:07

        Не совсем, ключевые вещи из стандартной библиотеки будут выполняться многопоточно и без вмешательства пользователя. Каждый запрос, приходящий в 'http/net' (HandleFunc, ListenAndServe).



  1. VBKesha
    11.12.2017 11:23

    Хм если появились статьи почему Go плох, значит уже стоит обратить на него внимание.


    1. humbug
      11.12.2017 11:30

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


      1. Idot
        11.12.2017 12:01
        +1

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


        1. QtRoS
          11.12.2017 21:10

          «если девушку назвали блядиной, значит она даёт»
          Это шедевр!


          1. vintage
            12.12.2017 01:32

            Лайфхак: назови любую девушку блядью и она пренепременно тебе даст!


            1. l4l Автор
              12.12.2017 14:53

              Логика слегка хромает. Дает — не значит тебе


            1. QtRoS
              12.12.2017 19:59

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


      1. VBKesha
        11.12.2017 12:03

        PHP плохой язык, на нем пишут кучу народа.
        JavaScript плохой, ситуация повторяется.
        C/C++ плохой ситуация повторяется.
        Это какая то закономерность.
        PS. Я не отрицаю что у всего вышеперечисленного есть недостатки…


    1. snuk182
      11.12.2017 11:46

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


      1. JekaMas
        11.12.2017 13:19

        Спорно, изначально язык позиционировался, как mainstream язык общего назначения.


        1. snuk182
          11.12.2017 15:05

          Javascript тоже изначально позиционировался, а вышло вон оно как.

          Справедливости ради, юзеры просят не многого, но очевидного, без чего mainstream язык обречен:
          — Generics
          — Управление зависимостями
          — Более настойчивая система ошибок


          1. JekaMas
            11.12.2017 15:09

            Да, об этом и Дейв Чейни пишет, разве что упоминает еще и immutability. Что в общем-то требования не заоблачные, но надо понимать, что язык не соответствующим ожиданиям для mainstream сейчас, может оказаться обреченным для входа во многие области — просто потому, что программисты ожидают минимального набора фич для современного языка.
            Удручает, что движения в этих направлениях незаметно. Ну разве что dep пилят, но предварительное знакомство не обрадовало.


            1. Aleosha
              12.12.2017 11:53

              А что не так с godep, кроме нестандартного формата в сравнение с Glide?


              1. JekaMas
                12.12.2017 12:02

                Что лично я наблюдал где-то месяц назад: медленный (https://github.com/golang/dep/blob/master/docs/FAQ.md#why-is-dep-slow), клонирует по новой зависимости, если в них есть обновления. Если добавят кэширование, то будет приличнее.
                Второе — сырой, иногда валится без причины.


          1. YetAnotherSlava
            12.12.2017 00:10

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

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


      1. VolCh
        12.12.2017 08:41

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


    1. YetAnotherSlava
      12.12.2017 00:08

      «Значит хорошие сапоги, надо брать» (с)


  1. wawa
    11.12.2017 11:58
    -1

    Странный вывод для такой бурной критики:

    Его просто читать и просто использовать.

    Разве не это главное для синтаксиса?

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

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


  1. dmbreaker
    11.12.2017 12:30

    По личному опыту нужно минимум три месяца fulltime разработки, чтобы вникнуть в язык и начать в нем разбираться, а тут типичное «я пишу на языке XXX, а Go не работает так, как XXX. Значит Go плохой/кривой».
    Это прям как лакмусовая бумажка.
    Те, кто с языком работал основательнее, резонно замечают, что есть только проблема с дженериками, остальное — сделано довольно хорошо.


    1. 0xd34df00d
      12.12.2017 00:47

      Я с Go не работал основательно, так что стало интересно: какое откровение за N месяцев фуллтайм-разработки на Go должно на меня снизойти, чтобы я понял, что обработка ошибок в Go сделана правильно?


      1. develop7
        12.12.2017 10:22
        +4

        Это откровение называется «стокгольмский синдром»


    1. Aleosha
      12.12.2017 11:58
      +2

      Пишу на Go вот уже полтора года. Мне уже можно сказать, что он кривой по всем пунктам?


    1. TheShock
      12.12.2017 21:14
      +1

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

      Лол. У него проблем выше крыши. Вот недавно в комментарии описывал, что в нем совершенно уродские теги/аннотации/декораторы, словно их придумывал человек с сильным отставанием в развитии. Это ведь не относится к Дженерикам? ;)


  1. dmbreaker
    11.12.2017 12:37
    -1

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


    1. l4l Автор
      11.12.2017 12:54
      +1

      Выгллядит как haskell's typeclass или abstract class в C++, interface в Java/Delphi/PHP/остальных ООП языках


      1. khim
        11.12.2017 17:18

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

        О том, что GNU C++ signatures (которые и явились прототипом интерфейсов в Go) «срисованы» с Haskell type classes — сами разработчики говорят. Но вот «abstract class в C++, interface в Java/Delphi/PHP/остальных ООП языках» — это совсем о другом.


        1. SirEdvin
          11.12.2017 17:25
          +1

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

          Ну, вот с Вики список: Prolog, D, Perl, Smalltalk, Python, Objective-C, Ruby, JavaScript, TypeScript, Groovy, ColdFusion, Boo, Lua, Go.


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


          Это называется утиная типизация и в этом тоже нет ничего нового.


          1. khim
            11.12.2017 18:29

            Я и не говорил, что это что-то суперновое. Но в тех вот языках, о которых автор перевода говорит (C++/Delphi/Java/PHP) — этого нет. Есть только в «остальных ООП» языках, но в «остальных ООП», есть, как бы, вообще всё…


        1. mayorovp
          11.12.2017 21:36

          Я бы этот момент рассматривал как небольшую странность а не как ключевую особенность.

          Ну вот ни разу не было необходимости писать реализацию интерфейса раньше его самого…


          1. khim
            11.12.2017 22:13

            Я бы этот момент рассматривал как небольшую странность а не как ключевую особенность.
            Если это не «ключевую особенность», а «небольшая странность», то почему вокруг добавления подобного подхода в C++ сломано столько копий?

            Ну вот ни разу не было необходимости писать реализацию интерфейса раньше его самого…
            Вопрос не в написании реализации интерфейса раньше описания интерфейса, а во вполне эквивалетной этому возможности по реализации интерфейса, на описание которого вы, при написании вашего класса, вообще не смотрели. Какие-нибудь интерфейсы типа BasicLockable или Swappable, как правило, оказываются реализованы без явного намерения их реализовать.


            1. TheShock
              11.12.2017 22:18

              А как вы поймете, что lock и unlock связаны с тредами, а не совершенно другая логика класса Gate?


              1. khim
                11.12.2017 22:25

                А как вы поймете, что lock и unlock связаны с тредами, а не совершенно другая логика класса Gate?
                Никак — и в этом весь смысл. Совершенно неважно: захватывает lock какой-нибудь mutex или тыкву. Важно, что lock — захватывает ресурс, а unlock — его освобождает. Для класса, которому нужен BasicLocable — этого достаточно.


                1. TheShock
                  11.12.2017 22:35

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


                  1. khim
                    11.12.2017 22:58

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

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

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


                    1. TheShock
                      11.12.2017 23:06

                      Вам удобнее сам факт того, что вы не пишете implements BasicLocable и в этом ваше удобство?


                      1. khim
                        12.12.2017 00:47

                        То что я не пишу implements BasicLocable — это фигня. Главное — что я при этом не вытаскиваю и не включаю в проект модуль, где этот BasicLocable описан.

                        То есть я могу поддержать все интерфейсы требуемые MySQL'ем, PostgreSQL'ем и, скажем, Oracle'ом одновременно — и не втягивая в проект библиотек MySQL'я, PostgreSQL'я и Oracle.

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


                        1. mayorovp
                          13.12.2017 09:56

                          Скажите, а как вы будете свою поддержку MySQL, PostgreSQL и Oracle тестировать не втягивая в проект их модули?


                          1. khim
                            13.12.2017 16:09

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

                            Там и тогда, где это можно использовать — там можно и протестировать.

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


                1. 0xd34df00d
                  12.12.2017 00:55

                  В соседнем треде Rust обсуждали, я там пример придумал про тайпклассы и концепты, а тут он пригодился, хорошо-то как! В общем, как вы отличите Forward iterator от Input iterator? Как вы на уровне концептов гарантируете, что он многопроходный?


                  1. khim
                    12.12.2017 01:11

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

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


                    1. 0xd34df00d
                      12.12.2017 19:45

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


                      1. khim
                        13.12.2017 08:52

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

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


                        1. 0xd34df00d
                          13.12.2017 23:14

                          Хорошо, но ведь уменьшение количества зависимостей — это не самоцель, не так ли?

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


                          1. khim
                            14.12.2017 08:11

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

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

                            Что может растянуться на недели и месяцы.


                            1. mayorovp
                              14.12.2017 09:08

                              Погодите. Вы сейчас говорите о прямой зависимости или о транзитивной?

                              С прямой все понятно — если нужно реализовать интерфейс для MS SQL — значит, надо добавлять зависимость от их клиента. Это нужно даже в go, потому что во всех случаях кроме самых тривиальных понадобится описание структур данных.

                              Что же до транзитивной — то тут вовсе не обязательно выкачивать все подобные зависимости. В тех же Java или C# если вы не пользуетесь теми классами которые реализуют интерфейс MS SQL — то и описание интерфейса тоже не нужно!


                              1. VolCh
                                14.12.2017 12:31

                                С прямой все понятно — если нужно реализовать интерфейс для MS SQL — значит, надо добавлять зависимость от их клиента.

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


                                1. mayorovp
                                  14.12.2017 12:39

                                  DIP следует применять к коду а не к пакетам…


                                  1. VolCh
                                    14.12.2017 12:44

                                    Почему к пакетам не следует применять?


                  1. alexeykuzmin0
                    12.12.2017 18:52

                    По уму, у forward iterator должен быть конструктор копирования, а у input iterator — только перемещения. Тот факт, что input iterator, формально, требует наличия конструктора копирования, объясняется историческими причинами — input iterator появился раньше, чем move semantics


                    1. khim
                      12.12.2017 19:05

                      По хорошему-то нужно делать то, что отлично делает perl и хорошо делал python (пока они там все белены не обьелись) — что-нибудь типа

                      using C++20;

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

                      Тогда от них можно было бы отказываться постепенно…

                      А так — каждый новый стандарт делает вид, что он существует «в вакууме», старых программ «типа нет» — но при этом мы всё время о них думаем… Шизофрения какая-то…


                      1. alexeykuzmin0
                        12.12.2017 19:24

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


                        1. khim
                          13.12.2017 08:48

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

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


                          1. alexeykuzmin0
                            13.12.2017 10:39
                            +1

                            Честно говоря, не понял, зачем флагам быть частью стандарта. Флаги вроде "-std=c++17" делают ровно то же самое, что и гипотетический

                            using C++17;
                            в начале файла.


                            1. khim
                              13.12.2017 16:13

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


                      1. 0xd34df00d
                        12.12.2017 19:44

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


            1. 0xd34df00d
              12.12.2017 00:52

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

              И это сильно не всегда хорошо.


            1. mayorovp
              12.12.2017 07:07

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


              1. 0xd34df00d
                12.12.2017 19:35

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


            1. Bonart
              13.12.2017 14:43

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


              1. VolCh
                13.12.2017 14:47
                -1

                Если нам нужно холодное и жёлтое, то какая разница мороженое это или снег? :)


                1. 0xd34df00d
                  13.12.2017 23:15

                  Ну, дело вкуса.


        1. Nikita_Danilov
          11.12.2017 22:11

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

          Хотя, справедливости ради, мне рыдать хочется что теперь реализации методов по-умолчанию привносят в интерфейсы C# :( в Java они уже давно имеются.


        1. 0xd34df00d
          12.12.2017 00:51

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

          А оно надо? Я бы предпочёл, чтобы компилятор имел возможность проверить, всё ли я определил и тайпчекается ли оно, в точке определения реализации интерфейса.


          А вообще это сурово пахнет концептами C++, а соответствующий пропозал появился до релиза Go, ЕМНИП.


          В гошных тайпклассах есть, кстати, multiparam type classes? Fundeps?


          1. khim
            12.12.2017 01:31

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

            А вообще это сурово пахнет концептами C++, а соответствующий пропозал появился до релиза Go, ЕМНИП.
            Я бы сказал, что Go'шный ООП очень сильно пахнет GNU C++ сигнатурами, которым, если бы они были людьми, уже можно было пить и курить — это ж почти четверь века назад было всё релизовано! Не исключу, что и раньше, чем в Haskell подобные вещи пробрались, но точно не скажу — это нужно целое расследование проводить…

            И да — некая схожесть с концептами и type class'ами наблюдается, но в целом — это не совсем то.

            В гошных тайпклассах есть, кстати, multiparam type classes? Fundeps?
            Вроде бы нет, но на 100% не уверен.


            1. 0xd34df00d
              12.12.2017 19:57

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

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

              Не исключу, что и раньше, чем в Haskell подобные вещи пробрались, но точно не скажу — это нужно целое расследование проводить…

              Придуманы они были не позже 89-го года, вот в этом папире (вообще забавное чтиво с высоты почти тридцати лет). Судя по ссылкам на странице с описанием сигнатур, они появились году в 95-м.

              Но это я так, из любви к искусству.


              1. khim
                13.12.2017 09:04

                Судя по ссылкам на странице с описанием сигнатур, они появились году в 95-м.
                Нет, точно раньше. В GCC 2.6.3 (самая старая версия GCC с поддержкой C++ на ftp.gnu.org) они уже имеются. Это 1994й. А дальше история становится туманной.


      1. quasilyte
        12.12.2017 00:58

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

        Насколько это хорошо или плохо — не хочу полемизировать, но подчеркнуть, что это не «Как в C++», всё-таки захотелось.


        1. humbug
          12.12.2017 01:27

          Чойта? -fdevirtualize и -fdevirtualize-speculatively в компиляторах C++ придумали не вчера.


          1. quasilyte
            12.12.2017 01:45

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

            Про спекулятивную девиртуализацию поищу.

            Anyway, в Go можно явно сказать: «Тут мне полиморфный тип, а тут просто структру T».
            В C++ же полиморфность является свойством самого типа T. Right?


            1. khim
              12.12.2017 02:16

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

              В любом случае тут как бы «небольшие накладные расходы всегда» vs «никаких накладных расходов если полиморфность не нужна, но весьма внушительные — если нужна».

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


            1. humbug
              12.12.2017 02:34

              Anyway, в Go можно явно сказать: «Тут мне полиморфный тип, а тут просто структру T». В C++ же полиморфность является свойством самого типа T. Right?

              Угу. -fdevirtualize может вырезать лишний жир, если полиморфное поведение не используется. Но… это соооовсем не идеально.


    1. Alesh
      11.12.2017 16:10
      +2

      А какие языки вы кроме golang изучали?


  1. KirEv
    11.12.2017 14:04

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

    Go использую с версии 1.8, не знаю что было раньше, но то что сейчас — хорошо работает.

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

    Порог вхождения не высок, но месяца за три — только начинаешь въезжать в идею создания Go, хотя первый микросервис удалось написать дня через два после первого `Hello world`

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


    1. SirEdvin
      11.12.2017 14:52

      А что из описанного в статье поменялось?


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


      1. khim
        11.12.2017 17:20

        Вроде же все наоборот утверждают, что Go очень простой.
        А тут другая проблема: он простой — но другой. Человек, не видевший ничего, кроме GW-BASIC'а его легко освоит. А людям, работающим на других языках, приходится переучиваться. Это занимает время.


        1. SirEdvin
          11.12.2017 17:22

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


          Вот python простой, что бы начать писать на нем какой-то рабочий код достаточно вводной статьи и 15 минут времени. Да, качество кода будет так себе и все прочее, но в целом оно неплохо работает.


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


          1. khim
            11.12.2017 18:36

            Если он другой и на него нужно переучиваться, значит он не простой.
            Нет. Так у вас все языки, кроме C++, сложными станут. Потому что с ним я работаю последние 10 лет и мне в нём всё понятно. А чтобы освоить даже Lua — потребуется время.

            Простота/сложность языка определяется временем, которое требуется на его освоение человеком, который не знает ни одного языка программирования. С этой точки зрения — Go и JavaScript просты. А C++ и Haskell — сложны.

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

            Вот python простой, что бы начать писать на нем какой-то рабочий код достаточно вводной статьи и 15 минут времени. Да, качество кода будет так себе и все прочее, но в целом оно неплохо работает.
            Та же самая ситуация и с Go, как бы.

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

            Я в течении этого времени только искал, как же нормально задать переменную окружения навсегда.
            Что значит «задать переменную окружения навсегда», как это сделать в Python'е и почему в Go это сделать сложнее?


            1. SirEdvin
              11.12.2017 18:38

              Что значит «задать переменную окружения навсегда», как это сделать в Python'е и почему в Go это сделать сложнее?

              Это я про GOPATH и GOROOT. Вот в ubuntu это все еще не делается из под коробки, а значит надо устанавливать самому. А я в то время не знал как.


              А в python просто, pip install package и погнали. Потом, конечно, больно, но все же можно)


              1. khim
                11.12.2017 22:34

                А в python просто, pip install package и погнали.
                Серьёзно? А давайте я вам SunOS какой-нибудь постарше дам питона — и вы на ней pip install package без установки PYTHONPATH и PYTHONHOME погоните. А я посмеюсь.

                Или, если SunOS не нравится — могу дать MacOS и скрипт на Python3.

                Это я про GOPATH и GOROOT. Вот в ubuntu это все еще не делается из под коробки, а значит надо устанавливать самому. А я в то время не знал как.
                И что — это делает язык сложным? Python точно так же требует установки переменных окружения. Просто в Ubuntu это уже сделали за вас, на этапе сборки, собственно, питона.


                1. SirEdvin
                  12.12.2017 00:23

                  Почему так же не сделать для го то?


                  1. quasilyte
                    12.12.2017 01:07

                    Возможно проблема в том, что у Go нет своего pip.
                    Go build и то, что близ него — это довольно низкоуровневые вещи.

                    Мне не очевидно, насколько github.com/constabulary/gb юзабелен, но скорее всего со временем появится хороший project-based тул, который станет тем самым pip для Go.


            1. 0xd34df00d
              12.12.2017 00:58

              Простота/сложность языка определяется временем, которое требуется на его освоение человеком, который не знает ни одного языка программирования. С этой точки зрения — Go и JavaScript просты. А C++ и Haskell — сложны.

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


              1. khim
                12.12.2017 01:35

                У меня отец физик, и ему хаскель (и интуитивный подход к вычислению программы как к редукции графа) будет сильно понятнее, чем Go или JS.
                Вы бы ещё про математиков вспомнили!

                Да, есть люди, которые функциональный подход воспринимают легче, чем императивный. Но где-то для 90% программистов (и, боюсь, для 98%-99% людей вообще) иперативная «поваренная книга» воспринимается проще.

                Даже несмотря на то, что в школе, вроде как, математике учат всех…


  1. ilyasvetozar
    11.12.2017 15:18

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


    1. poxvuibr
      12.12.2017 08:15

      Лично по моему С++ и Java также являются простыми и не сложными языками, это дело привычки и опыта.

      Насчёт С++ есть просто отличное выступление Скотта Мейерса на конференции, посвящённой языку программирования D. Обязательно посмотрите, очень рекомендую. Джава по сравнению с С++ существенно проще, но по сравнению с Go в смысле количества сущностей — конечно сложнее.


  1. leshabirukov
    11.12.2017 15:23

    Язык можно описать как Си с дополнительными колесиками(ориг.: training wheels).

    Трёхколёсный велоСипед.


    1. Zinkalla
      11.12.2017 22:46

      Нет, обычный(детский) велосипед с дополнительными колесиками. Трехколесный велосипед это больше Visual Basic :)


    1. alexeykuzmin0
      12.12.2017 18:59

      Четырех- же


  1. EvilFox
    11.12.2017 20:41
    +2

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


  1. Mikanor
    11.12.2017 21:38
    +3

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


  1. Flaker
    11.12.2017 22:42

    1. alexeykuzmin0
      12.12.2017 18:59
      +1

      Ссылка сломана


      1. Flaker
        12.12.2017 20:39

        Прощу прощения! Спасибо, что подсказали!

        hackernoon.com/why-senior-devs-write-dumb-code-and-how-to-spot-a-junior-from-a-mile-away-27fa263b101a


  1. Delinker
    11.12.2017 22:49

    «Автор, вы просто не умеете его готовить», это единственное что приходит на ум после прочтения статьи. Очередная холиварная статья.


    1. Aleosha
      12.12.2017 12:00
      +1

      А может быть, если оно плохо пахнет, его и готовить не нужно?


      1. Delinker
        13.12.2017 23:24

        Вкусовщина, не более.


  1. guai
    12.12.2017 10:41

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


    1. VolCh
      12.12.2017 14:41

      А если задача не бизнес, а инфраструктурная?


  1. m0Ray
    12.12.2017 11:33
    -1

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


  1. McAaron
    12.12.2017 14:28
    -2

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


    1. mayorovp
      12.12.2017 14:32

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


    1. l4l Автор
      12.12.2017 14:59
      +2

      1. Автоматизация нужна, чтобы уменьшать человеческие ошибки, шаблоны — та же степь. Написали правильно — везде правильно, неправильно — везде неправильно
      2. Тогда в этом случае а) не нужны шаблоны б) обобщение на слишком большой кусок кода (e.g темплейт нужен не на метод, а его половину)
      3. Согласен, но впрочем шаблоны помощнее инструмент
      4. Выше веткой обсудили(-ают), если коротко: тоже самое


      1. sumanai
        12.12.2017 19:53

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

        С этим можно (и нужно) спорить, так как шаблон можно использовать неправильно, даже если сам по себе он близок к идеалу.
        Но самое весёлое в шаблонах- это их изменение…


    1. billyevans
      13.12.2017 03:03

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

      Это не так. Можно написать generic-реализацию для всех типов и для конкретного типа отдельно.


  1. unxed
    13.12.2017 10:23
    -1

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

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


    1. develop7
      13.12.2017 10:50
      +1

      Хосспде, да она закончилась с появлением GW-BASIC, или как его там. Да только как-то всё не в коня корм.