Pull to refresh

Comments 362

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

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

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

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

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

        copy((*arr)[org][i+1:], (*arr)[org][i:])
        (*arr)[org][i] = value
    }
Если можно без кода, я могу привести примеры:
1. вставка строки в середину перечня товаров счёта;
2. вставка строки в середину перечня ролей пользователя;
3. вставка строки в середину перечня подзадач расписания;
Для таких штук существуют другие структуры данных: односвязный список, двухсвязный список, двунаправленная очередь.
Но как с ними обстоят дела в go, в котором нет обобщений. Ведь с ними работа тоже получается неудобной.
Для таких штук существуют другие структуры данных: односвязный список, двухсвязный список, двунаправленная очередь.

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

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

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

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

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

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

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

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

Ну а Golang себя не позиционирует, как язык для микросервисов — это, скорее, полезный побочный эффект, что маленькие сервисы писать удобно и легко и Go зачастую начинаются использовать в компаниях, с написания или переписывания отдельных сервисов. Как раз Go «позиционируется» для масштабов Google — большие кодовые базы, большие группы людей и т.д.
Вот и мы код с PHP на Go переписываем. Этот подход себя оправдывает. Сервисы показывают бОльшую производительность. Встроенная поддержка тестов позволяет делать код надежным и модифицируемым.
И все это в продакшене с миллионами пользователей.
Кто-то еще считает Go игрушкой, а кто-то уже сейчас получает от этого преимущество.
UFO just landed and posted this here
Здесь T это как-раз тип, перепутать не получится, не скомпилится
Реальный код так будет выглядеть:

a = append(a[:pos], append([]string{x}, a[pos:]...)...)
UFO just landed and posted this here
И мы снова возвращаемся к вопросу — Зачем?
UFO just landed and posted this here
Go прекрасен!
Использую его уже более года, если что то и непонятно, то нужно лишь немного терпения (и умения читать, конечно) что бы разобраться!
В любом случае, не стоит недооценивать труд столь большой компании.
Вот я прочитал обе статьи и… немного не понял.
Вы так описали, что у меня сложилось довольно отрицательное впечатление о самом языке, причем именно от вашей статьи.
Половина аргументов выглядит «так делать нельзя, потому что так делать плохо.»
А вот если нужно, то пиши свой костыль и страдай.

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

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

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

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

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

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

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

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

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

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

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

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

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

Я бы Вашу характеристику отнес бы к обеим статьям
не слишком основательно прорабатывает аргументацию, смещая акцент в эмоции. «Инженерный» троллинг :)
UFO just landed and posted this here
я всё ещё под впечатлением от рекомендации автором статьи использования связного списка для реализации сортированных массивов.

Добавление элемента в сортированный список.
Вы самостоятельно изменили слово «список» на «массив», и находитесь в шоке. Почему бы и другие слова не поменять, как вам хочется?
Ни о чём.
UFO just landed and posted this here
Я попросил три реальных примера (показать код, к примеру или рассказать суть задачи).
Человек привел надуманный пример и сказал одно (сортированный список).
Вы перекрутили его слова, обвинив меня в том, что я предлагаю список для реализации сортированного массива.
Потом сказали, что «там как раз понятно».

Новый формат общения на Хабре, мда.
UFO just landed and posted this here
сделайте тип, опишите правила сортировки, логику резервирования памяти, возможно вы будете не целый массив выделять, а например блоками для оптимизации операций вставки.
как мне поддерживать сортированной массив на C?
UFO just landed and posted this here
Мало того, что вы мне вопросом на вопрос ответили. Так ещё и вопросы какие-то странные.
Ок, на C не получилось, давайте на C++
v.insert(upper_bound(v.begin(), v.end(), x), x);

— выполняет двоичный поиск и вставляет элемент.
UFO just landed and posted this here
конкретно я про это:
> А почему на C, а не на C++?
я то конечно и попросил C т.к. там нет дженериков. В целом не сказать что приходилось прям сильно страдать от этого в Go (как-то либо стандартный sort, либо штуки на interface{}, либо совсем кастом) но реально они должны быть здесь (хотя бы для стандартных контейнеров).
кстати ваши примеры на 11 плюсах, которые через 20 лет вышли после первой версии
UFO just landed and posted this here
C как бы это что-то старенькое.
Вообще это все ЯП, c++/c, go, python, haskell, php и т.п. и они все друг другу альтернативы.
> И что это нам говорит?
Нам это говорит что все развивается, где-то быстрее, где-то медленнее
> Кстати, конкретно этот пример на 14-х плюсах
в 11 добавили авто но не дописали что его можно использовать в лямбдах?

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

