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

image


Причина №1. Манипуляции со слайсами просто отвратительны


Автор начинает свой разнос дизайна языка с утверждения о том, что отрицательные индексы, как в Python, не работают.
// numbers[:-1] из Python не прокатит.

Здесь ответ прост — Go это не Python, это разные языки. Некоторым людям сложно даётся факт, что никакие языки, кроме Питона, не являются Питоном, но давайте изучим вопрос детальнее. Вот официальный ответ Роберта Пайка о том, почему отрицательных индексов нет в Go:
Это было убрано намеренно, потому что выражение s[i:j] может молча дать неверный результат, если j станет меньше нуля. Именно это было причиной ужасного бага в Rietveld, кстати говоря. Индексы должны быть не отрицательны.


В issues на Github есть похожий вопрос и ответ, который дополняет следующим утверждением:
Эта фича (присутствующая в Питоне, например) отсутствует намеренно.
Арифметика с индексами в слайсах может приводить к проблемам, если ошибочный отрицательный результат «просто сработал», как обратный индекс. Это приводит к сложноуловимым багам

Кроме того, от статус кво, выигрывает читабельность. Сейчас очевидно, что выражение s[:i] создает слайс от s длиной i байт. Если же i может быть отрицательным, то нужно больше контекста, чтобы понимать всё выражение слайса.

Это решение отталкивается от общей философии Go избегать тонких синтаксических трюков.

Можно согласиться, что кому-то для его случаев отрицательный индекс может быть удобен, и чуть короче в записи. Но авторы Go, исходя из своего, более чем, полувекового опыта разработки, видят, что эта экономия нескольких байт в одном случае, ведущая к сложным багам и ухудшению читабельности в другом — не стоит того, и выбирают решение, более подходящее концепции языка. Решение, требующее программистам на Python немного перепривыкнуть, но уменьшающее риск хитрых ошибок в long term. Понятно, что не все мыслят на long term, отсюда и конфьюз.

Идем далее, следующий rant автора:
/ Хочется вставить какое-то число? Ничего страшного,
// в Go есть общепринятая best practice!
numbers = append(numbers[:2], append([]int{3}, numbers[2:]...)...)

Во-первых, это не best practice а сниппет-однострочник, найденный на странице Go Slice Tricks. В реальном коде, если уж кто это и делает, то более читабельно. И тут мы, для начала, вспомним, что дизайн слайсов и массивов в Go обсуждался больше года, прежде чем прийти к окончательному дизайну. И основными факторами были «практическая необходимость» и «скорость». Да, это не очень привычный подход, во многих других языках наличие фич в большем приоритете, но в Go вот так.

А теперь давайте спросим автора два вопроса:
  1. насколько частый случай — вставка элемента в середину массива?
  2. насколько эффективна вставка в середину массива?

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

Резюмируя — такой дизайн выбран намеренно, для создания стимула правильно использовать структуры данных, и не получать в long term наследие в виде тормознутого софта. Опять же, видим этот ненавистный многим тут «long term», который портит всю сказку.

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

Причина №2. Нулевые интерфейсы не всегда нулевые :)


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

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

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

Причина №3. Забавное сокрытие переменных


Тут автор, обманывает и читателей и самого себя. Во-первых, shadowing всегда был источником различных конфьюзов и непоняток, и в Go, в отличие от, скажем С++, нет undefined behavior при сокрытии переменных. Винить можно только невнимательность программиста, что, безусловно, не снимает с языка ответственности в том, чтобы помогать программисту не совершать такие ошибки.
Во-вторых, критика «дизайна сокрытия переменных» должна подразумевать предложение альтернативного, более удачного дизайна — тогда дискуссия имеет шанс быть предметной.
В-третьих, штатная утилита go vet умеет показывать сокрытые декларации переменных, но, поскольку сокрытие это не ошибка, то, по умолчанию этот флаг go vet выключен, чтобы не засорять вывод на правильном коде.
Используйте
go tool vet -shadow=true
и не вводите в заблуждение читателей.

Например на код автора оригинальной статьи, go vet скажет:

$ go tool vet -shadow=true main.go
main.go:16: declaration of number shadows declaration at main.go:10:

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

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

Причина №4. Ты не можешь передать []struct как []interface


На эту ситуацию я, в начале знакомства с Go, наткнулся сам. Пытался делать нечто замудренное, по незрелости, конвертировать интерфейсы туда-обратно, и возникла вот точно такая же задача.
Разумеется, я наткнулся на ошибку компилятора, но, в отличие от автора статьи, не бросился писать статью с проклятиями в адрес Пайка и утверждениями о том, что «в Go нет полноценной поддержки интерфейсов» (хаха), а нашел объяснение почему такая операция явно не поддерживается.
Первое, что нужно знать — это отличия «структуры» от «интерфейса» в Go. Это просто, и этого достаточно, чтобы понять, почему вы просто так не можете «скастить» слайс структур в слайс интерфейсов. Это база, причем очень простая, и оправданий не знать её нет — вся документация на официальном сайте и читается за вечер.
Второе — и созвучное с выше обсужденными слайсами — это то, что операция конвертирования слайсов — дорогая операция. По времени это O(n) и компилятор Go подобные дорогие вещи не будет делать, чтобы не давать нерадивым программистам писать медленный код. Хотите делать потенциально дорогую операцию — будьте добры, сделайте это явно, вся ответственность на вас, а не на компиляторе. Очень правильный подход, который нацелен на качество кода на Go в long term. Ну, ясно, почему для автора поста это так непонятно.

Причина №5. Неочевидные циклы «по значению»


Тут автор возмущается тем, что ключевое слово range передает значения, а не ссылки, и что, цитирую,
range — это тебе не foreach из С++
Потом, правда, поправляется и говорит, что проблема в том, что в документации явно это не указано.

Что тут можно сказать? Go — это другой язык, это не C++. Зачем пытаться сделать из Go то Python, то C++ — загадка.
Любой, кто прошел go-tour увидит в этой строке оператор ":=", который означает создание новой переменной и присвоение ей значения:
for number := range numbers {}


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

Причина №6. Сомнительная строгость компилятора


Сомнительная строгость, по мнению автора заключается в том, что в Go код не компилируется если есть неиспользуемый импорт. Это, помимо того, что является квинтессенцией opinionated подхода Go к вопросу качества кода, ещё и демонстриует, что автор таки не читал FAQ, в котором этот вопрос подробно объяснен. Любой, кто писал на С/C++, знает во что превращаются проекты, после того, как кодом поработают 5-10 программистов, и код пройдет несколько стадий рефакторинга. Помимо этого, каждый импорт — это замедление процесса компиляции, и там где Go-программисты не успевают моргать глазом, С++-программисты идут пить кофе и ждать, и это тоже вина/заслуга «неиспользуемых импортов». Понимание правильности такого решение могло прийти только с большим опытом.
Согласен, что это непривычно, но это приводит к быстрой компиляции и чистому аккуратному коду в любом проекте на Go. И это бесценно. У программистов без опыта, конечно, приоритеты другие.

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

Причина №7. Кодогенерация в Go это просто костыль


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

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

go generate отлично выполняет свою функцию, позволяя обходиться безо всяких Make-файлов даже тогда, когда вам нужно сгенерировать какой-то код с помощью сторонних утилит вроде yacc, thrift, protobuf или swig. Это простой, удобный и рабочий инструмент, который решает реальную задачу, практически ничего не добавляя в язык, кроме одной команды go generate и одного соглашения о формат комментария (что-то вроде hashbang). Это работает и работает хорошо.

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

Эпилог


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

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

