Pull to refresh

Comments 77

Документация — для пользователей (Documentation is for users)

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

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

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

> «Конкурентность — это не параллелизм»

Многозадачность.

> Чем больше интерфейс, тем слабее абстракция

А смысл редуцировать все интерфейсы до одного метода? Не проще ли сразу фигачить сигнатуры этих методов?

> Стиль Gofmt — это не чье-то предпочтение, но gofmt предпочитают все

Смысл делать его тогда отдельным тулом? Внесите эти правила в спеку и пусть компилятор ругается.

> Как пример — функция IsPrint из пакета strconv — она дублирует функционал unicode.IsPrint(), при этом тесты проверяют, что функции работают одинаково.

И что хорошего в этом индусском подходе?

> Пайк говорит, что написал, вероятно, больше всех кода с рефлексией в Go, и до сих пор ненавидит это делать.

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

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

А смысл редуцировать все интерфейсы до одного метода? Не проще ли сразу фигачить сигнатуры этих методов?

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

Смысл делать его тогда отдельным тулом? Внесите эти правила в спеку и пусть компилятор ругается.

Тул форматирует код, делая эту работу за человека.

Значит ему стоило поработать над этим аспектом языка, чтобы он стал простым и понятным.

Простите ему, он не так мудр. А потом почитайте про essential complexity.
> Где сказано, что в Go нет разделяемой памяти?
тут:
> ваши функции не делят одну и ту же память, они безопасно общаются, передавая данные по каналам.

То, что это не правда уже понятно, раз есть мьютексы :-D Похоже постулаты можно нарушать, если ты Роб Пайк.

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

У интерфейсов есть 2 функции:
1. идентификационная (в го не используется)
2. группировочная (в го не рекомендуется)

Так зачем в го интерфейсы, если достаточно сигнатур?

> Тул форматирует код, делая эту работу за человека.

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

> Простите ему, он не так мудр. А потом почитайте про essential complexity.

Жду статью про essential complexity рефлексии :-)
У интерфейсов есть 2 функции:
1. идентификационная (в го не используется)
2. группировочная (в го не рекомендуется)
«Идентификационной функцией» вроде как пользуются в стандартной либе повсеместно (io.Reader, io.Writer, fmt.Stringer). На счет «группировочной функции» тоже не понятно. Вроде как есть рекомендации не делать интерфейсы большими. Рекомендации избегать группировки методов или интерфейсов в одном интерфейсе вроде нет.

P. S.: может не понял, что вы в эти два понятия вкладываете.
1. Может быть множество равных интерфейсов с разными именами, вы не можете отличить io.Reader от my.Reader если в них объявлены одинаковые сигнатуры
2. Есть рекомендация минимизировать число сигнатур вплоть до одного метода
Зачем мне отличать io.Reader от my.Reader, если мне нужно всего то совершить некое действие? Мне важно чтоб обьект поддерживал это действие, кто он мне глубоко не важно и не нужно их идентифицировать. В го это прекрасно работает.
Поэтому я и написал, что в го идентификационная функция не используется в отличие от других языков.
Два эти метода могут иметь одинаковые сигнатуры, но совершенно различную семантику. Вы можете явно или неявно воспользоваться таким методом не в том контексте и го не выявит такую ошибку на этапе компиляции. В лучшем случае она будет обнаружена тестами.
Так это правильно, мне не важно как он будет делать свои дела, мне важно чтоб он сделал определенное действие. Мне кажется это логичным действием для интерфейса, он не должен указывать как, он должен указывать что. А по поводу контекста, это уже вопросы к архитектуре и способностям программиста следить за тем что он делает. Никто ведь не ругает си за указатели, это мощная штуковина, но ей нужно грамотно пользоваться, тоже и с интерфейсами в го, ими нужно грамотно пользоваться а не как попало. Нужно продумывать интерфейсы, это большая часть философии языка, они не такие как в других языках и это нужно учитывать, это не плохо и не хорошо, это просто по другому.
По поему вы вообще говорите о разном. vintage говорит о том, что в языках C# и Java интерфейс — это не просто множество функций, которые могут быть реализованы для того или иного объекта, но ещё и «метка»: да, этот объект действительно пригоден для использования в определённом качестве. Интерфейс Cloneable вообще ни одного метода не содержит, что не делает его бессмысленным!