В плюсах нет встроенного параллелизма, сборщика мусора, а широкие возможности ООП по наследованию, виртуальным функциям и т.п. зачастую очень не плохо бьют по производительности.
И что мне теперь ржать в голос и говорить, что плюсы отстой?
Или вместо того чтобы сделать рабочий сервис за час, я буду сутки писать и дебажить его на плюсах лишь по тому что я не могу забабахать десяток шаблонных классов?
UFO just landed and posted this here
> PHP — это альтернатива хаскелю и C++, ок.
Я вам написал подробнейшим образом, а вы не прониклись, да альтернатива, зависит от задачи.
Если вам нужно сделать сайт из пары страниц, не надо упираться и делать его на плюсах.

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

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

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

go func () {
// do
}()

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

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

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

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

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

А в Go есть статическая проверка потокобозопасности используемых из разных горутин структур? В D, например, есть.

Вы не ответили на вопрос.
UFO just landed and posted this here
Нет, мой пример на C++98, самом первом стандарте.
Вы точно прочитали статью? Где в ней про удобство?

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

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

Возможно, я ошибаюсь, но мне кажется, что на неудобном языке быстро не напишешь.
Поэтому удобство подразумевается в данном контексте.
Раз пишется быстро то есть подозрение что все же достаточно удобен. Конечно же это не значит абсолютное удобство для всех и для любых задач.
На Basic тоже что-то пишется…
UFO just landed and posted this here
Вы почему-то написали это в ответ на мой комментарий, так что отвечу.
1.
Распять мерзавца, как он посмел высказать свое мнение! Четвертовать его!

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

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

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

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

> Да и как удобный синтаксис может мне вдруг навредить завтра — тоже не очень ясно.
В общих чертах-то ясно. Плохой код должен выглядеть плохо. То есть идея в том, что глядя на вставку в середину массива, человек должен заподозрить неладное и убедиться, что оно к месту. Скажу за хаскель. Если бы писать там с мутабельными переменными было так же удобно, как без них, хаскель был бы другим. Вопрос только в том, что именно счесть плохим кодом, и вот тут да, мнения разнятся. Время покажет.
UFO just landed and posted this here
А тут — набор ad-hoc-костылей и решений с потолка, уж простите.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Вот так никогда в реальности не бывает.
Если вы действительно заранее сели и на пару лет вперед хорошо продумали Архитектуру, то это значит только, что вы проели огромное денег бизнеса, впустую.
Архитектура — это то, что выстраивается в результате развития проекта. И она меняется и должна меняться. И вот эти изменения должны быть максимально простыми. Чего Go с успехом и добивается. А то, что в середину слайса вставить значение «не красиво выглядит» — в реальности на это всем плевать.
Так-так, что тут у нас сегодня? Ничего нового, в Go одни правильные решения, все пытаются делать из него питон и совать свои закоренелые паттерны. Ну, что я могу сказать? Хорошо.
По большей части я согласен скорее с вами, чем с автором оригинальной статьи. Кроме одного пункта — пункта 7.
Комментарии по определению это такие пометки, присутствие или отсутствие которых в коде не меняет поведения кода. Так во всех языках. Ну, разве что в Python встречаются любители хранить метаданные в docstring'ах, но их даже коллеги за это колотят. А тут вы говорите, что вызывать из комментариев кодогенератор — это норма. Кодогенератор, Карл! Да даже в C++ максросы сделаны лучше. А что, если этот комментарий сольётся с комментарием к функции ниже? В общем, можно сколько угодно защищать такое решение, ссылаясь на авторитет Пайка, но это реально выглядит на решение из разряда «да ну, для одного кейса не будем прагмы добавлять, сделаем магический комент и так сойдёт»
это машиночитаемый комментарий он автоматом ничего не вызывает, для него существует отдельная команда, которую надо запускать руками.
по смыслу — стандартизовали то, что уже использовали люди, только они это писали в make файлах или так же в комментариях: https://github.com/golang/net/blob/master/html/atom/gen.go.
Это чтобы например на основе описания protobuf сгенерировать исходный код на go и т.п.
Стандартизировать костыли — божественный подход к дизайну
эм, то есть автоматическая генерация кода в любой форме, это костыль?
вы уж определитесь к чему претензии к тому, что стандартизовали или как это сделали.

ну и в тему про магические комментарии:
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
А тут изобретены аннотации, но почему-то не выделены явно синтаксически.
магические комментарии — это суть есть аннотации, как один из вариантов размещения неких метаданных в коде, чем "@NotNull" принципиально отличается от //go:nosplit или //go:generate?
Тем, что он
— не выглядит как комментарий
— обрабатывается не как комментарий

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