Статья же автора о том, что дизайн языка «плохой» — это, к сожалению, не более, чем попытка привлечь к себе внимание. В подростковом возрасте это нормально, но хочется донести автору, что искусственное разжигание хейтерства и холиваров никогда не бывает конструктивным. Подобными статьями, заведомо предвзятыми и не объективными, безусловно, автор наносит вред. К примеру, есть компании, где Go в процессе внедрения, и, зачастую, решение о том «писать несколько месяцев REST-бекенд на C++ и нанять для этого ещё 2 rock-star C++ программиста» или «перейти на Go и написать все быстро и качественно» принимает менеджер сверху, который может понимать области применимости языков, а может и не понимать. И достаточно такого вброса, чтобы человек, даже не читая и не вникая, решил для себя, что «Го не стоит использовать, раз такие статьи про него пишут». И это реальные ситуации.

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

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


  1. ramzes_yan
    30.10.2015 06:28
    +9

    согласен с автором добавлю отсебятины

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

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


  1. Musia17
    30.10.2015 06:47
    +9

    Осмелюсь поблагодарить за статью! Действительно вчерашний пост (про «ужасный» язык) оставил в голове какое-то впечатление сумбура. Сейчас оно отступило :)


    1. jemali_m
      30.10.2015 07:17
      +1

      У меня оно еще не скоро пройдет ))
      Что касается golang, мне, как плавно переходящего с PHP, новый ЯП все больше начинает нравиться. Есть конечно же определенные нюансы, но это все равно большущий шаг вперед.

      P.S.: по части WEB, разумеется!


  1. bolk
    30.10.2015 07:43
    +2

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

        // если вставка требуется по индексу, который больше
        // массива, просто добавляем в конец
        if i >= len((*arr)[org]) {
            (*arr)[org] = append((*arr)[org], value)
        } else {
            // надо добавить любой элемент в конец, чтобы появилось место
            // если в срезе место есть, оно будет использовано автоматически
            (*arr)[org] = append((*arr)[org], nil)
    
            copy((*arr)[org][i+1:], (*arr)[org][i:])
            (*arr)[org][i] = value
        }
    


    1. 4dmonster
      30.10.2015 10:33

      Если можно без кода, я могу привести примеры:
      1. вставка строки в середину перечня товаров счёта;
      2. вставка строки в середину перечня ролей пользователя;
      3. вставка строки в середину перечня подзадач расписания;


      1. Gorthauer87
        30.10.2015 11:07

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


        1. lair
          30.10.2015 11:40
          +10

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

          У этих «других штук» другие стоимости, что иногда может быть неудобно (Да, мне как-то была нужна упорядоченная структура с O(1)-доступом к произвольному элементу, и меня устраивало O(n) при ее расширении. Нет, кейс не помню, что-то из стандартных алгоритмов.)


          1. Gorthauer87
            30.10.2015 14:06
            -5

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


            1. lair
              30.10.2015 14:14
              +17

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

              От этого в Go появится операция insert?


              1. divan0
                30.10.2015 17:54
                -8

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

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


                1. lair
                  30.10.2015 17:57
                  +5

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


              1. mirrr
                31.10.2015 11:12

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

                a = append(a[:pos], append([]T{x}, a[pos:]...)...)
                

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


                1. lair
                  31.10.2015 13:02
                  -1

                  Угу. И так k раз.


                  1. mirrr
                    31.10.2015 19:21

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

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


                    1. lair
                      31.10.2015 19:22

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

                      Вообще-то, я был одним из таких комментаторов.

                      И, к сожалению, это реальная жизнь.


                      1. mirrr
                        31.10.2015 22:25

                        Такова жизнь, но примеров из жизни никто так и не привел. Хотя мне еще тогда было интересно увидеть необходимость такой функции в серверном микросервисе на 100-200 строк, для создания которых и позиционирует себя golang.


                        1. lair
                          31.10.2015 22:47
                          +3

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


                        1. divan0
                          01.11.2015 00:32
                          -2

                          Ну там примеры из жизни были — «я хочу написать вот именно такую функцию именно таким способом».

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


                          1. dmbreaker
                            01.11.2015 12:29
                            +1

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


                        1. 0xd34df00d
                          02.11.2015 14:01

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


                          1. mirrr
                            02.11.2015 14:19

                            Здесь T это как-раз тип, перепутать не получится, не скомпилится
                            Реальный код так будет выглядеть:

                            a = append(a[:pos], append([]string{x}, a[pos:]...)...)
                            


                            1. 0xd34df00d
                              02.11.2015 14:24

                              И мы снова возвращаемся к вопросу о том, как написать такую обобщённую функцию.


                              1. mirrr
                                02.11.2015 15:03
                                +1

                                И мы снова возвращаемся к вопросу — Зачем?


                                1. 0xd34df00d
                                  02.11.2015 15:42
                                  -2

                                  Чтобы не привязываться к конкретным типам данных, внезапно.


  1. Daniro_San
    30.10.2015 09:35
    -15

    Go прекрасен!
    Использую его уже более года, если что то и непонятно, то нужно лишь немного терпения (и умения читать, конечно) что бы разобраться!


  1. Daniro_San
    30.10.2015 09:41
    -16

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


  1. SirEdvin
    30.10.2015 10:04
    +57

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

    Вы очень много пишите про дизайн Go и про то, что он такой удобный, но… на самом деле это нет.
    Строгий язык не может быть удобным.
    А язык, в основе которого лежат какие-то фиксированные практики программирования, которые говорят что «делать можно только так» тем более не может быть удобным.

    Например, почему нужно писать так:

    numbers = append(numbers[:2], append([]int{3}, numbers[2:]...)...)
    

    Вместо того, что бы писать так:
    numbers = append(numbers[:2], 3, numbers[2:]...)
    

    Чем можно обосновать такое решение?

    Или заменить int[]{3} на просто [3].


    1. 4dmonster
      30.10.2015 10:17
      +35

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

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


      1. Alex_At_Net
        30.10.2015 13:40
        -12

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

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


        1. Ramires
          30.10.2015 13:52
          +20

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

          Серьезно?
          Любой, кто писал на С/C++, знает во что превращаются проекты, после того, как кодом поработают 5-10 программистов, и код пройдет несколько стадий рефакторинга

          писать несколько месяцев REST-бекенд на C++ и нанять для этого ещё 2 rock-star C++ программиста

          и в Go, в отличие от, скажем С++, нет undefined behavior при сокрытии переменных

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

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

          Я бы Вашу характеристику отнес бы к обеим статьям
          не слишком основательно прорабатывает аргументацию, смещая акцент в эмоции. «Инженерный» троллинг :)


          1. 0xd34df00d
            30.10.2015 19:44
            +10

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

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

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


            1. divan0
              30.10.2015 21:11
              -1

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

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


              1. 0xd34df00d
                30.10.2015 21:30

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

                Это ваша цитата.

                Там вам товарищ, правда, вот ответил почему-то со словом «список», ну да ладно. Там как раз понятно, что раз он отвечал про массив, то массив ввиду и имелся.


                1. divan0
                  30.10.2015 21:44
                  -6

                  Я попросил три реальных примера (показать код, к примеру или рассказать суть задачи).
                  Человек привел надуманный пример и сказал одно (сортированный список).
                  Вы перекрутили его слова, обвинив меня в том, что я предлагаю список для реализации сортированного массива.
                  Потом сказали, что «там как раз понятно».

                  Новый формат общения на Хабре, мда.


                  1. 0xd34df00d
                    30.10.2015 21:48
                    +2

                    Да что ж такое…
                    Ну как мне поддерживать сортированный массив на Go, а?


                    1. neolink
                      30.10.2015 22:00
                      +1

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


                      1. 0xd34df00d
                        30.10.2015 22:27

                        А правила сортировки — они относятся к типу или к месту вызова?
                        А блоки — это уже не массив, а deque.
                        А почему на C, а не на C++?


                        1. neolink
                          30.10.2015 22:50

                          Мало того, что вы мне вопросом на вопрос ответили. Так ещё и вопросы какие-то странные.
                          Ок, на C не получилось, давайте на C++


                          1. encyclopedist
                            30.10.2015 23:01

                            v.insert(upper_bound(v.begin(), v.end(), x), x);
                            

                            — выполняет двоичный поиск и вставляет элемент.


                          1. 0xd34df00d
                            31.10.2015 00:16
                            +1

                            Вопросы не странные.

                            Операция сравнения должна задаваться в момент определения типа или в момент вызова функции сортировки/поиска?
                            Условно, если у меня есть структура, описывающая человека, с двумя полями — имя и фамилия, то мне надо иметь отдельно по типу на структуру, сравниваемую по имени, отдельно по фамилии, отдельно по их комбинации, и так далее? Или компаратор должен задаваться в момент вызова sort/upper_bound/etc?
                            В плюсах доступны оба варианта, если что.

                            А код на C++ уже за меня написали. Потребуется кастомный компаратор, можно будет написать

                            v.insert(std::upper_bound(v.begin(), v.end(), x,
                                        [](const auto& left, const auto& right) { return left.field < right.field; }),
                                    x);
                            


                            1. neolink
                              31.10.2015 00:45

                              конкретно я про это:
                              > А почему на C, а не на C++?
                              я то конечно и попросил C т.к. там нет дженериков. В целом не сказать что приходилось прям сильно страдать от этого в Go (как-то либо стандартный sort, либо штуки на interface{}, либо совсем кастом) но реально они должны быть здесь (хотя бы для стандартных контейнеров).
                              кстати ваши примеры на 11 плюсах, которые через 20 лет вышли после первой версии


                              1. 0xd34df00d
                                31.10.2015 00:55
                                +1

                                я то конечно и попросил C т.к. там нет дженериков.

                                А Go позиционируется как альтернатива C? Это что-то новенькое!

                                Давайте с ассемблером сравним, будет вообще по всем пунктам в выигрышном свете.

                                кстати ваши примеры на 11 плюсах, которые через 20 лет вышли после первой версии

                                И что это нам говорит?

                                Кстати, конкретно этот пример на 14-х плюсах, ну да ладно, простой заменой auto на конкретный тип сводится к 11-м.


                                1. neolink
                                  31.10.2015 01:32

                                  C как бы это что-то старенькое.
                                  Вообще это все ЯП, c++/c, go, python, haskell, php и т.п. и они все друг другу альтернативы.
                                  > И что это нам говорит?
                                  Нам это говорит что все развивается, где-то быстрее, где-то медленнее
                                  > Кстати, конкретно этот пример на 14-х плюсах
                                  в 11 добавили авто но не дописали что его можно использовать в лямбдах?

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

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


                                  1. 0xd34df00d
                                    31.10.2015 06:54
                                    +2

                                    Вообще это все ЯП, c++/c, go, python, haskell, php и т.п. и они все друг другу альтернативы.

                                    PHP — это альтернатива хаскелю и C++, ок.

                                    Нам это говорит что все развивается, где-то быстрее, где-то медленнее

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

                                    в 11 добавили авто но не дописали что его можно использовать в лямбдах?

                                    Потому что auto в аргументе лямбды — это совсем не то же самое, что auto в объявлении переменной. Это даже называется специальным словом, generic lambdas, и разворачивается в структуру с шаблонным operator().

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

                                    Подумайте на досуге, почему вы спросили о сравнении с C, а не с ассемблером или Brainfuck или Whitespace.

                                    В плюсах нет встроенного параллелизма

                                    Есть (хотя кривой, не кривой делается на boost.asio один раз и почти на всю жизнь).

                                    сборщика мусора

                                    И GUI-библиотеки в самом языке нет.

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

                                    Например? И что такое «очень неплохо»?

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

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


                                    1. neolink
                                      31.10.2015 11:15

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

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

                                      > Подумайте на досуге, почему вы спросили о сравнении с C, а не с ассемблером или Brainfuck или Whitespace.
                                      Потому что я сам пишу на C и там нет generics. Подумайте на досуге, почему вы не смогли написать этот код.

                                      > Есть (хотя кривой, не кривой делается на boost.asio один раз и почти на всю жизнь).

                                      go func () {
                                      // do
                                      }()

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

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

                                      > И GUI-библиотеки в самом языке нет.
                                      опять сравнили теплое с пальцем.

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

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


                                      1. 0xd34df00d
                                        02.11.2015 14:23
                                        +1

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

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

                                        Пруфы?

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

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

                                        Этот пассаж я, признаться, не понял.

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

                                        А ещё вы этот код не сможете написать на Brainfuck или Whitespace. И что теперь?

                                        подобная есть?

                                        Один раз за всю жизнь (или за проект, ок) сделали тредпул, и всё,
                                        как пример.

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

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

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

                                        опять сравнили теплое с пальцем.

                                        А почему тёплое с пальцем, а не тёплое с тёплым или палец с пальцем?

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

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

                                        В общем ваша позиция плюсы для всего

                                        Нет, не такая. Я кроме плюсов могу потыкать в R для подсчета всяких статистик по данным, в Haskell для много чего, в Bash, если надо что-то быстренько заскриптовать на 10 строк. А вот зачем мне Go, я не очень понимаю.
                                        Более того, как в итоге позиционируется Go, я вообще не понимаю. Если это язык для микросервисов в 2015 году, то сравнивать его с C, как вы это делаете, несколько странно.


                              1. encyclopedist
                                31.10.2015 01:10

                                Нет, мой пример на C++98, самом первом стандарте.


    1. overmes
      30.10.2015 10:40
      +1

      Вы точно прочитали статью? Где в ней про удобство?

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


      1. Ramires
        30.10.2015 10:46
        +6

        который помогает вам делать более быстро более качественный код

        перейти на Go и написать все быстро и качественно

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


        1. IncorrecTSW
          30.10.2015 10:49

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


          1. SirEdvin
            30.10.2015 13:10
            +1

            На Basic тоже что-то пишется…


        1. Alexeyco
          30.10.2015 21:29

          Как-то странно. Привели пример НЕКОТОРЫХ!!! нестыковок в языке по сравнению с другими языками, подчеркиваю — с другими. И внезапно язык становится неудобным во всем. Я когда выбирал профессию программиста, честно, не думал, что здесь в итоге будет царствовать вкусовщина и такая податливость хайпам. Современному языку программирования на ранних этапах важно одно: чтобы его пропиарило как можно больше значимого в узком круге народа. Если бы все случилось чуть иначе, и, скажем, Rust вышел чуть позже, а о Go положительно отозвалось бы чуть больше народа, взгляды были бы совсем другими. Некоторая неуклюжесть работы со срезами показалась бы незначительной, зато каждый, кто выбрал бы этот язык тешил бы себя мыслью о причастности к чему-то вечному и великому только благодаря своему выбору. Я не преувеличу, если скажу, что немного разочарован в сообществе программистов. Более того, все эти кровавые холивары происходят по той же самой причине. Просто одни адепты выбрали маоизм от программирования, другие выбрали условный капитализм. Перед их носами махнули красной тряпкой в виде не совсем, надо признать, честной статьи, и они готовы грызть друг другу глотки в интернетах. По сути, плевать мне хотелось, если кто-то будет писать на брейнфаке свои проекты. Ну честное слово, я знаю, чего хочу от жизни — ну наздоровье. Зачем мне переубеждать человека, и тем более портить ему карму — да еще так остервенело. Но все меняется, когда язык становится идеологией. Вот тогда да, тогда тот, кто не с нами — тот непременно враг, тот достоин всяческого унижения и обструкции. Да на костре сжечь еретика, он слайсами манипулирует кодом, на строчку больше, чем мы. Распять мерзавца, как он посмел высказать свое мнение! Четвертовать его!


          1. Ramires
            30.10.2015 23:21

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

            Распять мерзавца, как он посмел высказать свое мнение! Четвертовать его!

            Лично Вам я поставил плюс.
            2.
            И внезапно язык становится неудобным во всем

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

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


            1. Alexeyco
              31.10.2015 03:27
              +5

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


      1. matiouchkine
        30.10.2015 10:59
        +19

        > Написано, что Go помогает писать код с которым будет меньше проблем в будущем.
        Это из области метеорологических прогнозов. Поживем — увидим. Предыдущим стремительно завоевывавшим рынок языком, с которым не будет проблем в будущем был КОБОЛ.

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


        1. VoidEx
          30.10.2015 20:40

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


          1. 0xd34df00d
            30.10.2015 21:00
            +6

            В хаскеле это математически обосновано и следует из базовых свойств языка и абстракций (запихивать всё в unescapable-монаду ST, например). А тут — набор ad-hoc-костылей и решений с потолка, уж простите.


            1. divan0
              30.10.2015 21:19
              -3

              А тут — набор ad-hoc-костылей и решений с потолка, уж простите.

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


              1. qnikst
                30.10.2015 21:24
                +4

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


          1. divan0
            30.10.2015 21:16
            -3

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

            Именно так. Спасибо, хоть кто-то написал, что понимает о чем речь.
            Это и вправду такая сложная концепция для понимания или я её непонятно объясняю?


            1. VoidEx
              30.10.2015 22:24
              +7

              Мне сложно сказать, потому что я понимал, о чем речь, до ваших объяснений, но, как мне кажется, основная претензия не к самому подходу «плохое должно выглядеть плохо», а к конкретному выбору того, что считать плохим. Ни в C++, ни в Хаскеле, ни много где ещё нет проблемы написать вставку в середину массива, т.е. если уж сильно надо, можно написать красиво. Это приводит реально к каким-то серьёзным проблемам? Если да, то было бы замечательно увидеть примеры и какую-либо статистику, а так это звучит несколько безапелляционно. Ну т.е. проблема в подаче и восприятии. Если подать как «авторы [языка] считают, что это решение оправдано», то это одно, а если «это будет хорошо в long term» без внятного ответа на вопрос «почему», то в купе с холиварным несколько стилем это и приводит к соответствующему стилю обсуждения.


            1. matiouchkine
              31.10.2015 12:23
              +12

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

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


    1. Alex_At_Net
      30.10.2015 13:29
      +3

      Так «нужно» писать, потому что так писать не нужно. Если использовать неправильный инструмент, результат получается некрасивым (мягко говоря).

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

      Правильно — увеличить размер слайса и сдвинуть все элементы на нужный offset и установить новый элемент (или несколько элементов):

      s = append(s, 0)
      copy(s[i+1:], s[i:])
      s[i] = x
      


      1. SirEdvin
        30.10.2015 13:38

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

        А как же синтаксический сахар?


        1. Alex_At_Net
          30.10.2015 13:49

          Много сладкого вредно для здоровья :)

          Если вам нужно собрать в один массив несколько массивов и чисел — вы сами решайте как вам это нужно сделать, в каком порядке и т.д. К вашим услугам append, make, и copy — вполне лаконичные и простые операции. Понять потом код очень просто.


          1. SirEdvin
            30.10.2015 13:55
            +1

            Просто я не знаю Go, но разбираюсь по статье.
            Я могу написать что-то похожее на:

            append(arr1,1,arr2,3,arr4,5)
            

            ?


            1. Alex_At_Net
              30.10.2015 20:20

              Нельзя, к сожалению. У append только одна реализация, которая проверяет тип при вставке.

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

              Как то append<T'>(slice []T', e []T'|T'...) — сложновато…


              1. divan0
                30.10.2015 21:22

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


                1. alexeibs
                  30.10.2015 23:38
                  +1

                  То, что сложно для компилятора, не всегда сложно для человека. Смысл выражения append(arr1,1,arr2,3,arr4,5) вполне очевиден, особенно если функцию назвать join, а не append


    1. vintage
      31.10.2015 13:49

      А лучше так:

      numbers = numbers[0..2] ~ 0 ~ numbers[2..$];


      1. SirEdvin
        31.10.2015 14:01
        +1

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


        1. vintage
          31.10.2015 14:14
          -1

          Это конкатенация. Слово «append» тоже не говорит, что это соединение массивов, а не, например, добавление записей в файл :-)


    1. dmbreaker
      01.11.2015 12:39
      +1

      Строгий язык не может быть удобным.

      Конечно. Равно как и хорошим.
      А если серьезно — язык должен быть удобным не для написания кода, а в первую очередь для его сопровождения. И тут строгость Go на вашей стороне. Потому что поддерживать код на Go — УДОБНО.
      Правда я так и не увидел аргументов (т.е. конкретных примеров) как строгость делает язык неудобным. Следуя такой логике можно дойти до того, что JavaScript/PHP очень удобные языки. Удобнее Питона и тем более Java/C#. Но я бы не согласился с такими утверждениями.


      1. SirEdvin
        01.11.2015 13:43

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

        Все дело в ограничениях, которые накладывает на вас язык.
        Подуймайте, какой костыль нужно будет соорудить, что бы написать, например, удобные матрицы на языке Go для различных типов данных. Сколько раз вам нужно будет просто копировать туда-сюда код? А теперь представьте, что вы еще добавили изменение в один тип матрицы, и вам нужно перенести их в другие…
        Вы считаете, это удобно?
        Следуя такой логике можно дойти до того, что JavaScript/PHP очень удобные языки. Удобнее Питона и тем более Java/C#. Но я бы не согласился с такими утверждениями.

        Внезапно, но вроде как именно этот пункт выставляется одним из основных преимуществ Node.js для новичков.
        Потому что писать различные веб-приложение на JavaScript или Python (серверную часть) куда проще и удобнее, а следовательно и быстрее, чем на Java/C#.
        язык должен быть удобным не для написания кода, а в первую очередь для его сопровождения.

        Это сложный дисскусионный вопрос. Что лучше, потратить больше времени на написание самого кода или на его review и комментирование?


        1. VoidEx
          01.11.2015 13:48
          +2

          А вы про какую строгость говорите?


          1. SirEdvin
            01.11.2015 16:30

            Вроде как о наличии различных синтаксических соли и сахара.


        1. dmbreaker
          01.11.2015 15:04

          То, что в языке нет generics — я тоже не считаю плюсом. Но это ничего не говорит про дизайн языка. Есть множество языков, где их нет, во многих они появились не сразу. Вполне возможно, что и в Go 2.0 (например) они таки будут.

          Внезапно, но вроде как именно этот пункт выставляется одним из основных преимуществ Node.js для новичков.

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

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

          Быстрее «наговнокодить» имелось в виду? :)

          Сопровождение — это не review и комментирование, а debugging и внесение серьезных изменений в приложение. А эти моменты — часто отнимают куда больше времени, нежели «первичное» написание кода.
          И да — писать на Go быстро. Не так быстро как на Питоне, но сравнимо с Java/C# и быстрее, чем на C++.


          1. SirEdvin
            01.11.2015 16:35

            То, что в языке нет generics — я тоже не считаю плюсом.

            Как там фраза про «Язык уже закончен и развиваться не будет»?
            Сопровождение — это не review и комментирование, а debugging и внесение серьезных изменений в приложение. А эти моменты — часто отнимают куда больше времени, нежели «первичное» написание кода.

            Если проект был нормально спроектирован и code review проводилось с целью поддерживать эту архитектуру, то проблем не будет. Аналогично, если написать плохую архитектуру на Go, с ней будут такие же проблемы.

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


            1. dmbreaker
              01.11.2015 16:42

              Если проект был нормально спроектирован

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


  1. namespace
    30.10.2015 10:12
    +25

    Так-так, что тут у нас сегодня? Ничего нового, в Go одни правильные решения, все пытаются делать из него питон и совать свои закоренелые паттерны. Ну, что я могу сказать? Хорошо.


  1. danslapman
    30.10.2015 10:18
    +23

    По большей части я согласен скорее с вами, чем с автором оригинальной статьи. Кроме одного пункта — пункта 7.
    Комментарии по определению это такие пометки, присутствие или отсутствие которых в коде не меняет поведения кода. Так во всех языках. Ну, разве что в Python встречаются любители хранить метаданные в docstring'ах, но их даже коллеги за это колотят. А тут вы говорите, что вызывать из комментариев кодогенератор — это норма. Кодогенератор, Карл! Да даже в C++ максросы сделаны лучше. А что, если этот комментарий сольётся с комментарием к функции ниже? В общем, можно сколько угодно защищать такое решение, ссылаясь на авторитет Пайка, но это реально выглядит на решение из разряда «да ну, для одного кейса не будем прагмы добавлять, сделаем магический комент и так сойдёт»


    1. neolink
      30.10.2015 10:31
      -3

      это машиночитаемый комментарий он автоматом ничего не вызывает, для него существует отдельная команда, которую надо запускать руками.
      по смыслу — стандартизовали то, что уже использовали люди, только они это писали в make файлах или так же в комментариях: https://github.com/golang/net/blob/master/html/atom/gen.go.
      Это чтобы например на основе описания protobuf сгенерировать исходный код на go и т.п.


      1. danslapman
        30.10.2015 11:03
        +21

        Стандартизировать костыли — божественный подход к дизайну


        1. neolink
          30.10.2015 11:26
          -2

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

          ну и в тему про магические комментарии:
          https://github.com/golang/go/blob/master/src/runtime/wbfat.go#L6
          https://github.com/golang/go/blob/master/src/runtime/wbfat_gen.go#L5


          1. Gorthauer87
            30.10.2015 11:28

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


          1. danslapman
            30.10.2015 11:32
            +10

            Магические комментарии — это костыль. Претензии к тому, КАК сделали.


            1. neolink
              30.10.2015 12:07
              -2

              магические комментарии — это суть есть аннотации, как один из вариантов размещения неких метаданных в коде, чем "@NotNull" принципиально отличается от //go:nosplit или //go:generate?


              1. danslapman
                30.10.2015 12:21
                +7

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

                Аннотация явно говорит «тут делаются разные дела»
                В случае комментария может быть так:

                //go:generate toolname -params -blabla
                //Hey! Look at my awesome function Blabla
                //Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                //Donec tortor erat, rhoncus ac turpis id, ullamcorper congue odio
                func Blabla() {
                    // code...
                }
                


                1. neolink
                  30.10.2015 13:09

                  вас смущает, что go doc зацепит этот комментарий к функции Blabla?


                  1. lair
                    30.10.2015 13:15

                    Меня, кстати, смущает.

                    (скажем, в C# просто комментарии и документационные комментарии отличаются)


                    1. neolink
                      30.10.2015 13:22

                      не писал на c#, не могу сходу представить что вы имеете ввиду


                      1. lair
                        30.10.2015 13:27
                        +1

                        public class SomeClass
                        {
                          ///<summary>Это пойдет в документацию</summary>
                          ///<remarks>И это пойдет в документацию</remarks>
                          ///<param name="f">f-word</param>
                          ///<returns>a swear based on <paramref name="f"/></returns>
                          //а тут программист может писать что угодно, это не войдет ни в какую документацию
                          public bool WhatThe(string f)
                          {
                          }
                        }
                        


                        Естественно, все это поддерживается IDE и на уровне автодополнений, и на уровне показа подсказок при наведении на использование.


                      1. danslapman
                        30.10.2015 13:28
                        +1

                        Там есть вот такой комментарий

                        //Это комментарий
                        

                        а есть вот такой
                        ///Эта функция считает синусы
                        


                        из комментариев второго типа генерируется документация, из комментариев первого — нет


                        1. neolink
                          30.10.2015 13:31

                          аналог на go:
                          // это просто коммент

                          // а это информация о работе функции, она пойдет в godoc
                          func DoCool() {
                          }


                          1. danslapman
                            30.10.2015 13:34

                            В вашем же примере github.com/golang/go/blob/master/src/runtime/wbfat.go#L6
                            //go:nosplit пойдёт в godoc
                            Это норма, да?


                            1. neolink
                              30.10.2015 13:37
                              +1

                              он не пойдет в godoc — это приватная функция


                              1. mirrr
                                31.10.2015 11:26

                                Если я не ошибаюсь дока должна еще начинаться с названия метода?

                                // это просто коммент
                                
                                // DoCool а это информация о работе функции, она пойдет в godoc
                                func DoCool() {
                                }
                                


                            1. divan0
                              30.10.2015 16:57
                              +2

                              Это не норма. nosplit и noescape — это внутренности компилятора и рантайма, в реальном коде вы ничего подобного не пользуете. //go:generate, если уж понадобилось, вы пишете единожды в заголовке файла, а не где попало. Обсуждаемая выше проблема — чистой воды теоретизирование.


                              1. danslapman
                                30.10.2015 17:18
                                +2

                                Обсуждаемая выше проблема — чистой воды теоретизирование

                                Как будто это делает решение поместить в комментарии инструкции для кодогенератора или «внутренности компилятора и рантайма» long-term хорошим решением.


                                1. divan0
                                  30.10.2015 18:21

                                  А что, по вашему, будет хорошим решением?


                                  1. SirEdvin
                                    31.10.2015 00:57
                                    +3

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


                                    1. divan0
                                      31.10.2015 02:31
                                      -4

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


                                      1. SirEdvin
                                        31.10.2015 09:59
                                        +2

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

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

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

                                        А это плохо.


                                        1. divan0
                                          31.10.2015 19:18
                                          -3

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

                                          Раз избранный, то поясню — новая сущность в Go 1.5 == ошибка компиляции в Go 1.4.
                                          Не за что.

                                          А это плохо.

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


                                          1. lair
                                            31.10.2015 19:23
                                            +3

                                            Раз избранный, то поясню — новая сущность в Go 1.5 == ошибка компиляции в Go 1.4.

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


                                          1. SirEdvin
                                            01.11.2015 00:29
                                            +3

                                            Раз избранный, то поясню — новая сущность в Go 1.5 == ошибка компиляции в Go 1.4.

                                            Очень смешно звучит. То есть Go 1.5 совсем не добавляет ничего нового в сравнении с Go 1.4? Я вас правильно понял?

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

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

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


                                            1. divan0
                                              01.11.2015 00:37
                                              -3

                                              То есть Go 1.5 совсем не добавляет ничего нового в сравнении с Go 1.4? Я вас правильно понял?

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

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

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

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

                                              Согласен. Только непонятно, про какой вы язык говорите.


                                              1. SirEdvin
                                                01.11.2015 00:39
                                                +6

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

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

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

                                                Я говорил про комментарий. То, что он должен исходит из его определение.

                                                Согласен. Только непонятно, про какой вы язык говорите.

                                                Про Go, в котором комментарии были заменены на метаданные.


                                                1. divan0
                                                  01.11.2015 01:16
                                                  -2

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

                                                  Я к ней аппелирую, потому что это один из моментов, по которым принимаются решения. Уже писал, что дизайн языка — это не черное и белое, и не бинарный выбор «очевидно, что это должно быть так» и «не так». Неужели это и вправду нужно разъяснять 15 комментариев подряд?

                                                  Я говорил про комментарий. То, что он должен исходит из его определение.

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

                                                  Про Go, в котором комментарии были заменены на метаданные.

                                                  В Go не заменяли комментарии на метаданные.


                                                  1. SirEdvin
                                                    01.11.2015 01:31
                                                    +3

                                                    Я к ней аппелирую, потому что это один из моментов, по которым принимаются решения. Уже писал, что дизайн языка — это не черное и белое, и не бинарный выбор «очевидно, что это должно быть так» и «не так». Неужели это и вправду нужно разъяснять 15 комментариев подряд?

                                                    А прямая совместимость бинарная. Она или есть, или ее нет. Как я понял, в Go ее нет. Смысла на ее ориентироваться нет, раз ее нет.
                                                    Вы просто привели бесполезный аргумент и все.
                                                    В Go не заменяли комментарии на метаданные.

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

                                                    По определению самолёт — должен летать.

                                                    В нашем случае, самолет совершает телепортацию, а не летает.

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


                                                  1. creker
                                                    01.11.2015 02:41
                                                    +5

                                                    Сколько вы пишете на Go, кстати?

                                                    А вот и пошли аргументы в стиле «сначала добейся».

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


                                                    1. divan0
                                                      01.11.2015 02:54
                                                      -1

                                                      А вот и пошли аргументы в стиле «сначала добейся».

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


                                                      1. SirEdvin
                                                        01.11.2015 16:29
                                                        +3

                                                        Если же это «не пробовал, но порицаю», то ценность такой дискуссии нулевая.

                                                        Плохие практики в разных языках так же отлично решают свои задачи.
                                                        Например, что бы понимать, что generic в Java сделаны плохо, не обязательно иметь опыт работы с ней. Они объективно плохи.

                                                        Так же, как решение заменить комментарии на некую другую сущность.


                                                        1. grossws
                                                          01.11.2015 20:02
                                                          +1

                                                          Дизайн generics в java с type erasure оправдан. Реализация позволяет сохранить прямую и обратную совместимость с 1.4, что для enterprise-пользователей является очень существенным фактором.

                                                          Т. е. в библиотеку, написанную и скомпилированную под java 1.4 можно передавать generic-объекты из кода под 1.5 и наоборот.

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


                                                          1. s-kozlov
                                                            01.11.2015 22:48

                                                            Дизайн generics в java с type erasure оправдан. Реализация позволяет сохранить прямую и обратную совместимость с 1.4, что для enterprise-пользователей является очень существенным фактором.


                                                            Это не отменяет того факта, что generics в java — костыль. Единственная причина, по которой их сделали именно так — недальновидность создателей первой версии Java.

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


                                                            Приведите пример задачи, в которой type erasure выгоднее по сравнению с нормальными generics (как в C#).


                                                            1. grossws
                                                              01.11.2015 23:19
                                                              +1

                                                              Единственная причина, по которой их сделали именно так — недальновидность создателей первой версии Java.
                                                              Если пытаетесь намекать на дальновидность разработчиков .NET, который появился в 2000, то стоит посмотреть на то, что java появилась в 1995.

                                                              В C# generics появились тоже не сразу (2006, против 2004, когда они появились в java). И в случае .NET как-то не очень заморачивались совместимостью .NET 1.1 и 2.0.

                                                              У Java иной подход — сохранение совместимости. И во всех задачах, когда была необходимость использовать старый код в новом окружении (без какой-либо модификации и перекомпиляции) type erasure выигрывает по сравнению с переписыванием кода или запуском его различных кусков под разными версиями CLR.


                                                              1. qnikst
                                                                02.11.2015 00:01
                                                                +3

                                                                Однако параметрический полиморфизм, то, что в java почему-то назвается Generics, (без подтипирования) появился аж в 1975 году, так что это не оправдание. Кстати, это же объясняет почему, в Go его нету, туда настолько молодые фичи не попадают.


                                                              1. s-kozlov
                                                                03.11.2015 07:25

                                                                Опять отмазки пошли.

                                                                Я знаю, что java появилась давно. Я знаю, что обратная совместимость и бла-бла-бла.

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

                                                                Если бы Java проектировали сегодня, никто бы не делал type erasure.


                                                              1. s-kozlov
                                                                03.11.2015 07:27

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

                                                                Приведите пример задачи, в которой type erasure выгоднее по сравнению с нормальными generics (как в C#).


                  1. danslapman
                    30.10.2015 13:26
                    +1

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

                    //Hey! Look at my awesome function Blabla
                    //go:generate toolname -params -blabla
                    //Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                    //Donec tortor erat, rhoncus ac turpis id, ullamcorper congue odio
                    func Blabla() {
                        // code...
                    }
                    


                    Ну прямо ОЧЕНЬ заметно, что тут аннотация в комментариях. В общем, в других языках, которые тоже компетентные люди проектируют, такие вещи выделяют в отдельные сущности, Пайк же посчитал, что это СЛОЖНО. Ну ок, я его понял, но по-моему технология для инженеров не должна ориентироваться на дебилов…


                    1. divan0
                      30.10.2015 19:13
                      -1

                      Если бы вы писали на Go, вы бы понимали, почему нет оснований полагать, что кто-нибудь так напишет. А если и напишет, то ничего страшного не произойдет. С таким же успехом можно говорить «Tesla — плохой автомобиль, потому что кто-то можно положить пальто на тачскрин и не сможет его видеть». Попробуйте на практике и судите о дизайне по делу, а не по придуманным кейсам.


                      1. danslapman
                        30.10.2015 19:42
                        +1

                        Конкретно насчёт этого я сейчас немного разобрался и понимаю, что неправ.


              1. david_mz
                30.10.2015 13:18
                +10

                Тем что это части синтаксиса языка.

                Почему-то мало кто понимает, что «магические комментарии» в Go — это вообще не комментарии. go generate не парсит go-код, она тупо ищет подстроку. Посмотрите вот на такой код: http://play.golang.org/p/BwHvNiZggA — go generate найдёт тут свою инструкцию и попробует её исполнить, хотя она и не в комментарии.

                Я люблю Go, но вот это конкретное место — это очень плохой дизайн. Имхо.


          1. 0xd34df00d
            30.10.2015 20:33

            Автогенерация кода тоже костыль. См. хаскелевские template haskell (который на самом деле тоже кривоват и костыль) и generics.


            1. qnikst
              30.10.2015 21:34
              +1

              TH это, кстати канонический пример костыля, т.к. радостно ломает абстракции (скрывает типы за ExpQ), в отличии от Generics, и даже появляющийся Typed-TH не очень поможет в силу ограничений. (Правда в отличии от generics позволяет генерировать более эффективный код, с расширениями generics такое тоже возможно, но уже не так просто). Естественно плюс TH, в отличии от, насколько я понимаю, go, в том, что генерация производится средствами языка, что не мешает вызывать внешние утилиты если необходимо. А совсем хороший вариант в MetaOcaml, например.


              1. 0xd34df00d
                30.10.2015 21:36

                Именно. Даже костыльный TH лучше условного {-# hask-henerate ...#-}.
                Хотя стоп, какие {-#, у нас же нет прагм, пусть будет обычный --.

                А MetaOcaml я не тыкал :(


        1. DaylightIsBurning
          30.10.2015 20:38
          +2

          Магические комментарии — это костыль. Претензии к тому, КАК сделали.
          Лучший критический комментарий за два поста, imho.


          1. divan0
            30.10.2015 21:27

            «Костыль» — это ярлык, не более. Shebang — это тоже такой-же «костыль», что не мешаем ему исправно выполнять свою функцию на всех UNIX-системах, не так ли?
            Так что важнее — практическая польза или чей-то ярлык «костыля»? Какие реальные практические проблемы с go generate были хотя бы у одного из комментаторов тут? Да ни у кого.

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


            1. splav_asv
              30.10.2015 21:51
              +1

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


      1. Gorthauer87
        30.10.2015 11:10
        +7

        По сути дела они придумали препроцессор, но сделали вид, что они не при делах.


        1. neolink
          30.10.2015 11:18
          +1

          с make сравнили бы ещё ладно, но это не препроцессор


          1. Gorthauer87
            30.10.2015 11:31
            +4

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


            1. neolink
              30.10.2015 11:37

              По факту запускается любая команда, это как тоже самое, что сказать make или bash это препроцессор.
              Эти запуски не как не связаны с процессом компиляции, в зависимостях которые вы ставите они не вызываются, только запуски руками.
              Почитайте https://blog.golang.org/generate, возможно просто я плохо объясняю.


              1. Gorthauer87
                30.10.2015 13:52
                +2

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


                1. neolink
                  30.10.2015 13:56

                  Не всё что решается генерацией можно решить обобщенным программированием. Примеры с генерацией парсеров и тп.


                  1. Gorthauer87
                    30.10.2015 14:09

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


                    1. neolink
                      30.10.2015 14:31

                      ну если вы начнете читать, что вам люди пишут может даже диалог получится.
                      //go:generate go tool yacc -o gopher.go -p parser gopher.y
                      как думаете что такое yacc?


                      1. splav_asv
                        30.10.2015 17:11
                        +2

                        yet another compiler compiler — генератор парсеров?


                        1. Ramires
                          30.10.2015 17:18

                          Отсюда:

                          Yacc is a computer program for the Unix operating system. The name is an acronym for «Yet Another Compiler Compiler». It is a LALR parser generator


                    1. 0xd34df00d
                      30.10.2015 20:35
                      +1

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


                  1. encyclopedist
                    30.10.2015 14:37
                    +3

                    Ну вот Boost.Spirit обходится без препроцессоров.


                    1. 0xd34df00d
                      30.10.2015 20:35
                      +3

                      Даже parsec обходится без препроцессоров!


  1. mikka
    30.10.2015 10:32
    +22

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


    1. divan0
      30.10.2015 16:59
      -2

      Нападки на языки — это упоминание С++ в эпилоге?


      1. Ramires
        30.10.2015 17:04
        +1

        По-видимому, Вы пропустили мой комментарий ( хотя это неудивительно, их тут уже 120+ ).


        1. dmbreaker
          01.11.2015 15:07
          -3

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


          1. VoidEx
            01.11.2015 19:46
            +2

            Я писал на C++, теперь на C++ и Haskell, но отчего-то боли не ощущаю :)


  1. Daniro_San
    30.10.2015 10:38
    -17

    Go никому не нужен.
    Программист C++ легко освоит его, это да.
    Но в обратном я сомневаюсь.


    1. IncorrecTSW
      30.10.2015 10:53
      +5

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


      1. Daniro_San
        30.10.2015 10:57
        -11

        После того как меня «отхабрили» в предыдущем обсуждении Go, мне стало все равно.


        1. Suvitruf
          30.10.2015 11:05
          +13

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


        1. Alexeyco
          30.10.2015 11:24
          +8

          То есть, Go — плохой из-за того, что вас «отхабрили»? ))


    1. i360u
      30.10.2015 11:16
      +5

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


  1. yatagarasu
    30.10.2015 10:58
    +1

    а чёрт надо кофе с утра больше пить


    1. yul
      30.10.2015 13:30

      Эм, не стоит, тем более в выходной.


      1. yatagarasu
        30.10.2015 13:44
        +3

        Хорошо вам, пятница — выходной.


        1. Suvitruf
          30.10.2015 14:04

          Может человек в Эмиратах живёт)


          1. danslapman
            30.10.2015 14:15
            +4

            Тогда ему вдвойне хорошо)


  1. Alexeyco
    30.10.2015 11:18
    +7

    > Некоторым людям сложно даётся факт, что никакие языки, кроме Питона, не являются Питоном
    Золотые слова… я сам очень уважаю Питон, но Go — не Питон, а Питон — не Go…


  1. creker
    30.10.2015 11:25
    +31

    Статья же автора о том, что дизайн языка «плохой» — это, к сожалению, не более, чем попытка привлечь к себе внимание

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


    1. divan0
      30.10.2015 17:05
      -6

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


      1. creker
        30.10.2015 17:31
        +6

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


        1. divan0
          30.10.2015 18:20
          +1

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


      1. Alex_At_Net
        30.10.2015 20:37
        +1

        Таки я угадал не имея опыта общения с автором. Как прочитал, себя вспомнил лет 15 назад :-D


    1. dmbreaker
      01.11.2015 15:10
      -1

      Ну почему никто не пишет таких статей про C++? Там же на 100500 статей косяков наберется! Косяки Go — это мелкие шалости в сравнении с этим монстром!


      1. grechnik
        01.11.2015 15:49
        +4

        Ну почему же никто? Из самого масштабного — www.yosefk.com/c++fqa. Просто в мире C++ в ответ на такие статьи выходят новые версии языка, а не ответные статьи в стиле «в языке этого нет, поэтому вам это не нужно».


        1. dmbreaker
          01.11.2015 16:43
          -2

          Не смешите — проблема поддержки юникода возникла не вчера. В какой версии C++ стал из коробки поддерживать его?


          1. creker
            01.11.2015 17:29
            +2

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


            1. dmbreaker
              01.11.2015 17:51

              Есть. Только поддержки unicode от этого не прибавляется.


              1. creker
                01.11.2015 18:20
                +2

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


                1. Lol4t0
                  01.11.2015 20:01
                  +1

                  Да ничего та нет. Ни конертации в локаль/UTF8 и обратно, ни поддержки работы с суррогатными парами. Есть «массив-байтов» (string) и «массив-непонятно-чего»(wstring)


                  1. Ramires
                    01.11.2015 20:10

                    Ни конертации в локаль/UTF8 и обратно

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

                    Можно пояснить, что это?


                    1. Lol4t0
                      01.11.2015 20:32
                      +1

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

                      Про второе, ну вот, например, смотрите, очевидно, что й и и? — одна и та же буква, но на на самом деле это й и и&#774;. С++ это не поймет


                      1. grechnik
                        01.11.2015 20:36
                        +1

                        А есть какой-то язык, который поймёт это из коробки?


                        1. lair
                          01.11.2015 22:13
                          +4

                          Любой на платформе .net. Вот, скажем, F#:

                          > let s1 = "й";;
                          val s1 : string = "й"
                          > let s2 = "и\u0306";;
                          val s2 : string = "и?"
                          > s1.Length;;
                          val it : int = 1
                          > s2.Length;;
                          val it : int = 2
                          > System.StringComparer.CurrentCulture.Equals(s1, s2);;
                          val it : bool = true
                          


                      1. grossws
                        01.11.2015 20:39

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

                        Про второе, ну вот, например, смотрите, очевидно, что й и и? — одна и та же буква, но на на самом деле это й и и?. С++ это не поймет
                        Вы про collation? IO без разницы какой вариант нормализации вы применяете, выведет как есть.

                        Это ж не python2 у которого при выводе utf8 у танка отваливается башня, если вывод перенаправили/отправили в pipe.


                        1. Lol4t0
                          01.11.2015 20:44

                          Проблема в том, что IO как раз хорошо бы знать Потому что

                          (1) работать удобно с UTF-16, а пистаь/читать в файлы в UTF-8
                          (2) На некоторый системах (не будем показывать пальцем) консоль не понимает UTF, а понимает какой-ниюудь CP866

                          А при работе нужно чтобы поиск/замена понимали, что символ UTF8 может состоять из нескольких байт и даже слов UTF16


                          1. encyclopedist
                            01.11.2015 21:47

                            Работать с UTF-16 совсем неудобно. Он имеет все проблемы UTF-8 (символы имеют переменную длину).
                            Работать надо с настоящими code points. А любые кодировки — они для ввода-вывода только.
                            И поодержка этого кстати в C++ таки есть.


                            1. Lol4t0
                              01.11.2015 21:56

                              Ну хорошо, я согласен, будем считать, что я имел в виду «настоящие code points» :)

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


                          1. VoidEx
                            01.11.2015 23:17

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


                            1. grossws
                              01.11.2015 23:27

                              Это хорошо пока вам не надо, например, делать case insensitive поиск/замену, где в бой вступает collation. Или замену символов с диакритикой из пользовательского ввода, где они могут быть как в decomposed так и в composed вариантах.


                              1. VoidEx
                                01.11.2015 23:51

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


                            1. Lol4t0
                              01.11.2015 23:39

                              чтобы вот это работало, например

                              #include <iostream>
                              #include <string>
                              
                              int main() {
                                  std::string s {"пр?вет, мир"};
                                  s[s.find('?')] = 'и';
                                  std::cout << s << '\n';
                              }
                              


                              1. VoidEx
                                01.11.2015 23:55

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


                                1. Lol4t0
                                  02.11.2015 00:03

                                  Суперинтуитивно!

                                  А по факту тип char и string::operator[] не работают


                                  1. VoidEx
                                    02.11.2015 11:29

                                    А они где-то работают? Например лигатура ае может быть как одной, так и двумя буквами в зависимости от языка. И как взять в слове vae третью букву?


                                    1. lair
                                      02.11.2015 11:45

                                      А они где-то работают?

                                      Угу.

                                      > let s1 = "vae";;
                                      val s1 : string = "vae"
                                      > let s2 = "v\u00e6";;
                                      val s2 : string = "v?"
                                      
                                      > System.StringComparer.InvariantCulture.Equals(s1, s2);;
                                      val it : bool = true
                                      > System.StringComparer.Ordinal.Equals(s1, s2);;
                                      val it : bool = false
                                      


                                      И как взять в слове vae третью букву?

                                      > s1.[2];;
                                      val it : char = 'e'
                                      > s2.[2];;
                                      System.IndexOutOfRangeException: Index was outside the bounds of the array.
                                      


                                      1. VoidEx
                                        02.11.2015 11:50
                                        -1

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


                                        1. lair
                                          02.11.2015 13:22

                                          Знаете, мне кажется, что это упирается в требование к «работает». С моей точки зрения, семантика (различная!) обоих типов (и строк, и символов) передана верно.

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


                                          1. VoidEx
                                            02.11.2015 14:12

                                            Я ссылался на этот комментарий.


                                            1. lair
                                              02.11.2015 14:14
                                              +2

                                              Ну, как раз проблема «символ может состоять из нескольких байт» в моем примере успешно решена: адресация внутри [] идет посимвольно. а не побайтно.


                                              1. VoidEx
                                                02.11.2015 14:42

                                                Как раз нет. Обе эти строки — одно и то же слово, и в нём одна и та же третья буква — «e». А вот если взять другой язык, где есть буква "?", то это будут разные слова, а посему операция взятия n-ой буквы должна ещё и культуру принимать.
                                                ? — это две буквы (или одна, смотря какой язык), но code point в данном случае — один, хотя опять же, ту же «й» можно выразить двумя code point'ами. Операция индексации ж должна корректно взять третью букву в слове «май», даже если «й» там из двух «символов».


                                                1. lair
                                                  02.11.2015 14:52
                                                  +2

                                                  Обе эти строки — одно и то же слово, и в нём одна и та же третья буква — «e».

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

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


                                                  1. VoidEx
                                                    02.11.2015 14:57

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


                          1. grossws
                            01.11.2015 23:20

                            С чем работать удобнее — зависит от приложения. Иногда удобнее с utf8, иногда с utf32, иногда с utf16, а иногда и с bocu1. IO не должно это ограничивать.

                            В той же java есть два слоя io: input/output streams (или *channel+*buffer, если говорить про nio), которые оперируют байтами, и reader/writer, которые оперируют символами, кодируемыми в соответствии с параметрами конкретного reader/writer.

                            Про legacy-систему, где консоль «типа» 866, а на самом деле — смесь 866 и 1251 (параметры в argv передаются в cp1251) лучше постараться забыть, как страшный сон =)

                            А при работе нужно чтобы поиск/замена понимали, что символ UTF8 может состоять из нескольких байт и даже слов UTF16
                            Это вопрос к используемому вами движку regexp. Он не обязательно входит в стандартную библиотеку. И не обязательно одинаков между системами в том случае, когда входит в неё.

                            Что означает «символ UTF8 может состоять из нескольких байт и даже слов UTF16» мне не понятно. Набор codepoint'ов может быть представлен в utf8, utf16le или utf16le. Если есть CP от U+10000 до U+10ffff, то он будет представлен в виде суррогата в utf16 и в виде 4 байт в utf8.


                            1. Lol4t0
                              01.11.2015 23:45

                              Про legacy-систему, где консоль «типа» 866, а на самом деле — смесь 866 и 1251 (параметры в argv передаются в cp1251) лучше постараться забыть, как страшный сон =)
                              Суть в том, что страшным сном оно становится как раз из-за того, что в C++ нет нормальной поддержки строк, которая бы брала всю работу по конвертации на себя.

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

                              Это вопрос к используемому вами движку regexp. Он не обязательно входит в стандартную библиотеку.
                              Я даже не про regex. Но он, кстати, сейчас входит в стандартную библиотеку.

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


                              1. splav_asv
                                01.11.2015 23:52

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

                                Независимо от поддержки unicode программой, изменить кодировку консоли вроде бы нереально. И как прикажете писать в консоль с cp866 произвольные символы?

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


                                1. Lol4t0
                                  01.11.2015 23:58

                                  Во-первых, как минимум можно корректно все парсить всегда в одну кодировку независимо от текущей локали (argv, std::cin)

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


                                1. creker
                                  02.11.2015 00:06

                                  Если речь про cmd, то всегда можно использовать chcp 65001, если сменить в свойствах консоли шрифт. UTF8 батч файлы начинают говорить на разных языках.


                                  1. splav_asv
                                    02.11.2015 01:21

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


                                    1. Lol4t0
                                      02.11.2015 01:25

                                      SetConsoleOutputCP


                  1. grechnik
                    01.11.2015 20:23

                    В C++11 добавили char16_t, char32_t и u16string, u32string как альтернативу «непонятно чему» wchar_t и wstring, а также <codecvt> в целом и codecvt_utf8 в частности для конвертации, включая суррогатные пары.


                    1. grossws
                      01.11.2015 20:33

                      суррогатные пары
                      Суррогаты есть только в utf16, т. к. не всякий codepoint может быть представлен одним uint16. В utf8 этой проблемы нет.
                      Возможно, вы имели ввиду не суррогатные пары, а формы нормализации (всякие NCD/NFC/NFKD/NFKC).


                      1. grechnik
                        01.11.2015 20:35

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


                      1. Lol4t0
                        01.11.2015 20:37

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


                    1. Lol4t0
                      01.11.2015 20:36
                      -2

                      Ок, простой тест

                      #include <iostream>
                      int main() {
                      std::cout << "привет, мир\n";
                      }
                      

                      уже работает на всех системах одинаково, печатая «првиет, мир»?


                      1. grechnik
                        01.11.2015 20:46
                        +1

                        Ну да, копирует на stdout строку в той же кодировке, в которой она введена в исходнике. (Если вы намекаете на виндовую консоль с её legacy cp866 — перенаправьте вывод в файл.) Для этого поддержка unicode не нужна вообще.


                        1. Lol4t0
                          01.11.2015 20:55
                          -2

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


                          1. grechnik
                            01.11.2015 21:24
                            +4

                            Эм. А чего вы хотели, сказав просто отправить массив байт в поток? Хотите конвертации по дороге — так и говорите:

                            #include <iostream>
                            #include <locale>
                            #include <codecvt>
                            int main() {
                                // вариант 1: просто конвертируем строку wchar_t -> utf8
                                std::cout << std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(L"привет, мир\n");
                                // вариант 2: объясняем потоку, чтобы он конвертировал wchar_t -> utf8 при выводе
                                std::wcout.imbue(std::locale(std::wcout.getloc(), new std::codecvt_utf8<wchar_t>()));
                                std::wcout << L"привет, мир\n";
                            }
                            


                            1. Lol4t0
                              01.11.2015 21:44
                              -1

                              1) Я не хочу ничего говорить, я хочу, чтоб строка текста выводилась как текст. Всякие кодировки оставьте в прошлом веке.
                              2) Я не хочу конвертировать в utf8, я хочу чтобы строка выводилась строкой и на Linux, и в Windows, и на светодиодном табло.


                              1. encyclopedist
                                01.11.2015 21:50
                                +3

                                А я наоборот хочу работать с байтами.

                                С++ как раз такой язык который делает ровно то что попросили. Нужна определённая кодировка — попросите об этом. Нужны байты — будут байты.


                                1. Lol4t0
                                  01.11.2015 21:53
                                  -2

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


                              1. farcaller
                                03.11.2015 10:54

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


                              1. withkittens
                                03.11.2015 13:57
                                +2

                                1) Я не хочу ничего говорить, я хочу, чтоб строка текста выводилась как текст. Всякие кодировки оставьте в прошлом веке.
                                В какой кодировке? Текста без кодировки не существует. Строка — суть просто набор байтов.

                                Ну вот я прошу кодировку «чтоб было читаемо независимо от того, куда идет вывод и на какой системе». Как?
                                Utf-8?


                                1. grossws
                                  03.11.2015 14:27
                                  +1

                                  Ещё хуже, т. к. представление одного и того же текста (как упорядоченного набора глифов) не единственно даже в рамках одной кодировки.


                                1. Lol4t0
                                  03.11.2015 17:28
                                  -2

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


                                  1. creker
                                    03.11.2015 17:54
                                    +2

                                    Ну числа это тоже числа, однако в памяти это наборы байтов в определенном порядке. И знать little или big endian это надо, если хочется, чтобы вывелось правильно везде. Тут тоже самое. Текста в понятиях ПК не существует. Есть текст — суть, байты, которые в определенной кодировке дают текст на экране. А в другой уже не дают. Без кодировка нет текста, будь это UTF или даже просто ASCII. И я не видел ниодного рантайма, который бы не упоминал этих понятий. Просто напросто невозможно в полной мере манипулировать байтами, когда кодировка их содержимого неизвестна.


                                    1. Lol4t0
                                      03.11.2015 18:25

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

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

                                      Понимаете ли, есть разные слои абстракций. little или big endian нужны, если вы разработчик сериализатора. Если вы только используете сериализтиор, то вам это совершенно не нужно. Знать про особенности представления строк нужно, если вы разрабатываете поддержку Unicode. Но если вы заставляете меня, как пользователя вашей библиотеки по работе с Unicode с этим разбираться — то вы плохой разработчик библиотеки для поддержки Unicode.


                                      1. VoidEx
                                        03.11.2015 18:39

                                        Да чего о строках говорить, когда у нас и чисел-то нет нормальных :)


                                        1. Lol4t0
                                          03.11.2015 19:57
                                          +1

                                          Да с числами вообще беда! Попробуйте-ка посчитать 42! на С++, напрмиер


                                  1. VoidEx
                                    03.11.2015 18:33
                                    +2

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

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


                                    1. Lol4t0
                                      03.11.2015 19:58
                                      -1

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


                                      1. VoidEx
                                        03.11.2015 21:40

                                        Так уж и всё?


                                    1. splav_asv
                                      03.11.2015 21:52

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


                                      1. withkittens
                                        03.11.2015 23:26
                                        +3

                                        Lol4t0,

                                        Нет. Строка — суть кусок текста. То, что вы там напридумывали — это все от бедности. Строка не может быть «просто набором байтов» хотя бы потому, что строкам и тексту уже тысячи лет, а эти ваши байты вот только придумали.
                                        Понимаете какая штука… Компьютеры оперируют только битами, в оперативной памяти нет никаких букв, текстов и строк, там и чисел-то так таковых нет. Даже чтобы получить обыкновенный int и то нужно знать сугубо вторичную для пользователя вещь: хранится ли это число в little-endian или big-endian. Считайте это «кодировкой» чисел. Если вы не знаете «кодировку», вы не сможете интерпретировать биты в виде числа.

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

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

                                        И знать про little или big endian нужно только в качестве разминки для ума, но для проведения вычислений эти знания не требуются — спросите любого бухгалтера.
                                        Вот тут и настаёт привет: пока числа на бумажке у бухгалтера, у них действительно нет никаких little- и bin-endian. Но это представление появляется, как только числа набирают кнопочками на клавиатуре.

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

                                        С остальным, про идеальные строки и взаимодействие с пользователем, я согласен. Но C++ так не работает, он плюётся байтами.


                                        1. withkittens
                                          03.11.2015 23:31
                                          +3

                                          The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!):

                                          The Single Most Important Fact About Encodings

                                          If you completely forget everything I just explained, please remember one extremely important fact. It does not make sense to have a string without knowing what encoding it uses. You can no longer stick your head in the sand and pretend that «plain» text is ASCII.

                                          There Ain't No Such Thing As Plain Text.

                                          If you have a string, in memory, in a file, or in an email message, you have to know what encoding it is in or you cannot interpret it or display it to users correctly.


                                        1. Lol4t0
                                          03.11.2015 23:42
                                          -3

                                          Понимаете ли какая штука… Природа оперирует только атомами, в природе нет никаких битов, байтов и кодировок, там и оперативной памяти как таковой нет.


                                      1. VoidEx
                                        04.11.2015 00:10

                                        Я-то согласен, но те же рассуждения применимы и к обычным числам, где приходится почему-то знать, сколько там байт внутри. Но много ли где умолчальный Int — безразмерен? А float/double?
                                        Ну да, умолчание в C++ — это дефолтная локаль, которая не факт что utf8 (особенно в случае с windows).


      1. stepanp
        01.11.2015 17:35
        +3

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


        1. dmbreaker
          01.11.2015 17:52
          -2

          Первой появилась статья негативная. А эта не восхваление, а восстановление статус кво.


          1. creker
            01.11.2015 18:24
            +3

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


          1. lair
            01.11.2015 19:21
            +3

            Далеко не первой.


  1. Lol4t0
    30.10.2015 11:30
    +29

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


  1. ingrysty
    30.10.2015 11:38
    +15

    Поэтому нужно переходить на Раст и никаких вам недостатков.
    Радуюсь ежедневно.


    1. koras_dor
      30.10.2015 12:50
      +3

      Мы рады, что вы радуетесь, а можно аргументировать? Почему это «поэтому»? Недостатки есть везде, нет ничего идеального.


      1. ingrysty
        30.10.2015 13:18
        +6

        Я использую силу плюсов других хабравчан за доказательство!


    1. 0xd34df00d
      30.10.2015 20:37
      +3

      На хаскель, пожалуйста.


  1. Daniro_San
    30.10.2015 11:42
    -18

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


    1. Bringoff
      30.10.2015 11:48
      +9

      Обида живет в груди глупых


      1. Daniro_San
        30.10.2015 12:16
        -17

        Вы правы. Не стоит обижаться на хомячков.


  1. Daniro_San
    30.10.2015 11:55
    -14

    Go не нужен.
    Почему?
    Asm все равно быстрее…


    1. TimsTims
      30.10.2015 17:56
      +3

      Ну хватит уже…


  1. deniskreshikhin
    30.10.2015 12:31

    Кстати, не подскажите, а как в Go обойти слайс в обратном порядке?


    1. ingrysty
      30.10.2015 12:43
      +2

      http://play.golang.org/p/9xjT-oHxfI


      1. deniskreshikhin
        30.10.2015 13:34
        -2

        Спасибо)

        Прочитал статью, и начал сомневаться в своем отношении к Golang.
        Но вы таки развеяли сомнения)

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

        Python:

        # Прямой обход
        for item in items:
            print item
        
        # Обратный обход
        for item in reversed(items):
           print item
        


        В Go
        // Прямой обход. Класс, прям как в Python
        for _, item := range items {
           fmt.Println(item)
        }
        
        // Обратный обход. О_о. ЧЗНХ?
        for i := len(items) - 1; i >= 0; i = i - 1 {
           fmt.Println(items[i])
        }
        


        1. ingrysty
          30.10.2015 13:55
          +2

          Проблема в том, что скрывается за функцией «reversed» и какие операции оно выполняет :)
          И в итоге все становится на свои места.


          1. lair
            30.10.2015 14:16
            +11

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


            1. ingrysty
              30.10.2015 14:18
              -3

              Только вот разница описанного мной подхода и с использованием «reversed» скрывается в алгоритмической сложности.


              1. lair
                30.10.2015 14:20
                +1

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

                (вам продемонстировать? не на питоне, правда)


              1. Googolplex
                30.10.2015 14:22
                +14

                reversed(items) возвращает итератор:

                >>> x = [1, 2, 3, 4]
                >>> reversed(x)
                <list_reverseiterator object at 0x10092c668>
                

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


                1. ingrysty
                  30.10.2015 14:23

                  Спасибо за уточнение, аргумент вполне себе.


                  1. namespace
                    30.10.2015 14:34
                    -5

                    Вот я тебя и вычислил, nyarum!


        1. bogolt
          30.10.2015 14:53
          -9

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


          1. deniskreshikhin
            30.10.2015 15:03
            +1

            Почитайте комментарии habrahabr.ru/post/269817/#comment_8634629


          1. lair
            30.10.2015 15:03
            +11

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

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


        1. david_mz
          30.10.2015 15:06
          +1

          Обратный обход можно записать несколько проще: http://play.golang.org/p/Ij9XjQQixz. Да, не reversed, но.


          1. deniskreshikhin
            30.10.2015 15:26

            Да, верно, можно проще.

            Или сделать в «функциональном» стиле:

            play.golang.org/p/t5WyaFsR0W


            1. nwalker
              30.10.2015 16:56
              +2

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


          1. lair
            30.10.2015 16:53

            Интент теряется, к сожалению. Хотя визуально элегантно.


        1. DaylightIsBurning
          30.10.2015 20:50
          -1

          даже в C++ можно сделать

          for (auto i : boost::adaptors::reverse(x)) {
              ;;
          }
          


          1. 0xd34df00d
            30.10.2015 21:00
            +3

            Ну тогда уж auto&, const auto& или auto&&, а то копируете же.


    1. Yanzay
      30.10.2015 13:01
      +1

      Так же как в си


  1. iroln
    30.10.2015 12:41
    +31

    Это было убрано намеренно, потому что выражение s[i:j] может молча дать неверный результат, если j станет меньше нуля.
    Выражение s[i:j] может молча дать неверный результат, если i или j станет не тем положительным числом, о котором думает программист, представляете! И то, что j станет вдруг отрицательным после того как было положительным ещё менее вероятно, и это, скорее всего, будет уже совсем другая проблема.

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

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


    1. Alex_At_Net
      30.10.2015 14:32
      -7

      Идея не в том, что s[i:j] может что-то неправильно вернуть. Идея в том, что автор первой статьи никак не проанализировал существующую аргументацию, а просто ограничился демонстрацией и безапелляционным «плохо». И даже не просто плохо, а «прикиньте, они вот так делают, вот дурачки». Что толстый вброс :) Вторая статья — это уже шаг вперед.


    1. divan0
      30.10.2015 17:23
      -13

      Я не знаю, что для вас будет «веским аргументом». Авторы явно дают понять — на нашем опыте (не забываем, что это 50+ лет, создание UNIX, B, UTF-8 и тд), минусовый индекс приводит к реальным сложноуловимым багам. Что здесь должно служить «веским доказательством»?

      Вы случайно не подрабатываете евангелистом Go в Google на полставки: ?)

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


      1. creker
        30.10.2015 17:33
        +1

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


      1. danslapman
        30.10.2015 17:44
        +8

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

        50+ лет

        создание UNIX

        Ну да, наигрались с адресной арифметикой и решили запилить чего по-безопаснее, а вот посмотреть, что вокруг появилось — не хотели или забыли? Лямбды? Ну это в 80-е тупило, ну и сейчас тупит, да и всю жизнь без этого пишем, ненужно. Почему в Rust смогли сделать и удобно и быстро, а в Go — нет? Новички, говорите, не осилят? А может, их тогда вообще рановато до продакшена допускать? Технология для инженеров не должна ориентироваться на дебилов.
        В общем это… Может быть, авторам на пенсию пора?


        1. danslapman
          30.10.2015 17:52
          +4

          В конце концов не забываем принцип Питера

          В иерархической системе каждый индивидуум имеет тенденцию подняться до уровня своей некомпетентности

          Всю жизнь косячили с отрицательными индексами, а теперь диктуют всем что это опасно, приводит к багам и НИНУЖНО

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


        1. dmbreaker
          01.11.2015 15:20
          -4

          Я видел код на Rust — это новый C++. Т.е. про удобство — это не в кассу.


  1. stepanp
    30.10.2015 12:49
    +10

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


    1. koras_dor
      30.10.2015 13:05
      +3

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


      1. dmbreaker
        01.11.2015 15:21
        -4

        Да что Вы тролля кормите :)


    1. Alexeyco
      30.10.2015 14:25
      -5

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


      1. creker
        30.10.2015 17:34
        +1

        Про С++ когда-нибудь слышали? Ваш Go еще из пеленок не вырос. Все еще на стадии «а что же это за зверь такой»


        1. Alexeyco
          30.10.2015 21:19
          -2

          Слыхал что-то, да. Предположим (на самом деле, я с вами даже согласен). Тогда почему такая дикая (а она дикая) реакция на КАЖДЫЙ пост о Go? Откуда у людей столько ненависти к тем, кто просто выбрал свой собственный путь? Почему когда мы видим различие во взглядах, руки большинства моих соплеменников (так или иначе) тянутся к кнопке «Нагадить в карму»? Не то, чтобы меня это прям сильно расстраивало, я просто реально хочу выяснить это чисто для себя. Вот скажите, я пишу на Go, я никого не убиваю, занимаюсь спортом, не курю, алкоголь вообще не употребляю (мне от него действительно плохо, даже от одной бутылки пива), я стал аполитичным, учусь играть на электрогитаре. Но как только я высказываю свою мысль «Go лучше, чем многое, с чем я имел дело», сразу клац-клац-клац мне в карму. Почему так? Вот есть другая точка зрения, вот есть классическая точка зрения — навроде вашей, и понеслась — война минусяторов. Что с нами всеми вдруг стало?


          1. 0xd34df00d
            30.10.2015 21:33
            +9

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

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


          1. Kroid
            30.10.2015 21:48

            Так в том-то и дело, что вы не просто пишете на go, вы вдобавок пишете статьи о том, как пишете на го. А вот это уже непростительно!
            </irony>


          1. creker
            30.10.2015 22:53
            +4

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


  1. VoidEx
    30.10.2015 13:08
    +10

    А можно пример, где в C++ undefined behavior от сокрытия переменных? Что-то не могу придумать


    1. Ramires
      30.10.2015 13:29
      +2

      Тоже сходу не понял. А суть вот в этом случае.


      1. VoidEx
        30.10.2015 14:48
        +8

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


  1. Alex_At_Net
    30.10.2015 13:14
    +2

    Отлично, спасибо за практичный разбор. По многим пунктам согласен.

    for number := range numbers {}


    number тут будет индекс (если numbers is slice)


  1. sergeylanz
    30.10.2015 13:19
    +4

    я пишу на GO и мне нравится. да есть некоторые вредные моменты в языке, но и что? кто тут знает идеальный язык? Можно взять любой язык программирование и сказать что он ужасный потому что в нем…
    я вам могу написать на каждые язык программирование статью
    «Почему %язык X% плохо продуманный язык программирования». Может хватит тратить килобайты сети на лишним срачку про GO. Язык как язык. Он родился и вырос себя показал и останется. Как и других языков у него будет своя ниша и свой процент кода в мире.


    1. SirEdvin
      30.10.2015 13:29
      +10

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

      студентами-любителями в порыве написать что-нибудь свое


      1. Alex_At_Net
        30.10.2015 14:21
        +1

        не остальные, а «многие другие» — что правда :)


      1. sergeylanz
        30.10.2015 16:31
        +2

        А я не думаю что GO идеальный язык я просто его использую для подходящих задач. А то что GO спроектирован профессионалами тут спора нет


        1. SirEdvin
          30.10.2015 17:19
          -2

          Э б не был бы так уверен… я не видел еще не одного профессионала в проектировании языков.


          1. SirEdvin
            30.10.2015 17:26
            +1

            Вместо Э должно быть Я, вместо не должно быть ни :(


            1. dmbreaker
              01.11.2015 15:24
              -5

              Вы явно не профессионал в проектирования языков :)


      1. divan0
        30.10.2015 21:33
        +4

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

        Автор статьи уже несколько раз писал, что категориями «идеально»/«не идеально» не мыслит. Не нужно обвинять его в том, что придумали сами. :)

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


  1. marten_de
    30.10.2015 13:24
    +1

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

    Есть апи которое работает с неким ресурсом:

    package core
    type KernelAPI interface {
    ...
    LoadDump(fileName string) error
    ...
    }
    

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

    package importer
    import "core"
    
    type Importer interface {
    ImportCSV(kernel *KernelAPI)
    }
    


    но приходит день когда вместо LoadDump нужен hotfix который должен использовать Importer. это противоречило логике проекта и более того нужно было только для игр, но нужен был именно короткий хак для теста того что там Importerы нагенерили ( к core — привязан веб с кучей отчетов и возможностью просмотра данных). Как решение надо было разделять имплементацию и АPI — что повторюсь само по себе не плохо но данный рефакторинг был значительно больше данного временного хака.


    1. ramzes_yan
      30.10.2015 17:06
      +3

      сам попался на такое ограничение
      немного подумал посмотрел на свою реализацию
      разрешил циклические ссылки
      архитектура приложения только выиграла от этого ИМХО

      так что может это не такой уж и большой порок


    1. dmbreaker
      01.11.2015 15:27
      -3

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


  1. psylosss
    30.10.2015 13:29
    +69

    Почему Go — плохо продуманный автомобиль?
    1. Коробка переключения передач — в бардачке.
    2. Тормоз — не всегда тормоз.
    3. Забавно работают поворотники.
    4. Ты не можешь просто взять и залить воду в бачок омывателя.
    5. Неочевидная логика использования ремней безопасности.
    6. Сомнительная строгость сигнализации и противоугонной системы.
    7. Квадратные колёса — это просто костыль.

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

    НИФИГА! Go это хорошо продуманный автомобиль. Потому что:

    0. Оставим в стороне наезд на чувака. Теперь о деле.
    1. Неопытные водители часто включают не ту передачу. Именно так мы похерили новенькую коробку на прошлых выходных, когда друг врубил заднюю на трассе. И тут Его посетила мысль — а давайте чтобы водилы реже ошибались, уберём нафиг этот рычак в бардачок. Пока он туда тянется, он успеет несколько раз подумать и наверняка уж не ошибётся. И хватит уже сравнивать Go с BWM.
    2. Обожаю этот момент. В мануле чётко сказано, что тормоз — это не всегда тормоз. А если ты не прочитал мануал, ты сам тормоз. И это великолепное достоинство Go, в отличие от других поделок.
    3. Они работают так как должны. Да, немного непривычно их включать, да, они не выключаются автоматически, да они мигают разными цветами (а иногда не мигают). Но вы должны привыкнуть. Потому что это правильно. Вот увидите, вас и вашу люстру будут пропускать везде!
    4. У меня тоже сначала не получалось. Но потом я выяснил, что обычная вода не подходит, нужен легкий раствор соды. И чистит лучше! И да, если ты не прочитал об этом в первый же вечер в мануале, ты снова тормоз.
    5. Если ты плохо выспался, или ты просто тормоз, то естественно эта логика покажется тебе неочевидной. Короче, Go — это не Мерседес тоже. А ты — тормоз. Учи мануал.
    6. У тебя ещё ничего не угоняли? А вот у меня угоняли. Поэтому рядом с моим Go всегда дежурит наряд полиции, к машине подпускают строго по паспорту, конвой, все дела. У тебя ещё просто ничего не угоняли.
    7. Есть огромная пропасть между водилами-теоретиками и водилами-практиками. Практики знают, что с квадратными колёсами гораздо проще удержать автомобиль на наклонной плоскости. Все остальные — тормоза.

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


    1. Alex_At_Net
      30.10.2015 13:57
      -5

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


      1. zw0rk
        30.10.2015 21:05
        +4

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


        1. Alex_At_Net
          30.10.2015 22:26

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


    1. namespace
      30.10.2015 14:03
      -1

      Это просто пять, схоронил.


    1. Alexeyco
      30.10.2015 14:32
      -17

      Тогда выходит забавная аналогия. Еду я себе на таком «убогом» автомобиле по улице, а вы вместо того, чтобы ехать на своем «BMW» куда вам надо скачете вокруг меня и пытаетесь выкрикивать мне в окно, какой я идиот. Я пытаюсь от вас отвязаться на поворотах, подрезаю, откровенно посылаю на автозаправке, где обнаруживаю, что вы все еще бежите за мной, а вы ни в какую. Я — идиот, по вашему, и все тут. Проблема в том, что собака лает, а караван идет. Я еду по своим делам, а вы так и будете скакать вокруг меня? ))) может уже вернетесь к своему распрекрасному «BMW» и поедете… куда угодно?

      Кто собака, а кто караван, я надеюсь, объяснять не надо? ))) или объяснить?


      1. Randl
        30.10.2015 15:46
        +11

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


        1. Alexeyco
          30.10.2015 16:38
          -6

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

          Из-за того, что форма решетки вам не нравится, вы выискиваете кривости во всем автомобиле. Ну а чего нет — придумываете. А потом скачете, скачете, скачете за караваном… лаете на него, а он все идет, идет и идет, не обращая на это никакого внимания.


          1. Randl
            30.10.2015 20:51
            +3

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


            1. divan0
              30.10.2015 21:36
              -4

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


    1. Alexeyco
      30.10.2015 14:45
      -5

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


    1. dmbreaker
      01.11.2015 15:34
      -2

      Ну знаете.
      Мне больше кажется, что у большинства иначе:
      1) Нельзя залить бензин из салона? Фу, отстой, в моем автомобиле можно! Поэтому он лучше!
      2) Колеса всегда должны быть одинакового диаметра? Неуниверсально!
      3) Дворниками нельзя чистить капот? В топку!
      4) Фары не могут светить в салон? Как вы этим убожеством пользуетесь?
      5) А вот мое авто еще летать может, правда меня уже 2 раза за это чуть не посадили. Но без этого — отстой!
      6)…


  1. lair
    30.10.2015 14:27
    +29

    Обсуждения вокруг Go, по крайней мере, в исполнении некоторых людей, всегда удивляли меня количеством аргументов ad hominem. Давайте просто пройдемся по этому посту:

    авторы Go, исходя из своего, более чем, полувекового опыта разработки, видят [...] Решение, [...] уменьшающее риск хитрых ошибок в long term. Понятно, что не все мыслят на long term, отсюда и конфьюз.


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


    пропасть, между программистами-практиками и программистами-теоретиками [здесь к ним причислен программист из Mozilla, ага].


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


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


    1. Alex_At_Net
      30.10.2015 14:38
      +1

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


      1. lair
        30.10.2015 14:40
        +16

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


        1. Alex_At_Net
          30.10.2015 20:46
          +1

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


          1. lair
            30.10.2015 21:09
            +2

            Go и его сообщества.


    1. aml
      30.10.2015 23:50

      Много объяснений с конкретными примерами от авторов языка — github.com/golang/go/wiki/GoTalks


    1. s-kozlov
      01.11.2015 23:08

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


  1. Dywar
    30.10.2015 14:42
    +6

    «Есть всего два типа языков программирования: те, на которые люди всё время ругаются, и те, которые никто не использует.»
    Bjarne Stroustrup.


    Цитаты о языках программирования


  1. evnuh
    30.10.2015 15:29
    +8

    Складывается впечатление, что Go создан был не чтобы на нём программировать, а чтобы его обсуждали :)

    Кому и что пытаются доказать авторы как прошлой, так и этой статьи — непонятно. У каждого своё мнение, каждый выбирает сам. Обсуждать запятые в языке — сильно щепетильно для языка ПРОГРАММИРОВАНИЯ. А иначе это бессмысленный холивар, что мы собственно и там и тут и видим. Судя по всему, хабру нравится почесать языком и поспорить.

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


    1. divan0
      30.10.2015 17:46
      -8

      Эта статья — исключительно контр-ответ на не совсем адекватный выпад, который, к сожалению, люди уже тиражируют и репостят, не читая. Вот вам реальный случай:

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


      1. nwalker
        30.10.2015 17:59
        +1

        Ну, я могу предложить автору этого ответа использовать аргументацию «Go не сырой, он production ready, а статьи о его убогости как языка, это абсолютно ортогональная тема! Он должен быть таким by design, Великий Пайк так сказал».


      1. evnuh
        30.10.2015 18:03
        +13

        Собственно то, чт овы процитировали — это не спор и даже не ответ и не аппеляция. Так спорят только мудаки, по двум причинам:
        1) никаких фактов в целых 8 строчках текста
        2) унижение оппонента по признаку возраста/пола/etc.

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


        1. divan0
          30.10.2015 18:08
          -8

          Евнух, так можно про каждый комментарий писать. Это же не дискуссия уже. Вот ваш комментарий — тоже пустой спор и болтовня. и вы субъективны.

          Какие факты? Человек, рассказавший, как ему неадекватные вбросы приводит к реальным проблемам на работе — должен анонимусам в интернете «факты» писать? Справки с работы и видеозаписи общения с боссом? О чем вы? :)
          И «школьник» — это не унижение, автор статьи нам знаком и он, действительно, учится в школе.


          1. danslapman
            30.10.2015 18:10
            +9

            потратил 6 мес на своей работе внедряя Go

            Пока результат не очень

            Сдаётся мне, там далеко не только из-за статьи школьника проблемы


            1. divan0
              30.10.2015 18:15
              -3

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


              1. nwalker
                30.10.2015 18:30
                +1

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


                1. divan0
                  30.10.2015 19:07
                  -2

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


      1. 0xd34df00d
        30.10.2015 21:46
        +4

        Прикольно у вас там.
        Хаскель в продакшен не влезает — ахаха, трихомонадки, только факториалы на нём писать!
        Go в продакшен не влезает — долбанные школьники, форсят кривость Go, если б не они, у нас бы уже яблони на Марсе под управлением Go цвели!


    1. Alexeyco
      30.10.2015 21:38
      +4

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


  1. alexrett
    30.10.2015 16:20
    +1

    Go это не Python, это разные языки. Некоторым людям сложно даётся факт, что никакие языки, кроме Питона, не являются Питоном

    Go — это другой язык, это не C++.

    Ничто не воробей, кроме воробья.

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


    1. nwalker
      30.10.2015 17:22
      +3

      Да что в нем такого «другого»?
      Добавьте в Pascal GC и concurrency на корутинах с каналами, замените nominal typing то ли на structural, то ли вообще на duck typing — вот вам и Go. В самом языке нет вообще ни одной новой или даже просто малораспространенной идеи.

      Почему я должен считать этот язык чем-то необычным и мерить его какими-то другими рамками?


      1. alexrett
        30.10.2015 17:42

        Ну а почему в нем должно быть что-то прям вот обязательно новое или малораспространенное?
        Да, не будем спорить, в Go есть минусы, но благодаря сообществу — они почти все известны. В php вон вагон и маленькая тележка таких косяков, но тем не менее :) А возможно даже что-то исправится в перспективе. Вы конечно можете взять Pascal и поиграть в X-Zibit'a, но зачем? Go прекрасно решает свои задачи и на нем уже не один десяток проектов успешно работает. Например мы внедрили у себя InfluxDB и несмотря на то, что проект еще не в релизе, он вполне себя хорошо показывает.


        1. nwalker
          30.10.2015 17:53
          +6

          Не, вы не поняли.
          В Xzibit-а с паскалем уже поиграли создатели Go, а теперь его фанаты пытаются скормить нам точку зрения, что то, что нам неудобно — это такой особый go way, а не то, что язык by design сделан убогим и устаревшим.

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


          1. alexrett
            30.10.2015 18:01

            Ах вот оно что :)
            Все же, что-то мне подсказывает, что тошнота от языка исключительно субъективное ощущение. Так вот могу сказать, что такие позывы вызывает ruby, но это же не делает его чем-то прям категорично плохим? Лично для меня, возможно в силу опыта, Go пока вызывает ощущение — «нет, я пока не готов», но опыт коллег по цеху говорит, что в целом вполне можно и не плохо получится на выходе.


            1. nwalker
              30.10.2015 18:25
              +4

              Я-то давно готов, у меня ~5kloc Go в продакшне, я регулярно интересуюсь исходниками рантайма Go и вполне этот рантайм одобряю и вообще, считаю что подобный язык реально нужен — с GC, статическими бинарниками, правильно сделанным параллелизмом и concurrency. Идеи реально хорошие.

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


    1. ramzes_yan
      30.10.2015 17:38

      насчет ветерана спасибо льстит )

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

      в адаптации для веб программирования на Го после пхп стоит понять несколько отличий
      1

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

      в Го для этого есть указатель на структуру *http.Request из которой можно получить большую часть информации о запросе
      а так же интерфейс http.ResponseWriter куда нужно положить загаловки и ответ на запрос

      тут все более или менее можно сравнить с пхп

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

      а так лично для меня Го оказался не сложнее пхп в освоении


      1. alexrett
        30.10.2015 18:04

        :) Со всем согласен, мы поняли это в момент перевода части проектов с пхп на питон. В общем-то питоном пока довольны как яп, но вот скоростью не очень, поэтому и смотрим в сторону Го, хотя с внедрением celery проект ожил и Го пока отложен в ящик.


        1. rinat_crone
          31.10.2015 05:06

          А вы уверены, что у вас боттлнек именно в ЯП? Можно и на Go легко нагородить такого неповоротливого монстра (особенно, когда нет опыта разработки на нем), что по скорости выигрыш будет практически незаметен.


          1. alexrett
            02.11.2015 12:07

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


      1. vintage
        31.10.2015 15:31
        +4

        ПХП можно почти на что угодно менять и быть довольным :-D


  1. lair
    30.10.2015 17:21
    +6

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


    Первый удачный дизайн:

    var c = new Something();
    {
      var c = new Something();
    }
    

    Результат:
    CS0136	A local or parameter named 'c' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
    


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

    Второй удачный дизайн:
    let Secret () = (42, 1)
    
    let a = 0
    a |> printfn "before %A"
    begin
        let (a, _) = Secret()
        a |> printfn "inside %A"
    end
    a |> printfn "after %A" 
    

    Результат:
    before 0
    inside 42
    after 0
    


    Но:
    let Secret () = (42, 1)
    
    let a = 0
    a |> printfn "before %A"
    let (a, _) = Secret()
    a |> printfn "inside %A"
    a |> printfn "after %A" 
    

    Результат:
    error FS0037: Duplicate definition of value 'a'
    


    (Проще говоря, shadowing есть, а вот побочек нет)

    Напомню поведение Go
    	number := 0
    	fmt.Println("before", number)
    	{
    		number, _ := Secret()
    		fmt.Println("inside", number)
    	}
    	fmt.Println("after", number)
    

    Результат:
    before 0
    inside 42
    after 0
    


    Теперь:
    	number := 0
    	fmt.Println("before", number)
    	number, _ := Secret()
    	fmt.Println("inside", number)
    	fmt.Println("after", number)
    

    Результат:
    no new variables on left side of :=


    Но:
    	number := 0
    	fmt.Println("before", number)
    	number, err := Secret()
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println("inside", number)
    	fmt.Println("after", number)
    

    Результат:
    before 0
    inside 42
    after 42


    1. neolink
      30.10.2015 17:48

      вы опускаете специфику языка, такой reassing сделан прежде всего чтобы не делать err1 err2 и т.п., также стандартной проверкой является всё же
      if number, err := Secret(); err != nil {
      panic(err)
      }
      ну и больше фантазии нужно для имен переменных, это для любого языка справедливо


      1. lair
        30.10.2015 17:55
        +3

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

        А если серьезно, то если «специфика языка» ведет к неожиданному поведение — может, все-таки, что-то с дизайном не так?


  1. KIVagant
    30.10.2015 17:52
    +7

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


    1. divan0
      30.10.2015 18:11
      -5

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

      go generate используется для стандартизации рабочего процесса, позволяя любые кодогенераторы (для Protocol Buffers, Thrift или SWIG) вызывать одной командой — go generate, а не заставлять каждого писать мейкфайлы.


      1. KIVagant
        30.10.2015 18:41
        +1

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


        1. divan0
          30.10.2015 19:02
          -3

          Отказ от мейкфайлов — это желание упростить процесс сборки, убрать необходимость в ещё одном «языке», ещё одном слое потенциальных проблем, ошибок и сложности.
          Все проекты в Go собираются командой «go build» или «go build ./..» (для рекурсивной сборки проектов в поддиректории). go generate появился в Go 1.4, как ответ на все чаще возникающие проекты, в которых нужно было запускать время от времени какие-то кодогенераторы — специально ради них городить подобие мейкфайлов было бы никудышним решением.

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

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


      1. deniskreshikhin
        30.10.2015 19:11
        +8

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

        package main
        
        // typedef int (*intFunc) ();
        //
        // int
        // bridge_int_func(intFunc f)
        // {
        //		return f();
        // }
        //
        // int fortytwo()
        // {
        //	    return 42;
        // }
        import "C"
        import "fmt"
        
        func main() {
        	f := C.intFunc(C.fortytwo)
        	fmt.Println(int(C.bridge_int_func(f)))
        	// Output: 42
        }
        


        1. divan0
          30.10.2015 19:19
          -4

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


          1. deniskreshikhin
            30.10.2015 19:25
            +3

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

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


            1. divan0
              30.10.2015 19:30
              -9

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

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


  1. dom1n1k
    30.10.2015 18:07
    +8

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


  1. beduin01
    30.10.2015 20:14
    +1

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


  1. tyomitch
    31.10.2015 01:06
    +2

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

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

    Вместо Java можно подставить С++, Python или любой другой язык, и этот абзац останется верным.


    1. Randl
      31.10.2015 01:48
      +6

      Вместо Go тоже можно подставить любой язык и выражение останется в той или иной степени верным (в зависимости от близости итоговой пары языков).


      1. tyomitch
        31.10.2015 18:26

        Да, но другие языки реже подвергаются критике типа «А чего тут всё не как я привык?»


        1. Randl
          31.10.2015 19:18
          +1

          Питон — а почему отступы значимые?
          С++ — а почему такая долгая компиляция? Почему такие сложные шаблоны?
          Rust — почему неудобный синтаксис? Почему медленнее С++?
          Php — ну на эту тему сотни статей есть
          и т. д.


    1. divan0
      31.10.2015 02:35

      Всё так, но, смею полагать, это больше не о бекграунде, а о личностных характеристиках. У нас недавно был выпуск подкаста о Go с джавистами, очень здорово пообщались. И вот, джавист со стажем рассказывает о Go, очень неплохо получилось имхо :)


      1. david_mz
        31.10.2015 19:27

        Рассказывает весело, но сколько же там неточностей и фактических ошибок… Боюсь, слушатели скорее запутались:)


    1. divan0
      31.10.2015 02:41

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