Хорошо это или плохо? Я бы сказал что конкретно в языках C# и/или Java этот подход выглядит… странно. Потому что они во-многом являются наследниками С, а на Pascal'я. В наследниках Pascal'я (Oberon или какая-нибудь Ada) вариант, который реализован в Java был бы вполне естественнен: там даже функция, принимающая массив из 10 элементов может не принять массив из 10 элементов если это — другой массив (в смысле массив другого типа)! В C++ интерфейсов, строго говоря нет, так что обсуждать их бессмысленно, но когда их предлагали добавить, то, разумеется, предлагалась версия в стиле C, а не версия в стиле Pascal'я!

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

Это обозначает, по большому счёту, что для «генетического программирования» (в программе объединяются куски со StackOverflow в случайной последовательности пока не начинают проходить тесты, после чего код отправляется в production) язык Go подходит не так хорошо, как Java. Я вообще не уверен, что поддержка подобного стиля программирования — то, к чему стоит стремиться, но то, что Go для него не подходит — правда, тут как бы особо и спорить не о чем.
Да, я это и имел ввиду, сам пишу на PHP и там в интерфейсы вкладывают то же что и vintage имеет ввиду, по интерфейсу можно так же идентифицировать прибывший обьект, поэтому я такое поведение знаю хорошо. с другой стороны и понимаю почему в го изменили саму сущность интерфейсов, для него такой тип не подходит. Может я просто не так выразился :)
Вообще-то си ещё как ругают за указатели и именно потому, что с ними легко не просто прострелить себе ногу, а скастовать чёрную дыру. И мы до сих пор огребаем проблемы с безопасностью из-за того, что кто-то на заре юникс подумал «а давайте сделаем вот такую мощную штуку с которой нужно грамотно обращаться, а не как попало».

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

Вы либо не хотите понять, о чём речь, либо хотите, но не получается. Постулат призван помочь понять подход CSP (с каналами и рутинами), а не запретить использовать мьютексы.

Так зачем в го интерфейсы, если достаточно сигнатур?

Достаточно для чего? Интерфейс — это «строительный блок», помогающий создавать красивые архитектуры. Возьмите тот же io.Reader, с которым работают многие функции стандартной библиотеки. К примеру, декодер JSON принимает как параметр io.Reader, и ваша программа туда может передавать всё что удовлетворяет io.Reader — файл, тело http-ответа, стрим из сокета, буфер или что угодно.
Ещё раз — интерфейс это не «идентификация методов», это строительный блок программы. И, как и в философии UNIX, маленькие блоки, описывающие одну операцию, позволяют строить разнообразные и сложные конструкции.

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

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

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

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

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

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

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

Вы сейчас о чём-то о своем рассказываете, весьма пространном, и, соответственно, делаете странные выводы

Какжеэтоутомительновручнуюрасставлятьпробелы

Не понимаю вашего паясничания. Будьте добры, засеките сколько времени у вас займёт преобразовать вот такой простой плохочитаемый пример:
type User struct {
    ID int64 // user id
    Name          string              // user first name
   Surname    string      // given name
    Birth      time.Time              // user birthdate
}

вот в такой:
type User struct {
	ID      int64     // user id
	Name    string    // user first name
	Surname string    // given name
	Birth   time.Time // user birthdate
}

У go fmt это занимает миллисекунды, если что. Именно поэтому go fmt обычно стоит как hook на сохранении файла в редакторе/IDE.
В таком случае это никакие не постулаты. И вообще всю статью можно было бы свести к «думай головой» и не морочить голову протекающими принципами.

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