//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...
}
вас смущает, что go doc зацепит этот комментарий к функции Blabla?
Меня, кстати, смущает.

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

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


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

// а это информация о работе функции, она пойдет в godoc
func DoCool() {
}
он не пойдет в godoc — это приватная функция
Если я не ошибаюсь дока должна еще начинаться с названия метода?

// это просто коммент

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

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

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

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

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

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

А это плохо.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

То, что они могут быть субъективно плохи в ваших задачах не означает, что они плохи для всех. Так что никакой объективностью тут и не пахнет.
UFO just landed and posted this here
Единственная причина, по которой их сделали именно так — недальновидность создателей первой версии Java.
Если пытаетесь намекать на дальновидность разработчиков .NET, который появился в 2000, то стоит посмотреть на то, что java появилась в 1995.

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

У Java иной подход — сохранение совместимости. И во всех задачах, когда была необходимость использовать старый код в новом окружении (без какой-либо модификации и перекомпиляции) type erasure выигрывает по сравнению с переписыванием кода или запуском его различных кусков под разными версиями CLR.
Однако параметрический полиморфизм, то, что в java почему-то назвается Generics, (без подтипирования) появился аж в 1975 году, так что это не оправдание. Кстати, это же объясняет почему, в Go его нету, туда настолько молодые фичи не попадают.
UFO just landed and posted this here
UFO just landed and posted this here
Об этом я даже не подумал :)
В первую очередь меня смущает то, что может найтись чудак (особенно учитывая целевую аудиторию 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...
}


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

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

Я люблю Go, но вот это конкретное место — это очень плохой дизайн. Имхо.
UFO just landed and posted this here
TH это, кстати канонический пример костыля, т.к. радостно ломает абстракции (скрывает типы за ExpQ), в отличии от Generics, и даже появляющийся Typed-TH не очень поможет в силу ограничений. (Правда в отличии от generics позволяет генерировать более эффективный код, с расширениями generics такое тоже возможно, но уже не так просто). Естественно плюс TH, в отличии от, насколько я понимаю, go, в том, что генерация производится средствами языка, что не мешает вызывать внешние утилиты если необходимо. А совсем хороший вариант в MetaOcaml, например.
UFO just landed and posted this here
Магические комментарии — это костыль. Претензии к тому, КАК сделали.
Лучший критический комментарий за два поста, imho.
«Костыль» — это ярлык, не более. Shebang — это тоже такой-же «костыль», что не мешаем ему исправно выполнять свою функцию на всех UNIX-системах, не так ли?
Так что важнее — практическая польза или чей-то ярлык «костыля»? Какие реальные практические проблемы с go generate были хотя бы у одного из комментаторов тут? Да ни у кого.

Конкретно по поводу go generate — был пропозал и были дискуссии о том, как лучше решить проблему. В дискуссии мог поучаствовать каждый хабровчанин и предложить «не костыль», обосновав, почему его «не костыль» будет хорошим дизайном.
Костыль, но имеющий четко определенное место. Он идёт первой строкой в самом начале файла. Его сложно не заметить и тем боле спутать с чем-то другим.
Аналогично другой костыль — указание кодировки файла для python 2. Тоже расположен в первой или второй строке и только там.
По сути дела они придумали препроцессор, но сделали вид, что они не при делах.
с make сравнили бы ещё ладно, но это не препроцессор
По факту ведь берется этот файл с магическими комментариями и на основе него генерируется другой, новый файл. Это ли не препроцессор в чистом виде?
При помощи make тоже можно препроцессор к любому языку программирования приделать.
По факту запускается любая команда, это как тоже самое, что сказать make или bash это препроцессор.
Эти запуски не как не связаны с процессом компиляции, в зависимостях которые вы ставите они не вызываются, только запуски руками.
Почитайте https://blog.golang.org/generate, возможно просто я плохо объясняю.
Ну просто получается, что необходимость в кодогенерации нужна, то есть по факту нужны обобщения, но их нет в языке и нет никакого стандарта на них.
Вот тебе и плата за простоту.
Не всё что решается генерацией можно решить обобщенным программированием. Примеры с генерацией парсеров и тп.
Думается мне, что такие вещи нужно решать через генераторы парсеров, которые вообще на другом языке написаны, специально для этого созданном, а не встраивать их в комментарии.
ну если вы начнете читать, что вам люди пишут может даже диалог получится.
//go:generate go tool yacc -o gopher.go -p parser gopher.y
как думаете что такое yacc?
yet another compiler compiler — генератор парсеров?
Отсюда:
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

