Пользователь
12,0
рейтинг
30 октября 2015 в 05:18

Разработка → Почему Go — это хорошо продуманный язык программирования

Go*
В недавнем посте с критикой 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 и написать все быстро и качественно» принимает менеджер сверху, который может понимать области применимости языков, а может и не понимать. И достаточно такого вброса, чтобы человек, даже не читая и не вникая, решил для себя, что «Го не стоит использовать, раз такие статьи про него пишут». И это реальные ситуации.

Ну а, к кому прислушиваться и с кого брать пример — каждый решает сам, конечно же.
divan0 @divan0
карма
132,0
рейтинг 12,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

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

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

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

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

    а благодаря строгости компилятора и четкости инструкций на официальном сайте
    все пишут код более/менее в одном стиле, а это согласитесь многого стоит
  • +9
    Осмелюсь поблагодарить за статью! Действительно вчерашний пост (про «ужасный» язык) оставил в голове какое-то впечатление сумбура. Сейчас оно отступило :)
    • +1
      У меня оно еще не скоро пройдет ))
      Что касается golang, мне, как плавно переходящего с PHP, новый ЯП все больше начинает нравиться. Есть конечно же определенные нюансы, но это все равно большущий шаг вперед.

      P.S.: по части WEB, разумеется!
  • +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
        }
    
    • 0
      Если можно без кода, я могу привести примеры:
      1. вставка строки в середину перечня товаров счёта;
      2. вставка строки в середину перечня ролей пользователя;
      3. вставка строки в середину перечня подзадач расписания;
      • 0
        Для таких штук существуют другие структуры данных: односвязный список, двухсвязный список, двунаправленная очередь.
        Но как с ними обстоят дела в go, в котором нет обобщений. Ведь с ними работа тоже получается неудобной.
        • +10
          Для таких штук существуют другие структуры данных: односвязный список, двухсвязный список, двунаправленная очередь.

          У этих «других штук» другие стоимости, что иногда может быть неудобно (Да, мне как-то была нужна упорядоченная структура с O(1)-доступом к произвольному элементу, и меня устраивало O(n) при ее расширении. Нет, кейс не помню, что-то из стандартных алгоритмов.)
          • –5
            Так думать надо, а иногда и бенчмарки делать, если не очень очевидно, какая операция наиболее часто делается.
            • +17
              Ну вот подумали. Провели алгоритмический анализ. Подтвердили его бенчмарком. Вышло, что массив и вставки в середину — эффективнее всего для данного случая.

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

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

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

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

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

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

                      И, к сожалению, это реальная жизнь.
                      • 0
                        Такова жизнь, но примеров из жизни никто так и не привел. Хотя мне еще тогда было интересно увидеть необходимость такой функции в серверном микросервисе на 100-200 строк, для создания которых и позиционирует себя golang.
                        • +3
                          Не, если go позиционирует себя только для таких микросервисов, то ладно.
                        • –2
                          Ну там примеры из жизни были — «я хочу написать вот именно такую функцию именно таким способом».

                          Ну а Golang себя не позиционирует, как язык для микросервисов — это, скорее, полезный побочный эффект, что маленькие сервисы писать удобно и легко и Go зачастую начинаются использовать в компаниях, с написания или переписывания отдельных сервисов. Как раз Go «позиционируется» для масштабов Google — большие кодовые базы, большие группы людей и т.д.
                          • +1
                            Вот и мы код с PHP на Go переписываем. Этот подход себя оправдывает. Сервисы показывают бОльшую производительность. Встроенная поддержка тестов позволяет делать код надежным и модифицируемым.
                            И все это в продакшене с миллионами пользователей.
                            Кто-то еще считает Go игрушкой, а кто-то уже сейчас получает от этого преимущество.
                        • 0
                          Из реальной жизни, безотносительно к операциям вставки и прочему, опыт показывает, что писать наиболее обобщённые сигнатуры функций полезно, потому что, во-первых, не привязываешься к деталям и, во-вторых, сразу видно, какие типы совпадают потому, что они должны совпадать (например, типы индексов начала и конца чего-либо в контейнере), а какие — случайно. Помогает избегать ошибок в реальной жизни, ага.
                          • 0
                            Здесь T это как-раз тип, перепутать не получится, не скомпилится
                            Реальный код так будет выглядеть:

                            a = append(a[:pos], append([]string{x}, a[pos:]...)...)
                            
                            • 0
                              И мы снова возвращаемся к вопросу о том, как написать такую обобщённую функцию.
                              • +1
                                И мы снова возвращаемся к вопросу — Зачем?
                                • –2
                                  Чтобы не привязываться к конкретным типам данных, внезапно.
  • –15
    Go прекрасен!
    Использую его уже более года, если что то и непонятно, то нужно лишь немного терпения (и умения читать, конечно) что бы разобраться!
  • –16
    В любом случае, не стоит недооценивать труд столь большой компании.
  • +57
    Вот я прочитал обе статьи и… немного не понял.
    Вы так описали, что у меня сложилось довольно отрицательное впечатление о самом языке, причем именно от вашей статьи.
    Половина аргументов выглядит «так делать нельзя, потому что так делать плохо.»
    А вот если нужно, то пиши свой костыль и страдай.

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

    Например, почему нужно писать так:
    numbers = append(numbers[:2], append([]int{3}, numbers[2:]...)...)
    

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                  Новый формат общения на Хабре, мда.
                  • +2
                    Да что ж такое…
                    Ну как мне поддерживать сортированный массив на Go, а?
                    • +1
                      сделайте тип, опишите правила сортировки, логику резервирования памяти, возможно вы будете не целый массив выделять, а например блоками для оптимизации операций вставки.
                      как мне поддерживать сортированной массив на C?
                      • 0
                        А правила сортировки — они относятся к типу или к месту вызова?
                        А блоки — это уже не массив, а deque.
                        А почему на C, а не на C++?
                        • 0
                          Мало того, что вы мне вопросом на вопрос ответили. Так ещё и вопросы какие-то странные.
                          Ок, на C не получилось, давайте на C++
                          • 0
                            v.insert(upper_bound(v.begin(), v.end(), x), x);
                            

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

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

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

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

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

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

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

                                  В плюсах нет встроенного параллелизма, сборщика мусора, а широкие возможности ООП по наследованию, виртуальным функциям и т.п. зачастую очень не плохо бьют по производительности.
                                  И что мне теперь ржать в голос и говорить, что плюсы отстой?
                                  Или вместо того чтобы сделать рабочий сервис за час, я буду сутки писать и дебажить его на плюсах лишь по тому что я не могу забабахать десяток шаблонных классов?
                                  • +2
                                    Вообще это все ЯП, c++/c, go, python, haskell, php и т.п. и они все друг другу альтернативы.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                                      go func () {
                                      // do
                                      }()

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

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

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

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

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

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

                                        Пруфы?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            А мне кажется, что это как раз двигатель развития — аргументированный спор ( не путать с тупым флеймом! ). Программисты в душе — идеалисты. Хочется найти священный Грааль лаконичности, понятности и производительности. Вот и происходят споры, выявляющие плюсы и минусы каждого инструмента. Главное — не скатываться на личности и эмоции.
            • +5
              Вы считаете, что ищете святой Грааль. А я вижу, как большинство останавливает свой выбор на чем-то, что нравится именно им, и начинает верить, что это — святой Грааль для всех. В этом-то и проблема.
      • +19
        > Написано, что Go помогает писать код с которым будет меньше проблем в будущем.
        Это из области метеорологических прогнозов. Поживем — увидим. Предыдущим стремительно завоевывавшим рынок языком, с которым не будет проблем в будущем был КОБОЛ.

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

        • 0
          > Да и как удобный синтаксис может мне вдруг навредить завтра — тоже не очень ясно.
          В общих чертах-то ясно. Плохой код должен выглядеть плохо. То есть идея в том, что глядя на вставку в середину массива, человек должен заподозрить неладное и убедиться, что оно к месту. Скажу за хаскель. Если бы писать там с мутабельными переменными было так же удобно, как без них, хаскель был бы другим. Вопрос только в том, что именно счесть плохим кодом, и вот тут да, мнения разнятся. Время покажет.
          • +6
            В хаскеле это математически обосновано и следует из базовых свойств языка и абстракций (запихивать всё в unescapable-монаду ST, например). А тут — набор ad-hoc-костылей и решений с потолка, уж простите.
            • –3
              А тут — набор ad-hoc-костылей и решений с потолка, уж простите.

              Это не так. Хотите себя убеждать, что Go — это набор костылей с плохим дизайном, пожалуйста. Самообман — дело легкое.
              • +4
                Мне каждется, доказать то, что это обман достаточно просто, для этого все лишь нужно указать ссылки на статьи. Если язык не базируется на статьях, то можно попытаться агрументировать тем, что это хороший инженерный язык, и привести в доказательства рассылки и статьи в блог постах авторов, объясняющие решения, обосновывая это технически. К сожалению это будет доказательстов того, что язык построен на ad-hoc решениях (ну или костылях, смотря какая агрументация).
          • –3
            То есть идея в том, что глядя на вставку в середину массива, человек должен заподозрить неладное и убедиться, что оно к месту.

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

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

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

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

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

      s = append(s, 0)
      copy(s[i+1:], s[i:])
      s[i] = x
      
      • 0
        То есть, если мне нужно собрать в один массив несколько массивов и чисел мне тоже нужно будет так делать?

        А как же синтаксический сахар?
        • 0
          Много сладкого вредно для здоровья :)

          Если вам нужно собрать в один массив несколько массивов и чисел — вы сами решайте как вам это нужно сделать, в каком порядке и т.д. К вашим услугам append, make, и copy — вполне лаконичные и простые операции. Понять потом код очень просто.
          • +1
            Просто я не знаю Go, но разбираюсь по статье.
            Я могу написать что-то похожее на:
            append(arr1,1,arr2,3,arr4,5)
            

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

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

              Как то append<T'>(slice []T', e []T'|T'...) — сложновато…
              • 0
                Почему «к сожалению»? Сейчас append — детерминированная функция, которая делает одну ясную и четкую операцию.
                Если вам нужно добавить несколько других значений и слайсов — сделайте это явно. Избавляйтесь от этого желания «написать все в два символа», чтобы потом другие программисты гадали, что же имелось ввиду и зачем.
                • +1
                  То, что сложно для компилятора, не всегда сложно для человека. Смысл выражения append(arr1,1,arr2,3,arr4,5) вполне очевиден, особенно если функцию назвать join, а не append
    • 0
      А лучше так:

      numbers = numbers[0..2] ~ 0 ~ numbers[2..$];
      • +1
        Тут уже спорный вопрос.
        Я не уверен, что пойму, что делать операция ~, если увижу ее в незнакомом языке.
        Тут же вроде за простоту сражаются.
        • –1
          Это конкатенация. Слово «append» тоже не говорит, что это соединение массивов, а не, например, добавление записей в файл :-)
    • +1
      Строгий язык не может быть удобным.

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

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

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

        Это сложный дисскусионный вопрос. Что лучше, потратить больше времени на написание самого кода или на его review и комментирование?
        • +2
          А вы про какую строгость говорите?
          • 0
            Вроде как о наличии различных синтаксических соли и сахара.
        • 0
          То, что в языке нет generics — я тоже не считаю плюсом. Но это ничего не говорит про дизайн языка. Есть множество языков, где их нет, во многих они появились не сразу. Вполне возможно, что и в Go 2.0 (например) они таки будут.

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

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

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

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

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

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

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

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

              Вот так никогда в реальности не бывает.
              Если вы действительно заранее сели и на пару лет вперед хорошо продумали Архитектуру, то это значит только, что вы проели огромное денег бизнеса, впустую.
              Архитектура — это то, что выстраивается в результате развития проекта. И она меняется и должна меняться. И вот эти изменения должны быть максимально простыми. Чего Go с успехом и добивается. А то, что в середину слайса вставить значение «не красиво выглядит» — в реальности на это всем плевать.
  • +25
    Так-так, что тут у нас сегодня? Ничего нового, в Go одни правильные решения, все пытаются делать из него питон и совать свои закоренелые паттерны. Ну, что я могу сказать? Хорошо.
  • +23
    По большей части я согласен скорее с вами, чем с автором оригинальной статьи. Кроме одного пункта — пункта 7.
    Комментарии по определению это такие пометки, присутствие или отсутствие которых в коде не меняет поведения кода. Так во всех языках. Ну, разве что в Python встречаются любители хранить метаданные в docstring'ах, но их даже коллеги за это колотят. А тут вы говорите, что вызывать из комментариев кодогенератор — это норма. Кодогенератор, Карл! Да даже в C++ максросы сделаны лучше. А что, если этот комментарий сольётся с комментарием к функции ниже? В общем, можно сколько угодно защищать такое решение, ссылаясь на авторитет Пайка, но это реально выглядит на решение из разряда «да ну, для одного кейса не будем прагмы добавлять, сделаем магический комент и так сойдёт»
    • –3
      это машиночитаемый комментарий он автоматом ничего не вызывает, для него существует отдельная команда, которую надо запускать руками.
      по смыслу — стандартизовали то, что уже использовали люди, только они это писали в make файлах или так же в комментариях: https://github.com/golang/net/blob/master/html/atom/gen.go.
      Это чтобы например на основе описания protobuf сгенерировать исходный код на go и т.п.
      • +21
        Стандартизировать костыли — божественный подход к дизайну
        • –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
          • 0
            А тут изобретены аннотации, но почему-то не выделены явно синтаксически.
          • +10
            Магические комментарии — это костыль. Претензии к тому, КАК сделали.
            • –2
              магические комментарии — это суть есть аннотации, как один из вариантов размещения неких метаданных в коде, чем "@NotNull" принципиально отличается от //go:nosplit или //go:generate?
              • +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...
                }
                
                • 0
                  вас смущает, что go doc зацепит этот комментарий к функции Blabla?
                  • 0
                    Меня, кстати, смущает.

                    (скажем, в C# просто комментарии и документационные комментарии отличаются)
                    • 0
                      не писал на c#, не могу сходу представить что вы имеете ввиду
                      • +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
                        Там есть вот такой комментарий
                        //Это комментарий
                        

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


                        из комментариев второго типа генерируется документация, из комментариев первого — нет
                        • 0
                          аналог на go:
                          // это просто коммент

                          // а это информация о работе функции, она пойдет в godoc
                          func DoCool() {
                          }
                          • 0
                            В вашем же примере github.com/golang/go/blob/master/src/runtime/wbfat.go#L6
                            //go:nosplit пойдёт в godoc
                            Это норма, да?
                            • +1
                              он не пойдет в godoc — это приватная функция
                              • 0
                                Если я не ошибаюсь дока должна еще начинаться с названия метода?

                                // это просто коммент
                                
                                // DoCool а это информация о работе функции, она пойдет в godoc
                                func DoCool() {
                                }
                                
                            • +2
                              Это не норма. nosplit и noescape — это внутренности компилятора и рантайма, в реальном коде вы ничего подобного не пользуете. //go:generate, если уж понадобилось, вы пишете единожды в заголовке файла, а не где попало. Обсуждаемая выше проблема — чистой воды теоретизирование.
                              • +2
                                Обсуждаемая выше проблема — чистой воды теоретизирование

                                Как будто это делает решение поместить в комментарии инструкции для кодогенератора или «внутренности компилятора и рантайма» long-term хорошим решением.
                                • 0
                                  А что, по вашему, будет хорошим решением?
                                  • +3
                                    Выделить это в отдельные сущности, как это было сделано во всех других языках?
                                    Например, в аннотации.
                                    • –4
                                      Я, к примеру, не вижу плюсов от «введения новой сущности», зато ломается совместимость. Плодить новую сущность на каждый чих — это именно то, чем Go не является. Если хочется такого, то лучше выбирать другие языки. Если всё таки есть реальные проблемы с go generate или с комментариями — велкам в коммьюнити, выслушают, напишете пропозал, и ваше решение, раз оно реально лучше — имплементируют. Всё просто.
                                      • +2
                                        Я не знаю, как вы умудряетесь новой сущностью ломать совместимость, наверное вы избранный. Обычно она ломается, когда происходит наоборот.

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

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

                                        А это плохо.
                                        • –3
                                          Я не знаю, как вы умудряетесь новой сущностью ломать совместимость, наверное вы избранный.

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

                                          А это плохо.

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

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

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

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

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

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

                                            Лишить язык программирования возможности писать комментарии — это плохое решение.
                                            • –3
                                              То есть Go 1.5 совсем не добавляет ничего нового в сравнении с Go 1.4? Я вас правильно понял?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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


                                                            Приведите пример задачи, в которой type erasure выгоднее по сравнению с нормальными generics (как в C#).
                                                            • +1
                                                              Единственная причина, по которой их сделали именно так — недальновидность создателей первой версии Java.
                                                              Если пытаетесь намекать на дальновидность разработчиков .NET, который появился в 2000, то стоит посмотреть на то, что java появилась в 1995.

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

                                                              У Java иной подход — сохранение совместимости. И во всех задачах, когда была необходимость использовать старый код в новом окружении (без какой-либо модификации и перекомпиляции) type erasure выигрывает по сравнению с переписыванием кода или запуском его различных кусков под разными версиями CLR.
                                                              • +3
                                                                Однако параметрический полиморфизм, то, что в java почему-то назвается Generics, (без подтипирования) появился аж в 1975 году, так что это не оправдание. Кстати, это же объясняет почему, в Go его нету, туда настолько молодые фичи не попадают.
                                                              • 0
                                                                Опять отмазки пошли.

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

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

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

                                                                Приведите пример задачи, в которой type erasure выгоднее по сравнению с нормальными generics (как в C#).
                  • +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
                      Если бы вы писали на Go, вы бы понимали, почему нет оснований полагать, что кто-нибудь так напишет. А если и напишет, то ничего страшного не произойдет. С таким же успехом можно говорить «Tesla — плохой автомобиль, потому что кто-то можно положить пальто на тачскрин и не сможет его видеть». Попробуйте на практике и судите о дизайне по делу, а не по придуманным кейсам.
                      • +1
                        Конкретно насчёт этого я сейчас немного разобрался и понимаю, что неправ.
              • +10
                Тем что это части синтаксиса языка.

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

                Я люблю Go, но вот это конкретное место — это очень плохой дизайн. Имхо.
          • 0
            Автогенерация кода тоже костыль. См. хаскелевские template haskell (который на самом деле тоже кривоват и костыль) и generics.
            • +1
              TH это, кстати канонический пример костыля, т.к. радостно ломает абстракции (скрывает типы за ExpQ), в отличии от Generics, и даже появляющийся Typed-TH не очень поможет в силу ограничений. (Правда в отличии от generics позволяет генерировать более эффективный код, с расширениями generics такое тоже возможно, но уже не так просто). Естественно плюс TH, в отличии от, насколько я понимаю, go, в том, что генерация производится средствами языка, что не мешает вызывать внешние утилиты если необходимо. А совсем хороший вариант в MetaOcaml, например.
              • 0
                Именно. Даже костыльный TH лучше условного {-# hask-henerate ...#-}.
                Хотя стоп, какие {-#, у нас же нет прагм, пусть будет обычный --.

                А MetaOcaml я не тыкал :(
        • +2
          Магические комментарии — это костыль. Претензии к тому, КАК сделали.
          Лучший критический комментарий за два поста, imho.
          • 0
            «Костыль» — это ярлык, не более. Shebang — это тоже такой-же «костыль», что не мешаем ему исправно выполнять свою функцию на всех UNIX-системах, не так ли?
            Так что важнее — практическая польза или чей-то ярлык «костыля»? Какие реальные практические проблемы с go generate были хотя бы у одного из комментаторов тут? Да ни у кого.

            Конкретно по поводу go generate — был пропозал и были дискуссии о том, как лучше решить проблему. В дискуссии мог поучаствовать каждый хабровчанин и предложить «не костыль», обосновав, почему его «не костыль» будет хорошим дизайном.
            • +1
              Костыль, но имеющий четко определенное место. Он идёт первой строкой в самом начале файла. Его сложно не заметить и тем боле спутать с чем-то другим.
              Аналогично другой костыль — указание кодировки файла для python 2. Тоже расположен в первой или второй строке и только там.
      • +7
        По сути дела они придумали препроцессор, но сделали вид, что они не при делах.
        • +1
          с make сравнили бы ещё ладно, но это не препроцессор
          • +4
            По факту ведь берется этот файл с магическими комментариями и на основе него генерируется другой, новый файл. Это ли не препроцессор в чистом виде?
            При помощи make тоже можно препроцессор к любому языку программирования приделать.
            • 0
              По факту запускается любая команда, это как тоже самое, что сказать make или bash это препроцессор.
              Эти запуски не как не связаны с процессом компиляции, в зависимостях которые вы ставите они не вызываются, только запуски руками.
              Почитайте https://blog.golang.org/generate, возможно просто я плохо объясняю.
              • +2
                Ну просто получается, что необходимость в кодогенерации нужна, то есть по факту нужны обобщения, но их нет в языке и нет никакого стандарта на них.
                Вот тебе и плата за простоту.
                • 0
                  Не всё что решается генерацией можно решить обобщенным программированием. Примеры с генерацией парсеров и тп.
                  • 0
                    Думается мне, что такие вещи нужно решать через генераторы парсеров, которые вообще на другом языке написаны, специально для этого созданном, а не встраивать их в комментарии.
                    • 0
                      ну если вы начнете читать, что вам люди пишут может даже диалог получится.
                      //go:generate go tool yacc -o gopher.go -p parser gopher.y
                      как думаете что такое yacc?
                      • +2
                        yet another compiler compiler — генератор парсеров?
                        • 0
                          Отсюда:
                          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
                      Этим другим языком вполне может быть eDSL. И это как-то лучше и удобнее, чем дёргать действительно другие языки.
                  • +3
                    Ну вот Boost.Spirit обходится без препроцессоров.
                    • +3
                      Даже parsec обходится без препроцессоров!
  • +22
    Видимо автор этой статьи знает и умеет в Go, но вот эти обиды, нападки на другие языки и «неверных» можно было бы и опустить.
    • –2
      Нападки на языки — это упоминание С++ в эпилоге?
      • +1
        По-видимому, Вы пропустили мой комментарий ( хотя это неудивительно, их тут уже 120+ ).
        • –3
          Просто все, кто писал на C++, переключившись на другие языки — изливают накопившуюся боль оттого, что столько лет провели на темной стороне силы :)
          • +2
            Я писал на C++, теперь на C++ и Haskell, но отчего-то боли не ощущаю :)
  • –17
    Go никому не нужен.
    Программист C++ легко освоит его, это да.
    Но в обратном я сомневаюсь.
    • +5
      Уместней было бы сказать «легче». Зачем вешать неуместные ярлыки на людей.
      А по части нужности судить не вам думаю.
      • –11
        После того как меня «отхабрили» в предыдущем обсуждении Go, мне стало все равно.
        • +13
          Назвав собеседников хомячками вы чего-то другого ожидали?
        • +8
          То есть, Go — плохой из-за того, что вас «отхабрили»? ))
    • +5
      Это пост любви к Go, тут нельзя так грубо.
  • +1
    а чёрт надо кофе с утра больше пить
    • 0
      Эм, не стоит, тем более в выходной.
      • +3
        Хорошо вам, пятница — выходной.
        • 0
          Может человек в Эмиратах живёт)
          • +4
            Тогда ему вдвойне хорошо)
  • +7
    > Некоторым людям сложно даётся факт, что никакие языки, кроме Питона, не являются Питоном
    Золотые слова… я сам очень уважаю Питон, но Go — не Питон, а Питон — не Go…
  • +31
    Статья же автора о том, что дизайн языка «плохой» — это, к сожалению, не более, чем попытка привлечь к себе внимание

    Не берите на себя слишком много. Написали статью для самоуспокоения — замечательно. Но прошлая статья прекрасно описывала те проблемы, с которым, например, столкнулся я и долго плевался. И что-то подсказывает, что я далеко не один. Статья написана в том числе для привлечения внимания, но ее суть и основные тезисы описывают фактические проблемы языка, которые некоторые отказываются видеть и выдумывают тысячу отмазок вроде «так сделали, значит так надо и правильно», «это не нужно, приведите примеры, когда это нужно» и прочие попытки успокоить себя, не более того.
    • –6
      Я имел опыт общения с автором в последние несколько месяцев, и хорошо понимаю его мотивы. Поэтому предложения про «подростковый возраст» и про «попытку привлечь к себе внимание» — это не догадки.
      • +6
        Тем не менее, его статья поднимает актуальные проблемы. Мне не важно, какой у него внутренний мир
        • +1
          Вы это уже написали в 10 комментариях. Отсутствие отрицательных индексов — это не «актуальные проблемы», это «привычка». На этом и разойдемся.
      • +1
        Таки я угадал не имея опыта общения с автором. Как прочитал, себя вспомнил лет 15 назад :-D
    • –1
      Ну почему никто не пишет таких статей про C++? Там же на 100500 статей косяков наберется! Косяки Go — это мелкие шалости в сравнении с этим монстром!
      • +4
        Ну почему же никто? Из самого масштабного — www.yosefk.com/c++fqa. Просто в мире C++ в ответ на такие статьи выходят новые версии языка, а не ответные статьи в стиле «в языке этого нет, поэтому вам это не нужно».
        • –2
          Не смешите — проблема поддержки юникода возникла не вчера. В какой версии C++ стал из коробки поддерживать его?
          • +2
            Не знаю, в какой это появилось, но вроде бы wchar_t и wstring там есть очень давно.
            • 0
              Есть. Только поддержки unicode от этого не прибавляется.
              • +2
                Что тогда есть поддержка Unicode, если не возможность хранения и манипулирования unicode строками на уровне стандартной библиотеки? Да, там это не очень удобно делать, в основном из-за многочисленных устаревших API, которые умеют только char. Но все же есть.
                • +1
                  Да ничего та нет. Ни конертации в локаль/UTF8 и обратно, ни поддержки работы с суррогатными парами. Есть «массив-байтов» (string) и «массив-непонятно-чего»(wstring)
                  • 0
                    Ни конертации в локаль/UTF8 и обратно

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

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

                      Про второе, ну вот, например, смотрите, очевидно, что й и й — одна и та же буква, но на на самом деле это й и и&#774;. С++ это не поймет
                      • +1
                        А есть какой-то язык, который поймёт это из коробки?
                        • +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
                          
                      • 0
                        Понятно что библиотеки есть для всего. Речь именно про стандартную библиотеку языка, в которой это можно было бы удобно объединить со стандартным же IO.

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

                        Это ж не python2 у которого при выводе utf8 у танка отваливается башня, если вывод перенаправили/отправили в pipe.
                        • 0
                          Проблема в том, что IO как раз хорошо бы знать Потому что

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

                          А при работе нужно чтобы поиск/замена понимали, что символ UTF8 может состоять из нескольких байт и даже слов UTF16
                          • 0
                            Работать с UTF-16 совсем неудобно. Он имеет все проблемы UTF-8 (символы имеют переменную длину).
                            Работать надо с настоящими code points. А любые кодировки — они для ввода-вывода только.
                            И поодержка этого кстати в C++ таки есть.
                            • 0
                              Ну хорошо, я согласен, будем считать, что я имел в виду «настоящие code points» :)

                              В С++ есть некоторый набор функций для этого, но это больше похоже на отмазку, чем на поддержку, потому что работать с этим неудобно. А некоторые вещи просто невозможно сделать платформонезависиммым способом.
                          • 0
                            А зачем при поиске и замене в UTF8 нужно знать, что символ может состоять из нескольких байт? Поиск и замена подстрок к этому нечувствительны.
                            • 0
                              Это хорошо пока вам не надо, например, делать case insensitive поиск/замену, где в бой вступает collation. Или замену символов с диакритикой из пользовательского ввода, где они могут быть как в decomposed так и в composed вариантах.
                              • 0
                                Да даже при обычном поиске встают вопросы. «ёлка» и «елка» — разные слова? Думаю, в других языках есть примеры похлеще.
                            • 0
                              чтобы вот это работало, например

                              #include <iostream>
                              #include <string>
                              
                              int main() {
                                  std::string s {"пр?вет, мир"};
                                  s[s.find('?')] = 'и';
                                  std::cout << s << '\n';
                              }
                              
                              • 0
                                Достаточно искать и вставлять подстроки, а не символы, тогда будет работать
                                • 0
                                  Суперинтуитивно!

                                  А по факту тип char и string::operator[] не работают
                                  • 0
                                    А они где-то работают? Например лигатура ае может быть как одной, так и двумя буквами в зависимости от языка. И как взять в слове vae третью букву?
                                    • 0
                                      А они где-то работают?

                                      Угу.

                                      > 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
                                        Во втором примере вы показали, что оно — не работает, а про сравнение я и не спрашивал.
                                        • 0
                                          Знаете, мне кажется, что это упирается в требование к «работает». С моей точки зрения, семантика (различная!) обоих типов (и строк, и символов) передана верно.

                                          PS Я, заметим, не говорю, что в других языках сделано неправильно или хуже, я про это мало что знаю.
                                          • 0
                                            Я ссылался на этот комментарий.
                                            • +2
                                              Ну, как раз проблема «символ может состоять из нескольких байт» в моем примере успешно решена: адресация внутри [] идет посимвольно. а не побайтно.
                                              • 0
                                                Как раз нет. Обе эти строки — одно и то же слово, и в нём одна и та же третья буква — «e». А вот если взять другой язык, где есть буква "æ", то это будут разные слова, а посему операция взятия n-ой буквы должна ещё и культуру принимать.
                                                æ — это две буквы (или одна, смотря какой язык), но code point в данном случае — один, хотя опять же, ту же «й» можно выразить двумя code point'ами. Операция индексации ж должна корректно взять третью букву в слове «май», даже если «й» там из двух «символов».
                                                • +2
                                                  Обе эти строки — одно и то же слово, и в нём одна и та же третья буква — «e».

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

                                                  Вот с «й» сложнее — там действительно всегда одна буква, вне зависимости от количества char'ов, но я не знаю, как так правильно реализовать, чтобы при этом можно было и с бреветами отдельно работать.
                                                  • 0
                                                    Ну, собственно, я то и не спорю. Я как раз спорю с тем, что интуитивный способ работы хорош, ибо тут как раз абстракции протекают.
                          • 0
                            С чем работать удобнее — зависит от приложения. Иногда удобнее с 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.
                            • 0
                              Про legacy-систему, где консоль «типа» 866, а на самом деле — смесь 866 и 1251 (параметры в argv передаются в cp1251) лучше постараться забыть, как страшный сон =)
                              Суть в том, что страшным сном оно становится как раз из-за того, что в C++ нет нормальной поддержки строк, которая бы брала всю работу по конвертации на себя.

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

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

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

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

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

                                  С выводом, конечно, будут проблемы. Как минимум имело бы смысл выводить в UTF-8, если вывод редиректится куда-то, и, возможно, вопросики, если вывести на консоль символ не получается.
                                • 0
                                  Если речь про cmd, то всегда можно использовать chcp 65001, если сменить в свойствах консоли шрифт. UTF8 батч файлы начинают говорить на разных языках.
                                  • 0
                                    Штука полезная, запомню. Интересно, что она внутри использует. Можно то же самое делать внутри своих программ. А то всех пользоваться данной командой не заставишь.
                                    • 0
                                      SetConsoleOutputCP
                  • 0
                    В C++11 добавили char16_t, char32_t и u16string, u32string как альтернативу «непонятно чему» wchar_t и wstring, а также <codecvt> в целом и codecvt_utf8 в частности для конвертации, включая суррогатные пары.
                    • 0
                      суррогатные пары
                      Суррогаты есть только в utf16, т. к. не всякий codepoint может быть представлен одним uint16. В utf8 этой проблемы нет.
                      Возможно, вы имели ввиду не суррогатные пары, а формы нормализации (всякие NCD/NFC/NFKD/NFKC).
                      • 0
                        Я имел в виду конвертацию UTF8 -> UTF16 и наоборот, где с суррогатными парами приходится разбираться.
                      • 0
                        Возможно, вы имели ввиду не суррогатные пары, а формы нормализации
                        Скорее, я имел это в виду. Спасибо.
                    • –2
                      Ок, простой тест

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

                      уже работает на всех системах одинаково, печатая «првиет, мир»?
                      • +1
                        Ну да, копирует на stdout строку в той же кодировке, в которой она введена в исходнике. (Если вы намекаете на виндовую консоль с её legacy cp866 — перенаправьте вывод в файл.) Для этого поддержка unicode не нужна вообще.
                        • –2
                          Отлчино. Проблема в том, что это самый просто пример того, где наглядно демонстрируется то, что C++ работает не со строками, а с массивами байт. Взяли массив байт и отправили на stdout, как вы и говорите.
                          • +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
                              1) Я не хочу ничего говорить, я хочу, чтоб строка текста выводилась как текст. Всякие кодировки оставьте в прошлом веке.
                              2) Я не хочу конвертировать в utf8, я хочу чтобы строка выводилась строкой и на Linux, и в Windows, и на светодиодном табло.
                              • +3
                                А я наоборот хочу работать с байтами.

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

                                Ну вот я прошу кодировку «чтоб было читаемо независимо от того, куда идет вывод и на какой системе». Как?
                                Utf-8?
                                • +1
                                  Ещё хуже, т. к. представление одного и того же текста (как упорядоченного набора глифов) не единственно даже в рамках одной кодировки.
                                • –1
                                  Строка — суть просто набор байтов.
                                  Нет. Строка — суть кусок текста. То, что вы там напридумывали — это все от бедности. Строка не может быть «просто набором байтов» хотя бы потому, что строкам и тексту уже тысячи лет, а эти ваши байты вот только придумали.
                                  • +2
                                    Ну числа это тоже числа, однако в памяти это наборы байтов в определенном порядке. И знать little или big endian это надо, если хочется, чтобы вывелось правильно везде. Тут тоже самое. Текста в понятиях ПК не существует. Есть текст — суть, байты, которые в определенной кодировке дают текст на экране. А в другой уже не дают. Без кодировка нет текста, будь это UTF или даже просто ASCII. И я не видел ниодного рантайма, который бы не упоминал этих понятий. Просто напросто невозможно в полной мере манипулировать байтами, когда кодировка их содержимого неизвестна.
                                    • +1
                                      Нет, числа — это числа. И знать про little или big endian нужно только в качестве разминки для ума, но для проведения вычислений эти знания не требуются — спросите любого бухгалтера.

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

                                      Понимаете ли, есть разные слои абстракций. little или big endian нужны, если вы разработчик сериализатора. Если вы только используете сериализтиор, то вам это совершенно не нужно. Знать про особенности представления строк нужно, если вы разрабатываете поддержку Unicode. Но если вы заставляете меня, как пользователя вашей библиотеки по работе с Unicode с этим разбираться — то вы плохой разработчик библиотеки для поддержки Unicode.
                                      • 0
                                        Да чего о строках говорить, когда у нас и чисел-то нет нормальных :)
                                        • +1
                                          Да с числами вообще беда! Попробуйте-ка посчитать 42! на С++, напрмиер
                                  • +2
                                    > строкам и тексту уже тысячи лет
                                    Строкам-то да, а вот компьютерам нет. А компьютеры неявно тут очень даже подразумеваются:

                                    > чтоб было читаемо независимо от того, куда идет вывод и на какой системе
                                    Вы ж не про пергамент и не про надписи на стенах, а про компьютеры.
                                    • –1
                                      То, что с компьютером все гораздо сложнее, чем с пергаментом, говорит не в пользу компьютера, не так ли?
                                      • 0
                                        Так уж и всё?
                                    • 0
                                      Символы же в компьютер вводят не в виде набора бит. Нажимают кнопку с определенным символом, или касаются области экрана с изабраженным на нем символом, или вводят пером и распознается символ. Набор символов — текст. И вводят именного его. И обычно хотят чтобы при всех преобразованиях он оставался текстом и выводился обратно(на экран, принтер и тд) именно в виде того же набора символов(ну или чуть измененного нужным образом). Поэтому подробности хранения текста для пользователя сугубо вторичны. Он на более высоком уровне оперирует и опускается до кодировок только от безысходности или при разработки интерфейсов обмена данными в двоичном виде. Поэтому в идеале есть строка текста(в какой-то фиксированной, известной рантайму языка или компилятору кодировке) и пользователь просит вывести эту строку в консоль. Вывестись в идеале должна именно эта строка, причем без дополнительных телодвижения со стороны пользователя. Рантайм может узнать в какой кодировке консоль ожидает данные и сам перемять в нужное представление. Уровень взаимодействия в данном случае — «выести строку текста с помощью устройства», а не «отправить массив байт в устройство». Уровень массива байт тоже нужен, он должен быть доступен на случай необходимости полного контроля, но это нижний уровень. И всё время на нем оперировать это скорее привычка от плохой жизни.
                                      • +3
                                        Lol4t0,
                                        Нет. Строка — суть кусок текста. То, что вы там напридумывали — это все от бедности. Строка не может быть «просто набором байтов» хотя бы потому, что строкам и тексту уже тысячи лет, а эти ваши байты вот только придумали.
                                        Понимаете какая штука… Компьютеры оперируют только битами, в оперативной памяти нет никаких букв, текстов и строк, там и чисел-то так таковых нет. Даже чтобы получить обыкновенный int и то нужно знать сугубо вторичную для пользователя вещь: хранится ли это число в little-endian или big-endian. Считайте это «кодировкой» чисел. Если вы не знаете «кодировку», вы не сможете интерпретировать биты в виде числа.

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

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

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

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

                                        С остальным, про идеальные строки и взаимодействие с пользователем, я согласен. Но C++ так не работает, он плюётся байтами.
                                        • +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.
                                        • –3
                                          Понимаете ли какая штука… Природа оперирует только атомами, в природе нет никаких битов, байтов и кодировок, там и оперативной памяти как таковой нет.
                                      • 0
                                        Я-то согласен, но те же рассуждения применимы и к обычным числам, где приходится почему-то знать, сколько там байт внутри. Но много ли где умолчальный Int — безразмерен? А float/double?
                                        Ну да, умолчание в C++ — это дефолтная локаль, которая не факт что utf8 (особенно в случае с windows).
      • +3
        Потому что плюсовики не замусоривают хабр статьями с восхвалениями своего инструмента.
        • –2
          Первой появилась статья негативная. А эта не восхваление, а восстановление статус кво.
          • +3
            Зато до этого большинство статей только о том, какой это прекрасный язык. Как это обычно бывает со всеми новыми IT игрушками. Тот же docker какой прекрасный распрекрасный нам рисовали все время. NoSQL как нам рисовали, помнится. Правильно люди на конференциях Go говорят — перед знакомством с языком надо опустить свои ожидания, которые из-за хайпа вокруг него завышены очень сильно. Тогда язык не будет казаться непонятной хренью непонятно для чего.
          • +3
            Далеко не первой.
  • +29
    Забавно, что отсутствие отрицательных индексов избавит вас от страшных багов, а несовсем-нулевые-интерйесы — мощнейшая технология, которую надо просто выучить.
  • +15
    Поэтому нужно переходить на Раст и никаких вам недостатков.
    Радуюсь ежедневно.
    • +3
      Мы рады, что вы радуетесь, а можно аргументировать? Почему это «поэтому»? Недостатки есть везде, нет ничего идеального.
      • +6
        Я использую силу плюсов других хабравчан за доказательство!
    • +3
      На хаскель, пожалуйста.
  • –18
    Из за Go меня отхабрили. Ненавижу Go.
    Теперь хочу посвятить жизнь написанию гневных публикаций против Go.
    • +9
      Обида живет в груди глупых
      • –17
        Вы правы. Не стоит обижаться на хомячков.
  • –14
    Go не нужен.
    Почему?
    Asm все равно быстрее…
    • +3
      Ну хватит уже…
  • 0
    Кстати, не подскажите, а как в Go обойти слайс в обратном порядке?
    • +2
      http://play.golang.org/p/9xjT-oHxfI
      • –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])
        }
        
        • +2
          Проблема в том, что скрывается за функцией «reversed» и какие операции оно выполняет :)
          И в итоге все становится на свои места.
          • +11
            Я боюсь, что проблема в том, что в питоне можно написать одну функцию reversed и пользоваться ей, а вот в Go — только если авторы языка подарили.
            • –3
              Только вот разница описанного мной подхода и с использованием «reversed» скрывается в алгоритмической сложности.
              • +1
                А вы готовы утверждать, что невозможно написать такую реализацию reversed, которая будет иметь алгоритмическую сложность, сопоставимую с простым обходом массива?

                (вам продемонстировать? не на питоне, правда)
              • +14
                reversed(items) возвращает итератор:
                >>> x = [1, 2, 3, 4]
                >>> reversed(x)
                <list_reverseiterator object at 0x10092c668>
                

                который, судя по названию, делает то же самое, что цикл с убывающим индексом, только удобнее. Поэтому в алгоритмической сложности разницы нет вообще.
                • 0
                  Спасибо за уточнение, аргумент вполне себе.
                  • –5
                    Вот я тебя и вычислил, nyarum!
        • –9
          Го ориентирован на скорость работы. В го вы тоже можете написать функцию которая вернет список обратный заданному… но это копирование памяти которого можно избежать. Поэтому приходится больше кода как плату за скорость работы.
          • +1
            Почитайте комментарии habrahabr.ru/post/269817/#comment_8634629
          • +11
            В го вы тоже можете написать функцию которая вернет список обратный заданному… но это копирование памяти которого можно избежать.

            (1) эта функция, как неоднократно обсуждалось, не может быть универсальной
            (2) некоторые языки, внезапно, позволяют это сделать без копирования
        • +1
          Обратный обход можно записать несколько проще: http://play.golang.org/p/Ij9XjQQixz. Да, не reversed, но.
          • 0
            Да, верно, можно проще.

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

            play.golang.org/p/t5WyaFsR0W
            • +2
              В котором практически отсутствует смысл в отсутствии дженериков, которые, как известно, нинужны. Х)
          • 0
            Интент теряется, к сожалению. Хотя визуально элегантно.
        • –1
          даже в C++ можно сделать
          for (auto i : boost::adaptors::reverse(x)) {
              ;;
          }
          
          • +3
            Ну тогда уж auto&, const auto& или auto&&, а то копируете же.
    • +1
      Так же как в си
  • +31
    Это было убрано намеренно, потому что выражение s[i:j] может молча дать неверный результат, если j станет меньше нуля.
    Выражение s[i:j] может молча дать неверный результат, если i или j станет не тем положительным числом, о котором думает программист, представляете! И то, что j станет вдруг отрицательным после того как было положительным ещё менее вероятно, и это, скорее всего, будет уже совсем другая проблема.

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

    Если что, то я ни в том и ни в другом лагере, просто высказал свои впечатления от статьи.
    • –7
      Идея не в том, что s[i:j] может что-то неправильно вернуть. Идея в том, что автор первой статьи никак не проанализировал существующую аргументацию, а просто ограничился демонстрацией и безапелляционным «плохо». И даже не просто плохо, а «прикиньте, они вот так делают, вот дурачки». Что толстый вброс :) Вторая статья — это уже шаг вперед.
    • –13
      Я не знаю, что для вас будет «веским аргументом». Авторы явно дают понять — на нашем опыте (не забываем, что это 50+ лет, создание UNIX, B, UTF-8 и тд), минусовый индекс приводит к реальным сложноуловимым багам. Что здесь должно служить «веским доказательством»?

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

      К сожалению, нет :) Но подход Go слишком refreshing после языков, стремящихся за фишками и возможности сделать всё что угодно любыми способами, и приводящих к тоннам багов и ужасного неподдерживаемого кода в дикой природе.
      • +1
        А Go нет никакой возможности нам еще доказать, что он чем-то лучше этих языков «приводящих к тоннам багов и ужасного неподдерживаемого кода в дикой природе». Go новомодная штучка, все его достоинства пока что существуют в большинстве на словах и в мечтах авторов некоторых статей. Когда дорастет, то приходите, обсудим, во что превратился некогда такой прекрасный язык.
      • +8
        Данный комментарий — гипетрофированный пример альтернативной точки зрения, но к минусам я готов.
        50+ лет

        создание UNIX

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

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

          И это всё я пишу лишь к тому, что авторитет, каким бы он не был, это для разумного человека ещё не довод принимать мнение этого авторитета без аргументов.
        • –4
          Я видел код на Rust — это новый C++. Т.е. про удобство — это не в кассу.
  • +10
    Самое большое зло Go, это не косяки в языке, а его комьюнити. Такого количества слепо наяривающих на своего любимчика фанбоев, нету даже у JS.
    • +3
      Угу и благодаря этому комьюнити на Go сейчас создаются или переписывается довольно таки большое количество проектов. Не надо переходить на личности, это как минимум не культурно.
      з.ы.Недавно узнал что в SpaceX используют Go.
      • –4
        Да что Вы тролля кормите :)
    • –5
      Вы правы, ни у одного сообщества больше нет такого количества хейтеров ))) честное слово, я скоро перестану есть, а буду питаться только церебральными вихрями таких, как вы )))
      • +1
        Про С++ когда-нибудь слышали? Ваш Go еще из пеленок не вырос. Все еще на стадии «а что же это за зверь такой»
        • –2
          Слыхал что-то, да. Предположим (на самом деле, я с вами даже согласен). Тогда почему такая дикая (а она дикая) реакция на КАЖДЫЙ пост о Go? Откуда у людей столько ненависти к тем, кто просто выбрал свой собственный путь? Почему когда мы видим различие во взглядах, руки большинства моих соплеменников (так или иначе) тянутся к кнопке «Нагадить в карму»? Не то, чтобы меня это прям сильно расстраивало, я просто реально хочу выяснить это чисто для себя. Вот скажите, я пишу на Go, я никого не убиваю, занимаюсь спортом, не курю, алкоголь вообще не употребляю (мне от него действительно плохо, даже от одной бутылки пива), я стал аполитичным, учусь играть на электрогитаре. Но как только я высказываю свою мысль «Go лучше, чем многое, с чем я имел дело», сразу клац-клац-клац мне в карму. Почему так? Вот есть другая точка зрения, вот есть классическая точка зрения — навроде вашей, и понеслась — война минусяторов. Что с нами всеми вдруг стало?
          • +9
            Потому что они не только выбрали свой путь, но и везде его несут, как святыню, будто Go — это озарение и единственно правильный путь, не то, что питоны++.

            А я тоже не курю, не пью, не убиваю, но не понимаю, какое это отношение имеет ко мне как к программисту. Если вдруг буду устраиваться на работу программистом Go (хотя очень вряд ли, конечно), укажу это всё в резюме, видимо, там это важно.
          • 0
            Так в том-то и дело, что вы не просто пишете на go, вы вдобавок пишете статьи о том, как пишете на го. А вот это уже непростительно!
            </irony>
          • +4
            Мне кажется это, как тут уже говорили, имидж языка, который вот такими статьями и создается. Язык вроде и не плох, и есть чем ему похвастать против остальных, но вот такое вот комьюнити создает враждебную атмосферу, когда уже на любых защитников языка кидаются с уверенностью, что это наверняка очередной фанатик, который дальше своего Go видеть разучился, аргументов внятных предоставить не может кроме «Пайк сделал, значит правильно». И ведь много таких в комментариях даже здесь. Напротив, хейтерства именно я вижу мало. Я вижу людей, которые обсуждают то, что им не нравится. А против них обычно фанатик, который внятно свою позицию обозначить не может. Просто слепая вера какая-то в святость путей, избранных Go.
  • +10
    А можно пример, где в C++ undefined behavior от сокрытия переменных? Что-то не могу придумать
    • +2
      Тоже сходу не понял. А суть вот в этом случае.
      • +8
        Ну, я не согласен, что тут дело в сокрытии переменных. Если убрать внешний int x, ничего не поменяется.
  • +2
    Отлично, спасибо за практичный разбор. По многим пунктам согласен.

    for number := range numbers {}


    number тут будет индекс (если numbers is slice)
  • +4
    я пишу на GO и мне нравится. да есть некоторые вредные моменты в языке, но и что? кто тут знает идеальный язык? Можно взять любой язык программирование и сказать что он ужасный потому что в нем…
    я вам могу написать на каждые язык программирование статью
    «Почему %язык X% плохо продуманный язык программирования». Может хватит тратить килобайты сети на лишним срачку про GO. Язык как язык. Он родился и вырос себя показал и останется. Как и других языков у него будет своя ниша и свой процент кода в мире.
    • +10
      А вы знаете много языков, которые продвигают как идеально спроектированные?
      А вот автор статьи явно считает, что Go идеально спроектирован профессионалами, а остальные
      студентами-любителями в порыве написать что-нибудь свое
      • +1
        не остальные, а «многие другие» — что правда :)
      • +2
        А я не думаю что GO идеальный язык я просто его использую для подходящих задач. А то что GO спроектирован профессионалами тут спора нет
        • –2
          Э б не был бы так уверен… я не видел еще не одного профессионала в проектировании языков.
          • +1
            Вместо Э должно быть Я, вместо не должно быть ни :(
            • –5
              Вы явно не профессионал в проектирования языков :)
      • +4
        А вот автор статьи явно считает, что Go идеально спроектирован профессионалами

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

        А если вы изучите истории появления различных языков, то поймете, что за всеми ними действительно стоят разной зрелости люди и команды, и разные мотивы.
  • +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 — что повторюсь само по себе не плохо но данный рефакторинг был значительно больше данного временного хака.
    • +3
      сам попался на такое ограничение
      немного подумал посмотрел на свою реализацию
      разрешил циклические ссылки
      архитектура приложения только выиграла от этого ИМХО

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

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

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

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

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

    — Стёб на стёбе, конечно. Но если убрать шелуху, то всё выглядит именно так. И с языком, и с его комьюнити, и с этими двумя статьями.
    • –5
      Аналогия интересная, но явный перекос в мануальный негатив :) Не забывайте, что перед эксплуатацией автомобиля на дороге нужно сдать на права.
      • +4
        Права в данном случае это теоретические аспекты программирования и практический опыт на каком-либо языке (паскаль в основном, наверное). Вы же не сдаёте на права при покупке нового автомобиля всякий раз? :)
        • 0
          Ну если ездил на коробке автомат, то поучить как себя ведет машина с ручной коробкой будет не лишним.
    • –1
      Это просто пять, схоронил.
    • –17
      Тогда выходит забавная аналогия. Еду я себе на таком «убогом» автомобиле по улице, а вы вместо того, чтобы ехать на своем «BMW» куда вам надо скачете вокруг меня и пытаетесь выкрикивать мне в окно, какой я идиот. Я пытаюсь от вас отвязаться на поворотах, подрезаю, откровенно посылаю на автозаправке, где обнаруживаю, что вы все еще бежите за мной, а вы ни в какую. Я — идиот, по вашему, и все тут. Проблема в том, что собака лает, а караван идет. Я еду по своим делам, а вы так и будете скакать вокруг меня? ))) может уже вернетесь к своему распрекрасному «BMW» и поедете… куда угодно?

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