И часто вы пишете такой простой плохочитаемый код? :-D это ж ещё не полениться надо столько пробелов понаставить…
И часто вы пишете такой простой плохочитаемый код? :-D это ж ещё не полениться надо столько пробелов понаставить…

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

type User struct {
    // user id
    ID int64
    // user first name
    Name string
    // given name
    Surname string
    // user birthdate
    Birth time.Time
}


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

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

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

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

Я не вижу никаких сложностей так писать код, если это настолько критичная для вашей работы вещь, что вы готовы отказаться от такого удобного инструмента, как go fmt.
Субъективные настройки форматирования для вас настолько критичная вещь, что вы готовы отказаться от нормальной работы с СКВ?
Это не «субъективные настройки», это отсутствие ада, с которым приходилось сталкиваться раньше в других языках. И да, для меня это важнее, чем «чуть менее удобное представление части диффа в 1% случаев, при необходимости их внимательно инспектировать». Код я пишу чаще, чем анализирую диффы, и такое мелкое отличие, которое отнюдь не требует «телепатии», несравнимо с гарантией нормально отформатированного кода.
Если честно, не представляю, почему для кого-то может быть иначе, кроме как если ваша основная работа — код ревью. Но и тогда, будь у вас опыт с go fmt, вы, по идее, больше всех оценили бы его эффект в реальной практике.
Я не понимаю, почему я вообще обязан идти на компромисс: либо общий стиль оформления, либо нормальные комиты.

Для других языков, например (внезапно), C++, тоже есть инструменты для автоформатирования. При этом эти инструменты не зависят от хотелок какого-то конкретного человека. Каждая команда может установить свой стиль и «нормально» форматировать код в рамках команды/проекта/компании.

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

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

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

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

Ха-ха, а от кого же они зависят? Вот приходите вы в новую компанию, а там тим-лид установил «стиль», который вам неприятен/неудобен. В Go такой проблемы нет — стиль один и темы «а я люблю/хочу вот так» нету в принципе.
Ну и не говоря уже о том, что написание code guide для С++ — это та ещё забава, которая вводится обычно после большой боли, вызванной тем, что вы называете «преимуществом». А соблюдать большой команде эти code guide-ы — это тоже отдельная забава, отнимающая и без того излишне отнятое время при С++ разработке.
Я лично за 10+ лет натерпелся этого вдоволь, так что нет, спасибо.

Не надо выдавать недостаток за преимущество.

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

Нет ни одного плюса в том, что каждый человек/тим пишет код так, как это позволяет его фантазия/квалификация.

В Go такой проблемы нет — стиль один и темы «а я люблю/хочу вот так» нету в принципе.

… это однозначно преимущество, тут даже сомневаться не в чем ...


Зря я затеял разговор с религиозным фанатиком.
Зря я затеял разговор с религиозным фанатиком.

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

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

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

Вот git blame — да, тут это может помешать, но, как бы опцию -w никто пока не отменял.

Какую-такую деятельность с СКВ вы разводите, что она стоит того, чтобы вдвое увеличить количество строк ухудшив притом ещё и читабельность? Просто интересно — я могу поверить что существует такой код, где это может быть критично, но как-то за много лет никогда с таким не сталкивался…

P.S. А настройки форматирования как раз не субъективны, а впроне объективны: что gofmt сделает — то и будет. Тут нет места разговорам и переливанию из пустого в порожнее.
Вообще статья неплохая, но первое предложение просто убивает. Это в Го-то простые правила? Вы их вообще читали? Или нет? Когда оба игрока пасуют подряд, игра заканчивается — уже в одном это правиле столько всего сконцентрировано: а если я не хочу пасовать? Что со мной сделают? И вообще — много вы знаете игр, которые имеют отдельную страницу Варианты правил XXX (в английской версии отдельной страницы нет, просто страница с описанием правил содержит целую кучу вариантов, правил подсчёта очков и прочего). Нифига себе «простые правила»…
Нет, к сожалению, я в игру не играл и с правилами не знаком. В докладе Пайк противоставил игру го шахматам, как разные подходы к настольным играм в восточной и западной культуре. Наврал? :)
В этом месте — не наврал. Подходы — действительно разные. И язык Го тут похож на игру, да.

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

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

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

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

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

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

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