UFO just landed and posted this here
Ну вот Boost.Spirit обходится без препроцессоров.
UFO just landed and posted this here
Видимо автор этой статьи знает и умеет в Go, но вот эти обиды, нападки на другие языки и «неверных» можно было бы и опустить.
Нападки на языки — это упоминание С++ в эпилоге?
По-видимому, Вы пропустили мой комментарий ( хотя это неудивительно, их тут уже 120+ ).
Просто все, кто писал на C++, переключившись на другие языки — изливают накопившуюся боль оттого, что столько лет провели на темной стороне силы :)
Я писал на C++, теперь на C++ и Haskell, но отчего-то боли не ощущаю :)
Go никому не нужен.
Программист C++ легко освоит его, это да.
Но в обратном я сомневаюсь.
Уместней было бы сказать «легче». Зачем вешать неуместные ярлыки на людей.
А по части нужности судить не вам думаю.
После того как меня «отхабрили» в предыдущем обсуждении Go, мне стало все равно.
UFO just landed and posted this here
Это пост любви к Go, тут нельзя так грубо.
Эм, не стоит, тем более в выходной.
Может человек в Эмиратах живёт)
UFO just landed and posted this here
Статья же автора о том, что дизайн языка «плохой» — это, к сожалению, не более, чем попытка привлечь к себе внимание

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

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

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

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

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

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

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

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

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

#include <iostream>
#include <string>

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

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

Угу.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

С остальным, про идеальные строки и взаимодействие с пользователем, я согласен. Но C++ так не работает, он плюётся байтами.
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.
Понимаете ли какая штука… Природа оперирует только атомами, в природе нет никаких битов, байтов и кодировок, там и оперативной памяти как таковой нет.
Я-то согласен, но те же рассуждения применимы и к обычным числам, где приходится почему-то знать, сколько там байт внутри. Но много ли где умолчальный Int — безразмерен? А float/double?
Ну да, умолчание в C++ — это дефолтная локаль, которая не факт что utf8 (особенно в случае с windows).
Потому что плюсовики не замусоривают хабр статьями с восхвалениями своего инструмента.
Первой появилась статья негативная. А эта не восхваление, а восстановление статус кво.
Зато до этого большинство статей только о том, какой это прекрасный язык. Как это обычно бывает со всеми новыми IT игрушками. Тот же docker какой прекрасный распрекрасный нам рисовали все время. NoSQL как нам рисовали, помнится. Правильно люди на конференциях Go говорят — перед знакомством с языком надо опустить свои ожидания, которые из-за хайпа вокруг него завышены очень сильно. Тогда язык не будет казаться непонятной хренью непонятно для чего.
Далеко не первой.
Забавно, что отсутствие отрицательных индексов избавит вас от страшных багов, а несовсем-нулевые-интерйесы — мощнейшая технология, которую надо просто выучить.
Поэтому нужно переходить на Раст и никаких вам недостатков.
Радуюсь ежедневно.
Мы рады, что вы радуетесь, а можно аргументировать? Почему это «поэтому»? Недостатки есть везде, нет ничего идеального.
Я использую силу плюсов других хабравчан за доказательство!
UFO just landed and posted this here
Из за Go меня отхабрили. Ненавижу Go.
Теперь хочу посвятить жизнь написанию гневных публикаций против Go.
Обида живет в груди глупых
Вы правы. Не стоит обижаться на хомячков.
Go не нужен.
Почему?
Asm все равно быстрее…
UFO just landed and posted this here
UFO just landed and posted this here
Проблема в том, что скрывается за функцией «reversed» и какие операции оно выполняет :)
И в итоге все становится на свои места.
Я боюсь, что проблема в том, что в питоне можно написать одну функцию reversed и пользоваться ей, а вот в Go — только если авторы языка подарили.
Только вот разница описанного мной подхода и с использованием «reversed» скрывается в алгоритмической сложности.
А вы готовы утверждать, что невозможно написать такую реализацию reversed, которая будет иметь алгоритмическую сложность, сопоставимую с простым обходом массива?

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

который, судя по названию, делает то же самое, что цикл с убывающим индексом, только удобнее. Поэтому в алгоритмической сложности разницы нет вообще.
Спасибо за уточнение, аргумент вполне себе.
Го ориентирован на скорость работы. В го вы тоже можете написать функцию которая вернет список обратный заданному… но это копирование памяти которого можно избежать. Поэтому приходится больше кода как плату за скорость работы.
UFO just landed and posted this here
В го вы тоже можете написать функцию которая вернет список обратный заданному… но это копирование памяти которого можно избежать.