Что значит «нет возможности не сдаться»? Типичная игра в го заканчивается двумя способами: кто то сдаётся (точно также как в шахматах) или оба играют до тех пора пока захваченные области не будут касаться друг друга. Если вы имеете ввиду, что второй случай равносилен первому, потому что непонятно можно ли в какой либо из территорий построить живую группу, то это не так: в большинстве случаев можно доказаться с математической строгостью, что такую группу построить нельзя, а в тех 1% случаев где это неочевидно, можно добавить пару камней и сразу станет очевидно.
Типичная игра в го заканчивается двумя способами: кто то сдаётся (точно также как в шахматах) или оба играют до тех пора пока захваченные области не будут касаться друг друга.
И оба случая — это «сдача по собственному желанию».

Если вы имеете ввиду, что второй случай равносилен первому, потому что непонятно можно ли в какой либо из территорий построить живую группу, то это не так: в большинстве случаев можно доказаться с математической строгостью, что такую группу построить нельзя, а в тех 1% случаев где это неочевидно, можно добавить пару камней и сразу станет очевидно.
А вот здесь мы уже приходим к тому же, что и в статье: вместо того, чтобы дойти до состояния, когда человек вынужден пасовать (до сакраментальной фразы «вам мат»), вы доходите всего лишь до состояния где что-то можно сделать «с математической строгостью». Игра го никогда на практике не доходит до точки, где ни один из противников не может ходить. Никогда. Хотя правила этого и не запрещают.

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

Это не так, потому что в типичной игре оба игрока имеют как правило территории по 40-50 клеток и максимум там можно поставить 20-30 камней, если уж сильно хочется тянуть резину.
Это если вы «хотите ясности» вы можете туда поставить 20-30 камней :-) А вот если «тянуть резину», то туда начнёт ставить камни ваш противник — и он, разумеется, может довести дело до того, что вам придётся ставить камни на его территорию (иначе — да, вы снимите его камни, но территории-то больше останется у него), дальше всё это снимется с обоих сторой и пойдёт на второй круг, потом — на третий и так далее.
Каким образом Go принуждает меня красиво обрабатывать ошибки?
Где написано, что Go вас принуждает?
В том то то и дело, что нигде не написано. У Go какие-то красивые постулаты и принципы, вот только сам язык им не соответствует.
Обоснуйте, пожалуйста. Почему вам кажется, что Go не соответствует своим же постулатам?
> Небольшое копирование лучше небольшой зависимости
> Как пример — функция IsPrint из пакета strconv

А я посмотрел исходники. Там написано, что это костыль из-за слабого линкера, а не из-за «небольшое копирование лучше небольшой зависимости». 40 строк кода (не учитывая тестов) без единого изменения это не «небольшое копирование», а индусский код.

Пруф:
>> 405 // TODO: IsPrint is a local implementation of unicode.IsPrint, verified by the tests
>> 406 // to give the same answer. It allows this package not to depend on unicode,
>> 407 // and therefore not pull in all the Unicode tables. If the linker were better
>> 408 // at tossing unused tables, we could get rid of this implementation.
>> 409 // That would be nice.

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

Там написано, что эту реализацию можно будет убрать, если линкер сможет убирать неиспользуемые таблицы. Но суть остается той же — небольшое копирование может быть выгодней дополнительной зависимости.
> Там написано, что эту реализацию можно будет убрать, если линкер сможет убирать неиспользуемые таблицы
В моём комментарии (в частности, цитата из quote.go) именно это и сказано. Для чего вы повторяете слова собеседника?

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

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

Прошу прощения, но я не вижу выгоды в необходимости поддержки двух разных версий одной и той же функции (и, да, я смотрел исходный код и версии в пакете unicode)

Вы эту концепцию в принципе не понимаете или конкретно с примером в strconv она вам не нравится?
> более точно цитирую
Куда уж точнее кусочка, вырезанного из комментариев в исходнике? :)

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

> Вы эту концепцию в принципе не понимаете или конкретно с примером в strconv она вам не нравится?

Скопировать строчку-три-пять ещё, возможно, пойму, но не всю же функцию в 40 строк. Тем более, позднее выяснилось, что это другая реализация функции IsPrint, и, соответственно, разработчикам необходимо [было написать и] поддерживать обе её версии.

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

Пожалуйста.

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

Это одно и то же, и сути это не меняет — скопировать одну функцию может быть проще и эффективнее, чем тянуть новую зависимость, и причины этого могут быть совершенно разные. Никто же не говорит, что это всегда правильно, но там где это уместно — это нормально.
Т.е. индусский говнокод — это нормально, даже по «уважительным» (это каким?) причинам? О_ok.
К сожалению абсолютно пустой пост.

Берем те же принципы. Убираем «Cgo is not Go», меняем «interface{} says nothing» на «void * says nothing» и получаем вполне корректный набор «постулатов» для C.
С такими же минимальными изменениями можно натянуть на любой язык.

Ну вы переборщили слегка. «Каналы оркестрируют...» — тоже на С натянете? )

Но в целом да, многие постулаты тут относятся не только к Go, а к программированию в целом. И в этом и сила (и критика особо зашарпленных хабровчан) Go, что он навязывает вам эти взгляды на программирование, формируя вокруг языка круг людей, разделяющих эти взгляды и культуру программирования. Пайк в этом докладе об этом упоминает в конце.
А почему нет?
Давным давно писал на сях и использовал тогда модный подход с очередями. Они у меня как раз каналами и назывались.
Или вы думаете что каналы в Go настолько уникальны, что никто не догадался похожую сущность придумать в других языках? Просто в других языках это делается на уровне библиотек, а не языковых конструкций.
Нет, я так не думаю, и более-менее знаком с реализациями подходов CSP в других языках. Но если вы всё еще сопротивляетесь, могу дальше возвразить — постулат «Gofmt's style is no one's favorite, yet gofmt is everyone's favorite» тоже на «С и любые языки» не натянешь :)
Да, его забыл упомянуть. Но сути это не меняет, от 70% до 90% написанного верно для любого языка, не только Go. Называть это «постулатами Go» — лишь попытка приравнять Go и современные языки. Хотя Go откровенно отстает. Большое количество неформальных правил как раз этому подтверждение.
И про пакет unsafe забыли, и про syscall, ага.

от 70% до 90% написанного верно для любого языка

Большое количество неформальных правил как раз этому подтверждение.

Вы же только что написали, что 90% написанного верно для любого языка, а строчкой ниже этим же пытаетесь «доказать», что Go отстаёт от ваших любимых языков.
Для любого языка верно около 70% «постулатов» с синтаксическими отличиями. Оставшиеся описывают слабость языка. Например у C и Go общих «постулатов» гораздо больше, чем у C# и Go. Очевидно, что Go — низкоуровневый язык.

В C# например нет проблем с interface{}, рефлексией и обработкой ошибок, потому что в языке есть generic, dynamic и Exception. У языков с significant whitespace нет потребности в fmt и нет холиваров по поводу правильной расстановки скобочек. У C++ нет проблем с подключением еще одной библиотеки, компилятор выкинет из бинарника все лишнее. «Пустые» значения во многих языках отсутствуют, конструктор при необходимости всегда вызывается.