(1) эта функция, как неоднократно обсуждалось, не может быть универсальной
(2) некоторые языки, внезапно, позволяют это сделать без копирования
Обратный обход можно записать несколько проще: http://play.golang.org/p/Ij9XjQQixz. Да, не reversed, но.
UFO just landed and posted this here
В котором практически отсутствует смысл в отсутствии дженериков, которые, как известно, нинужны. Х)
Интент теряется, к сожалению. Хотя визуально элегантно.
даже в C++ можно сделать
for (auto i : boost::adaptors::reverse(x)) {
    ;;
}
UFO just landed and posted this here
Это было убрано намеренно, потому что выражение s[i:j] может молча дать неверный результат, если j станет меньше нуля.
Выражение s[i:j] может молча дать неверный результат, если i или j станет не тем положительным числом, о котором думает программист, представляете! И то, что j станет вдруг отрицательным после того как было положительным ещё менее вероятно, и это, скорее всего, будет уже совсем другая проблема.

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

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

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

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

создание UNIX

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

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

И это всё я пишу лишь к тому, что авторитет, каким бы он не был, это для разумного человека ещё не довод принимать мнение этого авторитета без аргументов.
Я видел код на Rust — это новый C++. Т.е. про удобство — это не в кассу.
Самое большое зло Go, это не косяки в языке, а его комьюнити. Такого количества слепо наяривающих на своего любимчика фанбоев, нету даже у JS.
Угу и благодаря этому комьюнити на Go сейчас создаются или переписывается довольно таки большое количество проектов. Не надо переходить на личности, это как минимум не культурно.
з.ы.Недавно узнал что в SpaceX используют Go.
Да что Вы тролля кормите :)
UFO just landed and posted this here
Про С++ когда-нибудь слышали? Ваш Go еще из пеленок не вырос. Все еще на стадии «а что же это за зверь такой»
UFO just landed and posted this here
UFO just landed and posted this here
Так в том-то и дело, что вы не просто пишете на go, вы вдобавок пишете статьи о том, как пишете на го. А вот это уже непростительно!
</irony>
Мне кажется это, как тут уже говорили, имидж языка, который вот такими статьями и создается. Язык вроде и не плох, и есть чем ему похвастать против остальных, но вот такое вот комьюнити создает враждебную атмосферу, когда уже на любых защитников языка кидаются с уверенностью, что это наверняка очередной фанатик, который дальше своего Go видеть разучился, аргументов внятных предоставить не может кроме «Пайк сделал, значит правильно». И ведь много таких в комментариях даже здесь. Напротив, хейтерства именно я вижу мало. Я вижу людей, которые обсуждают то, что им не нравится. А против них обычно фанатик, который внятно свою позицию обозначить не может. Просто слепая вера какая-то в святость путей, избранных Go.
А можно пример, где в C++ undefined behavior от сокрытия переменных? Что-то не могу придумать
Ну, я не согласен, что тут дело в сокрытии переменных. Если убрать внешний int x, ничего не поменяется.
Отлично, спасибо за практичный разбор. По многим пунктам согласен.

for number := range numbers {}


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

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

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

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

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

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

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

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

— Стёб на стёбе, конечно. Но если убрать шелуху, то всё выглядит именно так. И с языком, и с его комьюнити, и с этими двумя статьями.
Аналогия интересная, но явный перекос в мануальный негатив :) Не забывайте, что перед эксплуатацией автомобиля на дороге нужно сдать на права.
Права в данном случае это теоретические аспекты программирования и практический опыт на каком-либо языке (паскаль в основном, наверное). Вы же не сдаёте на права при покупке нового автомобиля всякий раз? :)
Ну если ездил на коробке автомат, то поучить как себя ведет машина с ручной коробкой будет не лишним.
UFO just landed and posted this here
Э не. Я сел в автомобиль, мне не понравилось, и я рассказал об этом остальным. А вы почему-то воспринимаете критику языка на свой счет.
UFO just landed and posted this here
Ситуация как раз обратная. За вами никто не бегает. Вот написал человек статью. Мол, не понравился мне язык — потому что первое второе третье…
А автор этой статьи начинает ему доказывать — все так как надо, и так должно всем нравится, а вот у других как раз плохо. Так кто за кем гонится? И кто не обращает внимания? Появилась бы эта статья, если бы никто не обращал никакого внимания?
Отнюдь, статья была не «мне не понравился язык», а «какой плохой дизайн у языка». Статья, которую, не читая, репостят и рассылают, а комментарии оккупированы людьми, не знакомым с языком, но люто его ненавидящим, и искажающим реальную картинку. Эта статья — зеркальный ответ для уравновешивания, не более.