Фактически «постулаты» это обратная сторона проблем языка.
В C# например нет проблем с interface{}, рефлексией и обработкой ошибок, потому что в языке есть generic, dynamic и Exception. У языков с significant whitespace нет потребности в fmt и нет холиваров по поводу правильной расстановки скобочек. У C++ нет проблем с подключением еще одной библиотеки, компилятор выкинет из бинарника все лишнее. «Пустые» значения во многих языках отсутствуют, конструктор при необходимости всегда вызывается.
Давненько я такого не видел. То есть я видел случаи когда люди искренне заблуждались… но чтобы настолько…

И ведь смысла писать длинные посты нет: в вашем мире нет ни PEP 008, ни других style guideов и разных beautifierов, никто не борется с мегабайтами кода которые подтягиваются из-за libICU и вообще всё в мире зашибись, а если у кого-то, кто пользует языки, отличные от Go, наблюдаются проблемы — ну так это из-за того, что у него карма плохая (пользователи Go, разумеется, страдают от выбора языка, с ними всё полнятно).

Вот только скажите: вы профессиональный тролль или вы действительно верите в ту чушь, что тут написали?
Вы как-то извратили мою мысль. Я сказал что постулаты — суть недостатки Go. Собственно любые «правила», «гайды» которые не поддерживаются компилятором — признак слабости языка\компилятора.

Я вовсе не говорил, что другие языки идеальны, куча недостатков есть у питона, C, С++, Java и C#. Это вовсе не значит что Go от этого стал хорош.
Мне кажется вы, намеренно или не очень, путаете мысль «design patterns are bug reports for your language» и эти постулаты.

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

Если внимательно посмотреть, то в спсике есть proverbs трех типов:
1) Общепрограммистские истины (конкурентность — не параллелизм, продумывайте все, пишите документацию для пользователей)
2) Оправдание ошибок дизайна (Рефлексия непонятна, Ошибки это значения)
3) Паттерны, описанные общими словами (мьютексы, share by communicating, пустые значения, интерфейсы с одним методом, использование fmt итд)

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

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

Почему паттерны являются недостатками попробую объяснить.
Например вы говорите что есть постулат вроде, «делать X, чтобы получить результат Y».
Это означает, что есть несколько способов сделать Y, но авторы языка считают идеологически правильным способом X.
Тогда зачем оставили другие способы? Причины могут быть разные, но обычно совместимость и быстродействие.
Если основная причина наличия двух (правильного и неочень) сделать одно и то же — совместимость, то почему не сделали флаг компилятора, который включает режим совместимости.
Если основная причина — быстродействие, то почему вообще авторы рекомендуют медленный путь, как «идеологически правильный»? Не поработали над быстродействием или есть расхождения между желаемым уровнем абстракции и фактическим?

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

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

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

Всё таки я верно угадал — вы путаете эти «постулаты» с паттернами.

Долго думал над первой фразой «Don't communicate by sharing memory, share memory by communicating.» и тому чему же она соотвествует в го. Озарение не пришло. Наверно моего хилого 1-го дана для этого мало?
Совсем никаких идей?
В этой фразе вроде как есть мутный намёк на территории и вроде как обмен (?) ими, но этом мне не сильно помогает.
Есть «классический» способ синхронизации работы с данными из нескольких потоков — через разделяемую память, там используются «классические» примитивы — мьютексы и семафоры. Это «communicate by sharing memory».
В Go же есть более мощный способ строить разнообразные архитектуры программ, в которых много «тредов» — с помощью каналов, select-а и goroutin. Там не нужны мьютексы, потому что передача объекта по каналу — тождественно передаче владения. Это «share memory by communicating».
Это всё понятно, но вопрос был не о том. В статье написано, что «постулаты несут глубинный смысл для тех, кто знаком с игрой го.» Ну вот он я — знаком с этой игрой на уровне хилого первого дана, но никакого глубинного смысла в этих фразах не вижу.
В том абзаце речь идёт о книжке с постулатами об игре го. В статье — с постулатами о языке Go.
Прокачивайте свой дан внимательности значит )
Sign up to leave a comment.

Articles