За два года с тех пор, как я опубликовал статью I want off Mr Golang's Wild Ride, она вновь и вновь всплывала на Reddit, Lobste.rs, на HackerNews и в других местах.

Всякий раз дискуссия выходит к одним и тем же ответам:

  • Вы говорите о Windows: а ведь как раз с Windows язык Go не слишком хорош! (Опять же, кого это волнует?)

  • Вы однобоки: о сильных сторонах Go вы не говорите!

  • Вы не понимаете тех компромиссов, на которые мы идем в Go.

  • Крупные компании используют Go, значит, не так уж он и плох!

  • «Правильно» моделировать задачи очень затратно, поэтому забота о корректности – спорный довод.

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

  • Вы сразу ссылаетесь на Rust, но и у него есть свои недостатки, так что ваш аргумент никуда не годится.

  • Т.д.

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

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

Автор - утконос

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

Например, на момент написания статьи верхний комментарий на HackerNews начинается со слов:

«Автор в корне не понимает, как построены языки программирования».

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

Не нужно большого умения, чтобы заметить проблему.

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

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

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

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

На самом деле, я спроектировал язык еще в 2009 году (по меркам программирования, тогда я был еще плаксивым грудничком), суть которого сводилась в обваливании С в синтаксическом сахаре. На тот момент этот язык сочли достаточно интересным и даже пригласили меня на OSCON (тогда я впервые оказался в Портленде, штат Орегон, столице кофе, гранжа, ненастья и белых людей), где мне довелось встретиться с другими юными и не столь юными молокососами (работавшими над Io, Ioke, Wren, JRuby, Clojure, D, Go, т.д.)

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

С тех пор я совершенно забросил мой авторский язык, поскольку стал присматриваться к семантике гораздо внимательнее, чем к синтаксису – по этим же причинам я также не интересовался Zig, Nim, Odin, т.д.: меня более не интересует проект «напишем еще один C, только лучше».

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

Мама курит, так может, это нормально?

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

Это отличный способ открывать для себя новые технологии для последующей оценки (как вариант – можно читать Tech Radar от ThoughtWorks), но этого далеко не достаточно.

Опус компании X о том, "как мы использовали технологию Y" лишь очень редко отражает, какой ценой в компании удалось освоить данную технологию. До того, как программистов (авторов поста) силой заставят написать такой текст в корпоративный блог, успела закончиться многомесячная неравная битва, было принято техническое решение, и пути назад уже нет.

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

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

Есть, конечно, и некоторые исключения. Например, блог Tailscale настолько искренний, что кажется глотком воздуха. Но, прочитав у них такие статьи как netaddr.IP: a new IP address type for Go или Hey linker, can you spare a meg?, можно отреагировать по-разному.

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

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

Разнообразные проблемы, упомянутые в статье о netaddr.IP, обусловлены следующими причинами:

  • В Go нет тип-сумм — и поэтому там реально неудобно написать тип, который представлял бы «либо адрес IPv4, либо адрес IPv6»

  • Выбор Go по поводу того, какие структуры данных вам понадобятся – в данном случае, речь идет о срезе «один на все случаи жизни», каждый из которых на 64-разрядной машине обойдется вам в 24 байта

  • Go не допускает перегрузки операторов, напоминая о той давней истории Java, когда a == b не было идентично a.equals(b)

  • В Go отсутствует поддержка неизменяемых данных. Единственный способ предотвратить любые изменения каких-либо данных – вручную раздавать их копии, проявляя при этом особую осторожность, чтобы не изменить их в том коде, который фактически обладает доступом к внутренним разрядам

  • Go не слишком способствует вам, если вы хотите написать на нем непрозрачный "newtype". Единственный способ это сделать – написать отдельный пакет и обеспечить опосредованность при помощи интерфейсов, что дорого и неудобно

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

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

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

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

Но есть и хорошие новости

Ну ладно, но ведь Tailscale продолжает пользоваться Go до сих пор. Можно вспомнить случай, когда в 2020 году мой пост о Windows вызвал рой скептических замечаний «но ведь Go для этого не слишком годится» — точно так можно отмахнуться и от постов Tailscale как «ну, они же сами захотели сдавать такой код для iOS / заниматься низкоуровневыми сетевыми операциями».

Весьма честно! Окей. Давайте поговорим о тех вещах, в которых Go блистает.

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

Все это также характерно для Node.js с момента его появления (в сущности, он представляет собой libuv + V8), и, как я полагаю, также касается «современной Java» с такими API как NIO. Хотя я и не проверял в деталях, что творится на территории Java, вы можете вообще не читать эту статью, если хотите попридираться к мелким неточностям: она же бесплатная.

Поскольку асинхронная среда выполнения образует ядро языка, в нагрузку к ней предлагается и инструментарий, которому в самом деле завидуют Rust-разработчики! Я рассказываю об этом, например, в статье Request coalescing in async Rust.

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

Легко подхватить и полюбить инструментарий Go, обеспечивающий управление пакетами, рефакторинг, кросс-компиляцию; на первый взгляд этот арсенал определенно воспринимается как серьезный шаг вперед на фоне многочисленных человеко-часов, потраченных на борьбу с капризами pkg-config, autotools, CMake, т.д. До тех пор, пока вы не столкнетесь с какими-то как ниоткуда возникшими ограничениями, просто не удостоившимися внимания со стороны команды Go — и вы остаетесь с этими проблемами один на один.

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

Но один реально хороший компонент погоды на платформе еще не делает.

По-настоящему удобная асинхронная среда выполнения не единственная вещь, которую вам придется принять. Также понадобится освоиться с очень своеобразным тулчейном, системой сборки, соглашением об именованиях, единственным сборщиком мусора (независимо от того, подходит он вам или нет), а также с набором «готовых батареек», притом, что некоторые из них МОЖНО поменять на другие, а оставшуюся часть экосистемы – нет. Самое важное, что вы беретесь за работу на языке, который возник случайно.

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

Думаю, именно такие ощущения у кого-то возникают от Rust.

Но излишне поверхностное отношение к чему-либо также опасно.

Очевидно, команда Go не собиралась проектировать язык. Им по-настоящему нравилась лишь их асинхронная среда выполнения. Они хотели добиться, чтобы у них получилось реализовать поверх нее TCP, HTTP, TLS, HTTP/2, DNS, etc., т.д. А над всем этим – ещё и веб-сервисы.

Но они этого не сделали. Вместо этого они спроектировали язык. Просто из разряда «он взял и получился».

Поскольку этот язык должен был казаться знакомым «недавно выпустившимся из университета гуглерам, уже в какой-то степени изучавшим Java/C/C++/Python» (Роб Пайк, Lang NEXT 2014), в Go оказались заимствования из всех этих языков.

Точно как и C, Go вообще не утруждает себя обработкой ошибок. Весь код – большой пушистый ком изменяемых состояний, и именно вы отвечаете за то, чтобы ОЧЕНЬ ОСТОРОЖНО (и только вручную) добавлять в него if-ы и else-ы, а также заботитесь о том, чтобы недействительные данные никуда не просачивались.

Go, точно как и Java, пытается стереть различия между «значениями» и «ссылками», поэтому (при рассмотрении с места вызова) невозможно судить о том, будет некоторая сущность меняться или нет.

import "fmt"

type A struct {
	Value int
}

func main() {
	a := A{Value: 1}
	a.Change()
	fmt.Printf("a.Value = %d\n", a.Value)
}

В зависимости от того, какова сигнатура изменения – такая:

func (a A) Change() {
	a.Value = 2
}

или такая:

func (a *A) Change() {
	a.Value = 2
}

...локальное a в main либо будет меняться, либо не будет.

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

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

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

Что совершенно логично, ведь слезть с Go по-настоящему тяжело.

Go - это остров

Если только вы не используете cgo, (но cgo не Go), то ваш мир похож на киновселенную из фильма «План-9».  

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

Go ближе к герметичным языкам, чем к C или C++. Даже Node.js, Python и Ruby не столь враждебны к FFI (интерфейсам внешних функций).

В значительной степени это фича, а не баг – ведь выделяться так круто. Такой подход не лишен достоинств. Когда есть возможность профилировать нутрянку стеков TLS и HTTP с той же легкостью, что и бизнес-логику приложения – это просто фантастика (тогда как в динамических языках стектрейс обрывается на OpenSSL). Ещё такой код в полной мере пользуется удобствами, связанными с отсутствием окрашивания функций: он может переложить на среду выполнения все заботы, связанные с неблокирующим вводом/выводом и планированием.

Но за это приходится ужасно дорого платить. Для многих вещей имеется отличный инструментарий, который с Go неприменим (но применим для работы с теми фрагментами, которые написаны на cgo, но опять же, не следует использовать cgo, если вы хотите Испытать Все Прелести Go). Здесь теряются все «институциональные знания», и приходится переучиваться с чистого листа.

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

Замечание: по состоянию на Go 1.13 сугубо двоичные пакеты больше не поддерживаются

Обеспечение красивого взаимодействия Go с (любым) другим языком – задача действительно сложная. Для вызова C из Go, не говоря уже об издержках на преодоление границы FFI, требуется вручную отслеживать дескрипторы, только бы не сломать сборщик мусора. (В WebAssembly была точно такая же проблема до появления ссылочных типов!)

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

Потратив годы на эти пляски с FFI (туда-сюда), я пришел к выводу, что единственная хорошая граница с Go – сетевая.

Интеграция с Go получается относительно безболезненной, если вы можете мириться с задержками, возникающими при вызове удаленных процедур (RPC) по TCP (будь то HTTP/1 API в стиле REST, либо что-нибудь вроде JSON-RPC или более сложная схема, такая, как GRPC, т.д.). Кроме того, только так можно обеспечить, чтобы Go не «заразил» всю вашу базу кода.

Но даже это недешево: вам придется поддерживать инварианты по обе стороны границы. В Rust в таком случае можно было бы прибегнуть к чему-нибудь вроде serde, которая, вкупе с тип-суммами и отсутствием нулевых значений, обеспечивает достаточную уверенность, что у вас в «мешке» действительно «кот»: если число – это ноль, значит, здесь и ожидался ноль, это не какая-нибудь недостача числа.

Все это выходит за рамки, если вы используете некоторый формат сериализации, например, protobuf, обладающий всеми недостатками системы типов Go, но ни одним из достоинств.

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

На этом мы подходим к более крупной общей проблеме – культуре Go.

Все или ничего (так не будем же делать ничего)

Я упомянул о том, что «поля структур остаются неинициализированными». Это легко происходит в случаях, когда мы меняем код примерно со следующего

package main

import "log"

type Params struct {
	a int32
}

func work(p Params) {
	log.Printf("Working with a=%v", p.a)
}

func main() {
	work(Params{
		a: 47,
	})
}

На следующий:

package main

import "log"

type Params struct {
	a int32
	b int32
}

func work(p Params) {
	log.Printf("Working with a=%v, b=%v", p.a, p.b)
}

func main() {
	work(Params{
		a: 47,
	})
}

Вторая программа выводит на экран:

2009/11/10 23:00:00 Working with a=47, b=0

В сущности, мы изменили сигнатуру функции, но забыли обновить то место, где её вызывают. Компилятор это совершенно не волнует.

Довольно странно, но, если бы наша функция была структурирована вот так:

package main

import "log"

func work(a int32, b int32) {
	log.Printf("Working with a=%v, b=%v", p.a, p.b)
}

func main() {
	work(47)
}

Мы получили бы ошибку компиляции:

./prog.go:6:40: undefined: p
./prog.go:10:7: not enough arguments in call to work
	have (number)
	want (int32, int32)

Go build failed.

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

Дело в том, что один из постулатов Go в том, что нулевые значения хороши.

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

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

package main

import "log"

type Container struct {
	Items []int32
}

func (c *Container) Inspect() {
	log.Printf("We have %v items", len(c.Items))
}

func main() {
	var c Container
	c.Inspect()
}
2009/11/10 23:00:00 We have 0 items

Program exited.

Это хорошо! Ведь срез []int32 в самом деле является ссылочным типом, и его нулевое значение есть nil, а len(nil) просто возвращает ноль, потому что, «очевидно», нулевой срез пуст.

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

package main

type Container struct {
	Items map[string]int32
}

func (c *Container) Insert(key string, value int32) {
	c.Items[key] = value
}

func main() {
	var c Container
	c.Insert("number", 32)
}
panic: assignment to entry in nil map

goroutine 1 [running]:
main.(*Container).Insert(...)
	/tmp/sandbox115204525/prog.go:8
main.main()
	/tmp/sandbox115204525/prog.go:13 +0x2e

Program exited.

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

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

  • Операция отправки в канал nil блокируется навечно

  • Операция получения из канала nil блокируется навечно

  • Операция отправки в закрытый канал вызывает панику

  • Операция получения из закрытого канала немедленно возвращает ноль

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

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

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

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

А в Go ответ на эту проблему – «просто будьте аккуратнее». Так же и в С на это отвечали.

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

Всего-то ещё одна вещь, за которой нужно тщательно следить.

Которая, в любом случае, не избавит вас от всех проблем.

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

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

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

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

Давайте же обсудим этот тезис.

Rust идеален, а вы все дураки

Как бы я хотел испытывать именно такие чувства, поскольку объяснять их было бы настолько проще.

Эту искусственную версию также очень легко разбить. «Как же вы тогда дошли до работы с Linux? Он же написан на C». «Rust небезопасен, поэтому писать на нем правильно невероятно сложно, как вам этот факт?»

Успех Go большей частью обусловлен тем, что в нем «все включено», а также есть жесткие умолчания.

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

Обе эти истории рассказывают об успехе, но эти истории успеха очень разные.

Если верить в конспирологическую версию «Rust – это замануха», то почему всем сразу не отбросить все старое, выбрав «Единственный Хороший Язык Из Всех Существующих»?

Такая позиция настолько далека от реально происходящих событий, что даже трагична.

База кода Firefox написана в основном на C++, но несколько критически важных компонентов в ней написаны на Rust. В проекте Android недавно повторно реализовали на Rust весь стек Bluetooth. Криптографический код Rust смог закрепиться в Python, коду Rust для HTTP нашлось место в curl (как в одном из многих бекендов, имеющихся в наличии), а патчи на Rust для ядра Linux с каждой итерацией смотрятся все лучше.

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

Мы очень далеки от подхода «выплеснуть ребенка с водой». Бекенд для кодогенерации под Rust, которым пользуются буквально все – это гора кода, написанного на C++ (LLVM). Любые альтернативы невозможно признать его конкурентами, сколько ни напрягай фантазию – исключением может быть, пожалуй, только еще одна гора кода на C++.

Самые закоренелые пользователи Rust громче всех кричат о проблемах, например, о том, сколько длится сборка, об отсутствии в языке определенных фич (просто дайте мне GAT!) и обо всех других недостатках, о которых говорят почти все остальные.

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

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

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

Люди, у которых развивается аллергия на «огромные комья изменяемых состояний без тип-сумм» обычно тяготеют к языкам, в которых удобно контролировать изменяемость, сроки жизни, а также строить абстракции. Не суть, что таким языком зачастую оказывается  Go и Rust. Иногда на их место заступают C и Haskell. Еще в некоторых случаях — ECMAScript и Elixir. Не скажу за них с уверенностью, но такие языки встречаются.

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

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

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

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

«Правильный» способ предположить, что установлено опциональное значение – сказать, что это так, а в противном случае не использовать его. В этом и есть разница между вызвать json.Unmarshal и скрестить пальцы – и вызвать unwrap() применительно к Option<T>.

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

Что подводит нас к следующему аргументу, который (с запасом) является самым резонным во всем букете.

Go - это прототипный/затравочный язык

Вот мы и добрались до пятой стадии: принятия.

Хорошо. Готов согласиться, что Go не подходит для продакшен-сервисов, если только ваша гильдия не состоит из одних только экспертов по Go (Tailscale) или если вы не можете потратить сколько угодно денег на инженерные расходы (Google).

Но у Go, определенно, остается своя ниша.

В конце концов, Go – язык, на который легко перейти (потому что он такой маленький, верно)? Сейчас уже много тех, кто его выучил, поэтому набрать Go-разработчиков легко, так почему бы не запастись ими за сходную цену и – уххх! – напрототипировать парочку систем?

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

Все бы хорошо, только не существует такой штуки как «бросовый код».

Все технические организации, которые мне известны, ИСКЛЮЧИТЕЛЬНО не любят ничего переписывать, и на то есть причины! Требуется время, чтобы организовать гладкий переход, в суете теряются детали, сдача новых фич тормозится, а еще приходится переучивать сотрудников, чтобы они шли по новому треку так же эффективно, как и по старому, т.д.

Масса хороших, веских причин.

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

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

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

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

Поскольку сигнатуры функций вам практически ни о чем не говорят (она изменяет данные? Она удерживает их? Нормально ли здесь нулевое значение? Запускает ли этот код горутину? Может ли этот канал быть нулевым? Какие типы в самом деле можно передать для этого параметра interface{}?), приходится полагаться на документацию, обновлять которую дорого, а не обновлять еще дороже – ведь тогда будут возникать новые и новые баги.

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

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

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

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

Я думал, что мы давно изжили убеждение, что «программирование – это битье по клавиатуре», но, когда я снова и снова читаю: «так можно же быстро написать много Go!» — такая уверенность пропадает.  

Неотъемлемая сложность никуда не денется, если просто зажмуриться.

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

В настоящее время я часто оказываюсь таким кем-то и уже устал от этого.

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

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

Это Ошибка на миллиард долларов, очередная.

Подведём итоги

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

  • Другие им пользуются, значит, и для нас он будет хорош

  • Все, кто скептически относятся к Go – это выскочки-элитарии

  • У Go такая привлекательная асинхронная среда выполнения и сборщик мусора, что они компенсируют все остальное

  • В отдельности любой языковой изъян – не страшен, и в совокупности они тоже не страшны

  • Все недостатки преодолимы, нужно «просто быть аккуратнее» или добавить лишних линтеров/внимательных глаз

  • Поскольку на Go легко писать, на нем легко разрабатывать софт для продакшена

  • Поскольку язык прост, все остальные связанные с ним вещи тоже просты

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

  • Потом всегда можно переписать.

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


  1. asaks
    14.07.2022 16:46
    +10

    Вторая программа выводит на экран:
    2009/11/10 23:00:00 Working with a=47, b=0

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

    В сущности, мы изменили сигнатуру функции,

    Но ведь сигнатура функции не поменялась, она как принимала на вход структуру Params, так и принимает


    1. DarthVictor
      14.07.2022 17:14
      +34

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


      1. aegoroff
        14.07.2022 21:56
        +7

        Да, добавлю лишь то, что в Rust вы не можете инициализировать структуру, которая не реализует trait Default, не указав все поля, которые есть. И даже если реализует этот trait, в инициализаторе явно надо писать ..Default::default() вроде, показывая что остальные поля будут инициализированы значениями по умолчанию


        1. svr_91
          15.07.2022 08:33
          +5

          Зато когда вы напишите ..Default::default() вам откроется уникальная возможность добавить новое поле, забыв его проинициализировать


          1. aegoroff
            15.07.2022 09:00
            +12

            Не совсем так - это будет ровно такое же поведение что и в Go, т.е. инициализация значением по умолчанию, но это явно и вы для этого должны приложить усилия (либо руками реализуя Default либо через #[derive(Default)]), в отличии от неявного поведения, которое никак не выражено синтаксически в вашем коде.


          1. orekh
            16.07.2022 05:59
            +1

            Эта штука в Go напоминает проблему null'ов, по какой-то причуде названной фичей и расширенной. Всё-таки лучше, когда возможность отсутствующих значений явно прописана ввиде Option<Value or None> вместо того чтобы ожидать их везде.


    1. paveltyurikov
      14.07.2022 17:17
      +10

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


    1. nin-jin
      14.07.2022 18:14
      +2

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

      import std.stdio, std.traits, std.format;
      
      struct Params {
      	mixin Strict;
      	int a;
      	int b;
      }
      
      void work( Params p ) {
      	writeln( "Working with ", p );
      }
      
      void main() {
      	work( Params(47) );
      	/+
      		Error: none of the overloads of `this` are callable using argument types `(int)`
      			Candidate is: `onlineapp.Params.Strict!().this(int _param_0, int _param_1)`
      	+/
      }
      
      
      mixin template Strict() {
      
      	@disable this();
      
      	this( FieldTypeTuple!(typeof(this)) args ) {
      		static foreach( Index, Field; FieldNameTuple!(typeof(this)) ) {
      			mixin( format( q{ this.%s = args[ %s ]; }, Field, Index ) );
      		}
      	}
      
      }


      1. Refridgerator
        15.07.2022 07:12
        +1

        Это D?


        1. nin-jin
          15.07.2022 09:16
          +2

          Агась.


      1. Borz
        15.07.2022 10:54
        -4

        В Go можно использовать обёртку Optional, если уж прям очень хочется для примитивов понимание "был параметр явно присвоен или нет: https://pkg.go.dev/github.com/searKing/golang@v1.1.18/go/util/optional

        Правда есть минус - теперь мы "потеряли" тип примитива и должны его знать

        import "github.com/searKing/golang/go/util/optional"
        
        type Params struct {   
          a optional.Optional   
          b optional.Optional
        }
        
        func work(p Params) {   
          log.Printf("Working with a=%d, b=%d", p.a.Get(), p.b.Get())
          if p.a.IsPresent() {
            log.Printf("calc: %d", 1+p.a.Get().(int))
          }
          if p.b.IsPresent() {
            log.Printf("calc: %d", 1+p.b.Get().(int))
          }
        }
        func main() {
          work(
            Params{
              b: optional.Of(2),
            },
          )
        }


        1. PROgrammer_JARvis
          15.07.2022 12:59
          +3

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

          Не говоря о НЕтипобеопасности


          1. Borz
            15.07.2022 14:34

            ну, можно и так - тут потери типа уже нет. Правда теперь в лог пишется адрес, а не значение поля. Но тут либо шашечки (примитивы с default value), либо ехать

            type Params struct {
            	a *int
            	b *int
            }
            
            func work(p Params) {
            	log.Printf("params: %++v", p)
              log.Printf("calc: %d", 1 + *p.a)
            }
            
            func main() {
            	a := 2
            	
            	p := Params{a: &a}
            }

            А про обязательность поля - по мне, так это достаточно удобно , когда примитив можно явно не указывать и ему присваивается default value - меньше писанины. На то он и примитив, а не объект


            1. siziyman
              15.07.2022 15:23
              +3

              когда примитив можно явно не указывать и ему присваивается default value

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

              Далеко не всегда default value типа имеет какой-либо смысл в реальном мире в том контексте, в котором этот тип используется в структуре. Хотя ладно: когда его нет, это ещё ничего, хуже, когда это значение по умолчанию смысл реально имеет - и потом поди догадайся, забыл автор его инициализировать или там и правда этот нолик стоит и с ним нужно работать (и, например, дебажить, почему у вас где-то косяк в коде дальше - проблема в вашей логике или этот нолик забыли инициализировать, что привело к неконсистентному состоянию данных в этой структуре).


    1. vlmonk
      14.07.2022 18:17
      +15

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

      да


    1. AnthonyMikh
      15.07.2022 01:28
      +8

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

      Да. Честно, я не понимаю, зачем эту "фичу" вообще реализовали, она даже больше кода в компиляторе требует.


    1. ghostiam
      15.07.2022 05:10
      +3

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

      Этот код не скомпилируется:

      package main
      
      import "log"
      
      type Params struct {
      	a int32
      	b int32
      }
      
      func work(p Params) {
      	log.Printf("Working with a=%v, b=%v", p.a, p.b)
      }
      
      func main() {
      	work(Params{
      		47,
        }) // <- Error: too few values in struct literal
      }
      


      1. Cerberuser
        15.07.2022 08:36
        +12

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


        1. ghostiam
          15.07.2022 08:44
          +1

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

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


          1. inferrna
            15.07.2022 12:28
            +2

            Можно указывать, но можно и не указывать. А если указали, то не обессудьте - вот тут для вашего удобства у нас такое поведение дополнительно зашито, читайте справочник по нашему самому простому языку в мире, стр 1531, третий абзац снизу. Я бы ещё понял, если бы дефолтное значение задавалось явно, как kwargs в питоне:

            type Params struct {
            	a int32
            	b int32 = 0
            }


        1. Kekmefek
          15.07.2022 09:17
          +3

          Не надо держать. IDE подсветит.

          В первом случае я указал явно field `a` со значением, тогда b будет иметь значение `0` по умолчани.


    1. slonegd
      15.07.2022 15:58
      -1

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


  1. maledog
    14.07.2022 16:47
    +13

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

    Мне например проще управляться с указателями, чем понять код где через слово self-self-self или this-this-this.


    1. Sin2x
      14.07.2022 17:01
      -14

      Потому что он топит за Раст, очевидно же, хотя это и языки с совершенно разными применениями и скоупом. Для 2022 года довольно типичный rant. Сейчас вот смотрю плашку справа, Go 122 вакансии, Rust 21 -- не даёт покоя это любителям раста аж до скрежета зубовного, кушать не могут.


      1. siziyman
        14.07.2022 18:09
        +31

        Нет, вы это сами себе придумали. :)

        Не пишу на Раст. Не топлю за переход на один конкретный язык. Это не мешает мне утверждать, что Go - пример отвратительного языкового дизайна, и для того, чтобы стало лучше, чем с ним (если вы конечно не фанатик), достаточно сменить язык на любой другой популярный, подходящий по предметной области. В фронте есть тайпскрипт, в бэке - что угодно от C++ (там конечно своих can of worms хватает), языков с явным рантаймом вроде Java/Kotlin/Scala и C#/F#, и до вещей для любителей экзоткики вроде Haskell.


        1. Sin2x
          14.07.2022 18:12
          +1

          Amos? Не узнаю в гриме.


          1. siziyman
            14.07.2022 18:26
            +8

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

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


            1. Sin2x
              14.07.2022 18:31
              +1

              Автор статьи Amos Wenger -- поэтому мне непонятны слова "Нет, вы это сами себе придумали. :)" от кого-то, кроме него. Только он может это сказать.

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


              1. siziyman
                14.07.2022 18:34
                +3

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

                Потому как даже среди тех, кто статью всячески ругал и защищал го в комментариях HN, реддита, и куда ещё там его статьи шерились, такого нелепого мнения я не встречал.

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


                1. Sin2x
                  14.07.2022 18:39
                  +3

                  Я уже написал всё, что хотел -- я считаю, что автор под критикой Го прикрывает продвижение Раста. Sapienti sat, dixi.

                  P.S. В обсуждении на HN упоминаний Раста 111 штук: https://news.ycombinator.com/item?id=31205072 Без комментариев.


                  1. siziyman
                    14.07.2022 18:51
                    +9

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

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


                    1. domix32
                      15.07.2022 09:59

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


        1. bosha
          14.07.2022 22:37
          -4

          Прям таки и большой выбор языков для бэка... Тащить java и производные либо отдаться мелкомягким? Просто отличный выбор :)


          1. nin-jin
            14.07.2022 22:49
            +9

            А остальные языки уже не компилируются что ли?


          1. Source
            15.07.2022 01:51
            +2

            Для бэка довольно много языков по факту. Если опираться на аргумент "у Go такая привлекательная асинхронная среда выполнения и сборщик мусора, что они компенсируют все остальное", то можно в качестве альтернативы взять упомянутый в статье Elixir, у которого и асинхронная среда выполнения и сборщик мусора сильно лучше, чем у Go. К тому же, при необходимости в него можно добавить щепотку Rust, если вам где-то в проекте нужна числодробилка.


            1. 0xd34df00d
              15.07.2022 01:52
              +4

              Если готовы брать эликсир, то возьмите уже хаскель. У него с многопоточностью тоже очень всё хорошо, гринтреды есть, шедулер хороший, GC хороший, STM — вообще прелесть.


              1. nin-jin
                15.07.2022 02:02
                -1

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

                Ближе всего к мейнстриму эта штука: https://vibed.org/


                1. Source
                  15.07.2022 22:02
                  +2

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


                  1. nin-jin
                    15.07.2022 22:26

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


                    1. Source
                      15.07.2022 22:55
                      +2

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

                      Под "зачахла" я подразумеваю, что активность коммитов существенно снизилась, см. график по ссылке, продублирую вам её: https://github.com/vibe-d/vibe.d/graphs/contributors

                      Ну, и вы всерьёз считаете активным проект, у которого между версиями 0.9.4 и 0.9.5 проходит примерно год? А 384 issues намекают, что стабильность весьма условна. На половину из них даже никакого ответа нет, что на практике, скорее всего, значит что нет ни одного человека, который занимается поддержкой этого проекта за зарплату.


                      1. nin-jin
                        15.07.2022 23:22

                        Не ошибся. Это ветка "что бы посоветовать человеку вместо го". Не будьте таким эгоцентричным.

                        Ну и гадать по графикам вы не умеете. До середины 2018 шла активная работа над двумя мажорными версиями 0.7 и 0.8. В середине 2018 развитие седьмой версии было завершено.

                        Проект над которым продолжают работу - активен. Зрелому проекту частые релизы ни к чему. Всего 384 issues только 16 из которых - баги, что весьма не плохой результат. Ну а на зарплате там никто не сидит, да.


                      1. Source
                        16.07.2022 01:10
                        +1

                        Блин, чувак, пиши себе на D, никто ж тебе не запрещает.

                        Но нафига ты влез в ветку сравнения Elixir c Haskell, которые оба уже много лет имеют веб-фреймворки, до которых vibe.d как до луны что по фичам, что по стабильности (88 issues у Yesod и 26 у Phoenix). А ты пытаешься нас убедить, что 384 - это мало. Нет, это over дохера для веб-фреймворка. Ладно бы это только цифра была, ты зайди на Github, посмотри, что по большинству issues никакого обсуждения нет, им даже не присвоены никакие метки. С таким подходом к разработке кол-во issues будет только расти год от года и сколько там среди них багов никто не знает, потому что их никто тупо даже не читает. Что это, если не заброшенность?

                        Зрелому проекту частые релизы ни к чему.

                        Зрелому то да, только vibe.d до зрелости пока не добрался. Где пруфы, что авторы принципиально не планируют версию 1.0? На их сайте я такого тезиса не увидел. Или вы просто выдаёте желаемое за действительное?


                      1. nin-jin
                        16.07.2022 01:53
                        -2

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

                        Овердохера - это 5к ишьюсов у GHC против 3к у DMD. И что? Да ничего. Тоже мне гадание по гитхабу.


                      1. Source
                        16.07.2022 13:16
                        +2

                        Во-первых, некорректно с темы фреймворков на тему самих языков перепрыгивать.

                        А во-вторых, с каждым коментом ты закапываешь D всё глубже и глубже. Я интереса ради зашёл в их багзиллу ????????‍♂️
                        И что я вижу: 4719 issues found. Видимо, с тех пор как ты заходил в issues tracker своего любимого ЯП, он успел ещё почти 2k issues набрать.

                        И чего ты сравниваешь с GHC, который себя как исследовательский проект позиционирует? Или ты посмотрел на Elixir с его 26 issues и обосрался от зависти? xD
                        Можешь даже 249 issues от Erlang/OTP приплюсовать.
                        А то вы со своим D даже хипстерский Crystal в 4 раза по кол-ву issues обогнали.



                      1. 4reddy
                        16.07.2022 13:18
                        +3

                        Просто у Дмитрия склонность форсить проекты, которые "не взлетели". К слову сказать, действительно интересные, классные технологии. Но, к сожалению, нужные 2,5 энтузиастам :)

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

                        Прошу меня извинить, что я влез в ветку сравнения Elixir c Haskell.


                      1. nin-jin
                        16.07.2022 15:49

                        Ну а какой смысл рассказывать людям про проекты, которые "взлетели"? Они и так про них знают. Каждый раз, когда я вижу очередное нытьё про Go или C++, React или Angular, мне становится грустно от того, сколько времени люди убивают на бестолковые решения, вместо того, чтобы вложить его с большей пользой для "взлёта" чего-то, что может вытянуть индустрию из этого болота.


                      1. 0xd34df00d
                        16.07.2022 18:15
                        +3

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


                      1. Source
                        17.07.2022 01:24
                        +3

                        В этом я могу вас понять. Но D, к сожалению, закопали сами разработчики, сначала расколов и так небольшое комьюнити на Phobos и Tango прям аккурат в момент релиза 1.0. А потом и полгода не прошло, как бросились вторую мажорную версию языка пилить. В довершение ко всему этому ещё и не уловили тренд на OpenSource. Тем самым отложив интеграцию с gcc лет на 10.

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


                      1. nin-jin
                        17.07.2022 09:20
                        -3

                        Да-да, у го прекрасная интеграция с гцц, а дженерики не раскалывают сообщество. Всё, что вы перечислили, на популярность не влияет вообще.


                      1. Source
                        17.07.2022 12:55

                        Да-да, у го прекрасная интеграция с гцц

                        Тем не менее, через 3 месяца после выхода Go 1.0 она уже была. А сколько лет с релиза D 1.0 прошло до включения в GCC?

                        а дженерики не раскалывают сообщество

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

                        Всё, что вы перечислили, на популярность не влияет вообще.

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


              1. Source
                15.07.2022 02:59
                +3

                А чего Cloud Haskell до стабильной версии не дотащили и забросили?
                Не нравится мне shared memory, даже под соусом STM.

                Так то мне многие идеи Haskell импонируют, но OTP - это прям самое мощное и самое подходящее, что я видел, для веб-разработки среди порядка 20 ЯП.

                Под BEAM, кстати, появился ML-подобный язык, в активной разработке сейчас: Gleam. Как автор признаётся, он хотел его сделать похожим на Haskell, но из-за негативной обратной связи отказался от этой затеи.


                1. 0xd34df00d
                  16.07.2022 04:57
                  +1

                  Спросил у людей, плотно пиливших cloud haskell — вы не поверите, но забросили именно из-за отсутствия интереса у коммьюнити в пользу (D)STM.


                  1. Source
                    16.07.2022 13:34

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


                    1. siziyman
                      16.07.2022 14:10

                      Мимопроходил - а Akka Typed в скале - это не те самые строго типизированные акторы?


                      1. Source
                        17.07.2022 01:09

                        Да, они. Но к JVM у меня какая-то личная неприязнь. Всё, что я на ней видел, имело медленный старт и дико жрало память.

                        Возможно, в Akka.NET тоже что-то подобное есть, но до F# я пока не добрался)


                    1. 0xd34df00d
                      16.07.2022 18:12
                      +2

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


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

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


                      Я вообще за минимальный и тупой язык, и перенос максимального количества всего в библиотеки. Условный row polymorphism так, конечно, не сделаешь, а вот акторы эти — ИМХО вполнле.


                      1. Source
                        17.07.2022 01:05

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

                        Я вообще за минимальный и тупой язык

                        Как же вы с Haskell уживаетесь? Я бы не назвал его ни минималистичным, ни тупым.

                        Лично мне распределённый STM больше понравился. 

                        По-моему, DSTM, как и CloudHaskell, тоже давно заброшен.


                      1. 0xd34df00d
                        17.07.2022 01:18

                        Как же вы с Haskell уживаетесь? Я бы не назвал его ни минималистичным, ни тупым.

                        Довольно паршиво, Haskell is the new C++.


                        Но минималистичные альтернативы почему-то не имеют толком библиотек.


                      1. DarkEld3r
                        17.07.2022 11:11

                        А можно несколько примеров этих альтернатив?


                      1. nikolas78
                        17.07.2022 12:05

                        Новый ЯП не хотите сделать (без прикола)? Чтобы простой ЯП + библиотеки из Haskell/Scala/F#/etc?


              1. domix32
                15.07.2022 10:04
                +2

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


                1. 0xd34df00d
                  15.07.2022 18:26
                  +1

                  Комунити у хаскела шибко токсичное в собственной илитарности

                  Я бы сказал, что это либо про коммьюнити из этак 2005-го, либо про людей, которые пишут очередной туториал по монадам. Коммьюнити что в IRC, что на условном SO вполне отзывчивое и не то чтобы илитарное.


                  гайдов/доков не сказать чтобы достаточно

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


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


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

                  Prelude, с одной стороны, действительно стрёмный, с другой — дописываешь пакеты с hackage в package.yaml и вперёд, а их там дофига, включая вкусные :]


                  1. domix32
                    16.07.2022 18:58

                    Я бы сказал, что это либо про коммьюнити из этак 2005

                    Телега на самом деле не моя, но программистов которые пытались вкатиться в функциональщину. Обычно самым большим минусом зовут консерватизм/элитаризм языка ("в 1970е уже все изобрели") и закидывание шапками за отсутствие знаний из теорката и прочих смежных дисциплин.

                    Prelude, с одной стороны, действительно стрёмный

                    опять же я не столько за стандартные библиотеки, сколько за УДОБНЫЕ инструменты каким стал cargo у Rust. Сборка, управление пакетами, всякие флаги оптимизации, подпись/публикация пакетов и куча прочего по большому счету не связанного непосредственно с кодом - все из одного места и без большой боли. Опять же я на настолько функциональных языках, как Haskell, длиннее Hello world не писал, поэтому по большей части ссылаюсь на опыт других людей и допускаю, что не так плох чёрт, как его малюют.


                    1. 0xd34df00d
                      17.07.2022 01:17

                      Обычно самым большим минусом зовут консерватизм/элитаризм языка ("в 1970е уже все изобрели")

                      Это точно не про хаскель (да и вообще ни про один из известных мне хардкорных ФП-языков) — туда постоянно что-то допиливают.


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

                      ХЗ, возможно, тонкости российского хаскелесообщества.


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


                      опять же я не столько за стандартные библиотеки, сколько за УДОБНЫЕ инструменты каким стал cargo у Rust. Сборка, управление пакетами, всякие флаги оптимизации, подпись/публикация пакетов и куча прочего по большому счету не связанного непосредственно с кодом — все из одного места и без большой боли.

                      Ну так это, stack же.


                    1. Source
                      17.07.2022 01:36

                      Могу предложить вам попробовать Elixir. Сообщество дружелюбное, теоркат знать не требуют, инструментарий удобный: iex, mix, hex.


                      1. domix32
                        17.07.2022 02:09
                        +1

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


      1. Eugeeny
        15.07.2022 10:08
        +1

        least butthurt gopher


    1. paveltyurikov
      14.07.2022 17:34
      +14

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


      1. maledog
        14.07.2022 17:59
        -9

        Больше похоже "на вот пять спорных недостатков - давайте к нам в rust". При этом не приводится даже как же эти недостатки в rust решены.


        1. siziyman
          14.07.2022 18:06
          +20

          Нет там никакого "давайте к нам в Rust", вы это сами себе придумали. :)

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


          1. Sin2x
            14.07.2022 18:17
            +2

            Звучит как-то неконкретно. Можно пару примеров?


            1. siziyman
              14.07.2022 18:31
              +17

              Мутабельность данных, от которой нельзя избавиться - ключевые слова final, const и иже с ними (val/var) есть давно в примерно каждом языке, на котором я писал и который я помню.

              Неумение разделять данные и ошибки, данные и отсутствие данных - всякие там "монады" (на самом деле не во всех языках они реализованы стандартно как честные монады - например, джавовый Optional монадические законы нарушает) Optional/Maybe/Try.

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


              1. maledog
                14.07.2022 20:51
                -6

                В golang есть const. Почему вы и автор статьи вдруг решили что нет? Я встречал исключения java которые отправлялись по почте программисту. Там было 500 Mb текста (просто обернул try все приложение tomcat). Естественно это письмо ему не пришло. Это точно лучший способ обрабатывать ошибки? Был еще такой вариант try, а результат игнорируем. При этом я часто встречал, как на обработку ошибок забивали совсем. К примеру дергаем какую-нибудь функцию из winapi(у которой есть задокументированное возвращаемое сообщение об ошибке) и не обрабатываем ошибку совсем. Потом приходим и делаем мозги сисадмину, как же так - почта не отправляется. Смотрю в логи: а на почтовый сервер никто даже не постучался. По мне так в go не так уж плохо с ошибками, если есть возвращаемая ошибка, то ее нужно явно проигнорировать, либо не обрабатывать никаких возвратов из функции совсем. Есть еще вариант "собирался обработать, но забыл". Но для страховки от таких ошибок сейчас есть инструменты.

                Опять же. Сейчас в принципе можно программировать на go в режиме "java-программиста": просто на каждую ошибку вызываем panic и log.Fatal, а в main recover и циклическая перезагрузка приложения, но зачем?


                1. siziyman
                  14.07.2022 20:58
                  +11

                  В golang есть const

                  ...который позволяет использовать только compile-time константные литералы:

                  Constants can be character, string, boolean, or numeric values.

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

                  Там было 500 Mb текста (просто обернул try все приложение tomcat)

                  Да, это какой-то абсурдный эдж-кейс, пример чьей-то некомпетентности. Но встречающееся в бОльшей части увиденного мной го-кода data, err := someCall(); if err != nil { return nil, err}лучше только неабсурдностью, практическая полезность всё ещё нулевая.

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


                  1. maledog
                    14.07.2022 21:41
                    -2

                    ..который позволяет использовать только compile-time константные литералы:

                    А в c и с++ это по-другому?

                    Но встречающееся в бОльшей части увиденного мной го-кода data, err := someCall(); if err != nil { return nil, err}лучше только неабсурдностью, практическая полезность всё ещё нулевая.


                    что вам не нравится в приведенном вам примере? Ошибка не проигнорирована. Она обработана, просто программист решил ничего от себя не добавлять. Может там это и не требуется. Если бы вызвал fmt.Errorf и добавил бы что делал когда ошибка вылезла, было бы лучше? если что там можно указать файл и строку откуда это вызвано, только всегда ли нужно?

                    Кстати возможно вы имели в виду
                    if data, err := someCall(); err != nil { return nil, err}

                    Тогда да. data никогда не будет обработан, err только в случае ошибки, но err = nil никому и не нужен. Но такую ошибку может только новичек совершить, и то, тот что невнимательно вводный курс прошел на сайте.


                    1. cepera_ang
                      14.07.2022 21:52
                      +6

                      А в c и с++ это по-другому

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


                      1. maledog
                        14.07.2022 22:07
                        -5

                        Go с самого начала наследовал именно синтаксис этих языков с поправкой на упрощение синтаксиса и форматирования.
                        Динозавры. Так где там rust/python/java/c# для микроконтроллеров? Почему ардуинщики на них не пишут? Почему когда речь заходит про java или micropython, то там речь про ну вот мы написали обвязку вокруг сишного SDK. А где реальные "дрова" оборудования на rust? А чего это никто еще c++ api из windows до сих пор не выкинул и не заменил на .net?
                        Вот буквально вчера работал в MPLABIDE. И представляешь, там реализация switch на c для микоконтроллеров PIC18 отсутствует.


                      1. cepera_ang
                        14.07.2022 22:35
                        +14

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


                        Ваши любимые С/С++ никуда не денутся, не переживайте, поддерживать легаси придётся вечно. Это не отменяет того, что они динозавры (древние и окаменевшие).


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


                      1. maledog
                        14.07.2022 22:49
                        -6

                        Rust для микроконтролеров вполне используется.

                        Не затруднит показать хоть один реальный проект где не мигают светодиодом и не используют spi/i2c. А что нибудь где например используются прерывания и сон устройства. Короче покажите проект на rust(без использования родного SDK) который использует возможности хотя бы одного контроллера на 100 % gpio/i2c/adc/dac/spi/interrupts/sleep/etc. Потому что фреймворков умеющих мигать светодиодом я видел сотни. А вот когда дело касается реальнызх проектов, то увы и ах.

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


                      1. cepera_ang
                        14.07.2022 23:34
                        +6

                        Вот, например, компания накидала целую ОС для микроконтроллеров, используемых как BMC для их компьютеров.


                      1. cepera_ang
                        14.07.2022 23:44
                        +8

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


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


                      1. maledog
                        15.07.2022 00:11
                        -8

                        Так SDK написанный, как правило, на c - это все, что способен выполнить ваш код <на современном ЯП>. Т. е. единственная его функция вызвать код на С, а дальше зона ответственности заканчивается, т.е. вы запустили rust, который вроде безопасен, но вся безопасность заканчивается на реализации кода на С за который вы не отвечаете, если там в коде кто-то выудит ваши секреты, вы же не отвечаете? Потому моё отношение такое. Хотите доказать, что ваш язык современен, производителен и безопасен - вперед. Спецификции большинства процессоров со всей периферией давно в широком доступе, но что-то не вижу я распространения таковых в широком доступе, вроде бы есть одна ОС на чистом rust, но и у той распространенность и поддержка железа уступает reaсt os. Равно как и существуют прототипы ОС на go. Черт, я даже драйвер для dht-22 на raspberry pi на go написал. Но утверждать, что за rust или go будущее не берусь. Слишком много "перспективных" языков было похоронено за последние 20 лет.


                      1. cepera_ang
                        15.07.2022 00:34
                        +3

                        Назовите «перспективные» языки за последние 20 лет, которые бы претендовали на место С и были бы при этом более безопасными, пользовались поддержкой в индустрии и затем похоронены?


                      1. maledog
                        15.07.2022 00:44

                        Java. В свое время заявлялась как безопасный кроссплатформенный язык у которого отсутсвуют проблемы с памятью. Существовал вариант и для микроконтроллеров JavaME. Сейчас скорее мертв чем жив. Ну или по крайней мере в микроконтроллерах уступает С. В кровавом энтерпрайзе активно теснится другими языками.

                        До нее были Delphi/Pascal.


                      1. cepera_ang
                        15.07.2022 00:55
                        +1

                        Java или Delphi заявлялись как языки для системной разработки на замену С?


                      1. maledog
                        15.07.2022 01:18

                        В свое время (середина нулевых) да. Я вот помню, как многие производители писали консоли управления raid-контроллерами на java, телефоны поддерживающие приложения на javame. Чуть позже телефоны отпали. там появились приложения на c/c++ для windows mobile и symbian, но java me долгое время поддерживали устаревшие промышленные GSM модемы и некоторые станки с ЧПУ. Консоли raid-контроллеров кстати тоже очень быстро вернулись на c++.

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


                      1. cepera_ang
                        15.07.2022 01:27
                        +1

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


                      1. maledog
                        15.07.2022 01:52

                        Android. Я может удивлю, но в свое время некоторые драйверы вполне себе на java писали. Особенно касалось всяких там USB-токенов или весов, или каких-нибудь фискальных регистраторов. Та что там, и прототипы ОС на java были. Так что ничто не ново.

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


                      1. 0xd34df00d
                        15.07.2022 00:53
                        +2

                        Так SDK написанный, как правило, на c — это все, что способен выполнить ваш код <на современном ЯП>. Т. е. единственная его функция вызвать код на С, а дальше зона ответственности заканчивается

                        Я регулярно пишу код на современном ЯП (правда, ему примерно 30 лет, но неважно), который из C дёргает разве что аллокацию памяти от ОС и файловый I/O.


                      1. maledog
                        15.07.2022 01:21
                        -1

                        Т. е. как любой java - код опираясь на java VM?


                      1. 0xd34df00d
                        15.07.2022 01:44

                        Да не, я на нативных языках пишу (ну, по крайней мере, тот код, который в итоге хотя бы запускается).


                      1. domix32
                        15.07.2022 10:18
                        +3

                         rust/python/java/c# для микроконтроллеров

                        за трех последних не скажу, но у раст embed/bare metal есть и цветёт полным цветом. Даже на хабре писали, не говоря уже про официальный шоукейс. Про дрова в статье уже написал - блютус стек андроида, аналогично у Fuchsia, в Линуксе пока на котиках эксперементируют, поэтому в мейнстриме окисленного кода пока нет, хотя Линус уже грозился в следующей версии выпустить немного. На одной из конференций один чувак выступал с рассказом как они ту же ржавчину для спутникового ПО использовали.


                      1. bogolt
                        15.07.2022 21:04

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


                    1. nin-jin
                      14.07.2022 22:31
                      +4

                      А в c и с++ это по-другому?

                      В D определённо по другому.

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

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


                      1. 0xd34df00d
                        14.07.2022 22:52

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

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


                      1. nin-jin
                        15.07.2022 00:05

                        Не вижу с этим проблем. Просто ссылка на отладочную информацию будет в нескольких местах.


                      1. maledog
                        14.07.2022 23:04
                        -4

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


                      1. nin-jin
                        15.07.2022 00:13
                        +3

                        А теперь представьте, что не вы один на проекте, а проект не Hello World, а код писали вообще не вы.

                        Ну да, вы всегда можете руками написать свой кривой стектрейс.


                      1. maledog
                        15.07.2022 01:00
                        -4

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

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


                      1. nin-jin
                        15.07.2022 01:17
                        +4

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


                      1. maledog
                        15.07.2022 01:38
                        -3

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

                        void begin(const char* hostname, uint16_t port)
                        ...
                        void begin(IPAddress ip, uint16_t port)

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


                      1. nin-jin
                        15.07.2022 01:49
                        +1

                        Вы предлагаете глазками что ли вычитывать кто кого где и почему вызывает?


                      1. 0xd34df00d
                        15.07.2022 01:48

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

                        Если честно, одна из вещей, которые я больше всего не люблю в современном хаскеле — это отсутствие нормального стектрейса в функциях вроде head или tail в стандартной библиотеке. Дёргаешь чей-то код, получаешь *** Exception: Prelude.head: empty list — а где оно? откуда? хрен его знает, где, и надо запускать repl, вспоминать, как там трейсить исключения, писать всякое :set -fbreak-on-exceptions или как его, и так далее.


                      1. maledog
                        15.07.2022 02:04
                        -2

                        Так я уже указал. Двух функций с одинаковым именем быть не может. Так что достаточно найти собщение об ошибке, а дальше тех кто его выводит. Если это не твой код, то там как правило сообщения уникальные, тебе остается пронумервать все точки, где это сообщение выводит твой код. Случаи, где return err мне попадаются достаточно редко(как правило это я сам, так я и не делюсь кодом по причине того, что стыдно). Если что-то выкладываю, то стараюсь чтобы там было все обработано.


                      1. nin-jin
                        15.07.2022 02:07

                        Что, и имена методов тоже все уникальные для всех объектов?


                      1. maledog
                        15.07.2022 02:19
                        -3

                        В го же нет методов и объектов в привычном понимании адептов ООП. Но да, для одного "объекта" не может быть двух методов с одним именем. Т. е. будет:

                        OpenbyHostname(hn string)
                        ....
                        OpenbyIP(ip net.IP)

                        вместо

                        Open(hn string)
                        ....
                        Open(ip net.IP)


                      1. nin-jin
                        15.07.2022 02:21
                        +2

                        Речь про разные объекты. Не делайте вид будто не понимаете.


                      1. siziyman
                        15.07.2022 08:54
                        +1

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


                      1. Gazzeline
                        15.07.2022 10:11

                        Всё нормально. Не вижу с этим проблем.


                      1. siziyman
                        15.07.2022 15:37
                        +1

                        Ухудшение читаемости и засорение пространства имён, как по мне. Заставляют дублировать в имени функции то, что прекрасно демонстрируется типом её аргумента.


                    1. mayorovp
                      14.07.2022 22:32
                      +1

                      А в c и с++ модификатор const можно добавить к любому типу данных, и инициализировать любым значением.


                      1. maledog
                        14.07.2022 22:57
                        -1

                        Constants can be character, string, boolean, or numeric values.

                        Какого стандартного типа go тут не хватает. struct? А точно в c struct может быть константой? И часто встречаются константы такого типа?


                      1. mayorovp
                        14.07.2022 23:05
                        +1

                        Ну так ключевое слово const к константам никакого отношения не имеет, так уж сложилось исторически.


                    1. 0xd34df00d
                      14.07.2022 22:49
                      +5

                      А в c и с++ это по-другому?

                      Да, конечно.


                      int main(int argc, char**)
                      {
                        const int dunno = argc;
                      }

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

                      Пробрасывание ошибок — это не их обработка. Это такие монады-экзепшоны для тех, у кого их поддержку в язык не завезли.


                      1. maledog
                        14.07.2022 23:41
                        -3

                        В с ваш пример не компилируется. в С++ работает, но есть ньюанс "не константа, а read-only variable" , тогда так https://stackoverflow.com/questions/47632706/immutable-struct-in-golang

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

                        Таким образом. Все чего яко-бы нет в <язык программирования> на самом деле есть, но как правило делается способом отличным от того, что имел в виду <автор утверждения>, и от того ему лично неудобным. Это кстати относится к любому срачу: Windows vs Linux, MSO vs LO etc.


                      1. 0xd34df00d
                        14.07.2022 23:57

                        В с ваш пример не компилируется.

                        Всё там компилируется.


                      1. maledog
                        15.07.2022 00:30

                        GCC 12, да но 10 уже нет.

                        <source>: In function 'main':
                        <source>:1:20: error: parameter name omitted
                            1 | int main(int argc, char**)
                              |                    ^~~~~~
                        Compiler returned: 1


                      1. 0xd34df00d
                        15.07.2022 00:56
                        +5

                        Могли бы догадаться написать там argv. К константности это не имеет никакого отношения.


                      1. nin-jin
                        15.07.2022 00:17
                        +8

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

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


                      1. maledog
                        15.07.2022 00:37

                        Вы же понимаете, что с подобным подходом вы создаете богатую почву для критики любого ЯП?
                        Развести горы копипасты для <действия>, которое я у себя делаю в два клика.
                        Например в go мне не нужно начинать Hello World с создания класса или объявления namespaces как в C#. Я же не заявляю что шарперы развели копипасту.


                      1. nin-jin
                        15.07.2022 00:45
                        +1

                        Есть не большая разница между "плюс 2 строки" и "в 2 раза больше строк".


                      1. maledog
                        15.07.2022 00:54

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

                        Вроде обязательное форматирование табами столько места не занимает.


                      1. nin-jin
                        15.07.2022 01:20

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


                      1. maledog
                        15.07.2022 01:42

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

                        ну или изначальный const, к структурам не применим, но сообщение об ошибке вполне способен сохранить или число.

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


                      1. BugM
                        15.07.2022 01:52
                        +5

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

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


                      1. nin-jin
                        15.07.2022 01:55

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


                      1. BugM
                        15.07.2022 01:40

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

                        Ну да, кому они нужны?


                      1. xMushroom
                        15.07.2022 11:00
                        +2

                        Вы не заявляете, а шарперы заявляют: https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements


                      1. 0xd34df00d
                        15.07.2022 01:49
                        +1

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

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


                        Как мне в go писать монадические парсеры?


                      1. maledog
                        15.07.2022 02:43

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

                        Я отвечу почему я им занимаюсь.
                        1. Простой. Я не профессиональный программист пришел к go когда для моих задач(системное администрирование/DBA, windows + linux стало не хватать обычных скриптовых языков вроде cmd/sh/bash).
                        2.Когда понадобилось копировать по сети за пределами os.copy
                        3. Когда понадобилось копирование множества файлов одновременно.
                        4. Когда понадобилось запускать свой код на компах где нет нужного рантайма(Можно на .net,вот только тогда еще .net не работал под linux. И у меня был зоопарк систем от windows NT 4.0 до windows 2012, и от centos5 до debian8)
                        5. когда потребовалось за короткий срок написать tcp-сервер принимающий множество сообщений одновременно.

                        6. Когда понадобилось сделать парсер для KX-TDA200 c составлением отчета о звонках.

                        7. А дальше пошло-поехало Modbus-устройства, расширение modbus-tcp, реверсивный modbus и мосты к сторонним системам, modbus over GSM....

                        8. А теперь все то же но на Arm....


                      1. 0xd34df00d
                        15.07.2022 04:15
                        +1

                        А нужно? Для этого есть более подходящий язык?

                        Так более подходящий язык, или «на самом деле есть, но непривычно»?


                      1. mikhanoid
                        15.07.2022 12:14
                        -3

                        А в чём проблема? Пишете return, join, и вперёд. Руководств по монадам на Go предостаточно.


                      1. 0xd34df00d
                        15.07.2022 18:27
                        +1

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


                    1. siziyman
                      15.07.2022 15:40
                      +1

                      что вам не нравится в приведенном вам примере? Ошибка не проигнорирована. Она обработана

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


            1. nin-jin
              14.07.2022 18:33
              +2

              • Проверяемые компилятором исключения в Java.

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


              1. siziyman
                14.07.2022 18:34
                +2

                checked exceptions в джаве кстати как раз одно из спорных и непопулярных решений. Другой вопрос, что даже оно лучше, чем то, что наворотили в го.


                1. nin-jin
                  14.07.2022 18:37
                  -3

                  А что там спорного? Хомячкам говнокодить не даёт?


                  1. siziyman
                    14.07.2022 18:45
                    +7

                    try-catch-based логика отвратительно читается, хуже тестируется и вообще более error-prone в моих глазах, чем более "чистые" в смысле флоу кода механизмы возврата и обработки ошибок. А ещё есть очень много откровенно unrecoverable ситуаций.

                    Чуть более развёрнуто есть тут, например.


                    1. nin-jin
                      14.07.2022 19:18
                      -2

                      try-catch-based логика отвратительно читается

                      Не хуже чем if, switch, for и тд. Претензию тут можно предъявить разве что к тому, что во многих языках зачем-то сделали, что переменные, объявленные в try не доступны в catch.

                      хуже тестируется

                      Это о чём вообще?

                       более "чистые" в смысле флоу кода механизмы возврата и обработки ошибок.

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

                       А ещё есть очень много откровенно unrecoverable ситуаций.

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


                      1. 0xd34df00d
                        14.07.2022 19:25
                        +3

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

                        Что там плохо читается? do, и все.


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

                        Раст не является образцово дружественным к монадам языком.


                      1. nin-jin
                        14.07.2022 19:39
                        +1

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


                      1. 0xd34df00d
                        14.07.2022 19:54
                        +7

                        К массовому программисту вообще много что недружелюбно. Тяжело быть массовым программистом.


                      1. siziyman
                        14.07.2022 20:45
                        +5

                        У ифа, свитча, фора, и прочих куда более очевидная логика перехода/ветвления, чем у try-catch. У них это "проверь условие на входе - неверно - иди в другой блок [и проверь условие там, если надо]". У try-catch это "видишь вот этот блок и абсолютно всё, что в нём вызывается? В любой момент абсолютно что угодно из блока этого может сделать плохую магию, и ты перескочишь вот в один из тех других блоков" (кэтчей-то бывает несколько).

                        А ещё если у трая большое тело, контекст теряется только в путь.

                        Захотели потестировать? Убедитесь, что интересующий вас эксепшн в трай-блоке тестируемого кода кидает та самая строка, о которой вы думаете, а не другая на 10 выше/ниже/глубже, потому что иначе вы не знаете, что вы протестировали на самом деле.

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


                      1. nin-jin
                        14.07.2022 20:57
                        -1

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

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


                      1. siziyman
                        14.07.2022 21:07
                        +2

                        либо будет ожидаемый переход в catch

                        В какой момент кода и в каком состоянии системы он произойдёт? :)

                        Тестировать надо поведение, а не строки.

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


                      1. nin-jin
                        14.07.2022 21:20
                        +1

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

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


                      1. siziyman
                        14.07.2022 21:28

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


                      1. nin-jin
                        14.07.2022 22:39

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


                  1. Nbx
                    14.07.2022 20:56

                    Аргументацию можно в статье посмотреть Checked exceptions: Java’s biggest mistake.


                    1. nin-jin
                      14.07.2022 21:16
                      -3

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


                      1. Nbx
                        14.07.2022 21:21
                        +1

                        Практика критерий истины — сколько проектов использует checked exceptions так как они задумывались?


                      1. nin-jin
                        14.07.2022 22:44
                        -2

                        С демагогией - это не ко мне.


                  1. WraithOW
                    15.07.2022 00:33
                    +2

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

                    Давайте посмотрим на классику — интерфейс Readable из JDK

                    int read(CharBuffer cb)
                    throws IOException

                    Throws:
                    IOException — if an I/O error occurs
                    NullPointerException — if cb is null
                    ReadOnlyBufferException — if cb is a read only buffer


                    Заставляет ли джава обработать все ошибочные сценарии? Нет, ей наплевать на ReadOnlyBufferException. Заставит ли меня каждый вызов оборачивать в try/catch? Да, хотя вызывающему коду в 90% случаев вообще наплевать, что там сломалось — не смог прочитать и не смог, залоггировал и дальше поехали (при этом язык никак не мешает хомячкам бахать пустой catch и съедать исключения).

                    Если вам мало — можете заглянуть в класс Cipher. Там вообще красота

                    public final int doFinal(byte[] output,
                    int outputOffset)
                    throws IllegalBlockSizeException,
                    ShortBufferException,
                    BadPaddingException


                    Note: if any exception is thrown, this cipher object may need to be reset before it can be used again.

                    Throws:
                    IllegalStateException — if this cipher is in a wrong state (e.g., has not been initialized)
                    IllegalBlockSizeException — if this cipher is a block cipher, no padding has been requested (only in encryption mode), and the total input length of the data processed by this cipher is not a multiple of block size; or if this encryption algorithm is unable to process the input data provided.
                    ShortBufferException — if the given output buffer is too small to hold the result
                    BadPaddingException — if this cipher is in decryption mode, and (un)padding has been requested, but the decrypted data is not bounded by the appropriate padding bytes
                    AEADBadTagException — if this cipher is decrypting in an AEAD mode (such as GCM/CCM), and the received authentication tag does not match the calculated value


                    Три проверяемых исключения, которые в 90% случаев бесполезны, и еще 2, которые всё равно уронят весь код, если вы их не обработаете руками, и которые так же бесполезны.


                    1. nin-jin
                      15.07.2022 01:07
                      -1

                      Заставляет ли джава обработать все ошибочные сценарии? Нет

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

                      Заставит ли меня каждый вызов оборачивать в try/catch? Да

                      Не врите.

                      не смог прочитать и не смог, залоггировал и дальше поехали

                      if в данном случае ничем принципиально от try-catch не отличается.

                      Три проверяемых исключения, которые в 90% случаев бесполезны,

                      Их хорошо бы объединить в CipherExceotion.

                      и еще 2, которые всё равно уронят весь код

                      Ну так, лучше бы выпилили UnchekedException вообще.


                      1. WraithOW
                        16.07.2022 18:40
                        +1

                        Заставлять она и не должна.

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

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

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

                        Не врите.

                        NO U.

                        Ну так, лучше бы выпилили UnchekedException вообще.

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


                      1. nin-jin
                        16.07.2022 23:39
                        -1

                        Не пытается и не заставляет. Чего вы фантазируете?

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

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


                      1. WraithOW
                        17.07.2022 13:34
                        -1

                        Не пытается и не заставляет. Чего вы фантазируете?

                        class Scratch {
                            public static void main(String[] args) {
                                ByteArrayInputStream stream = new ByteArrayInputStream(new byte[] { 1 });
                                stream.close(); // unreported exception java.io.IOException; must be caught or declared to be thrown
                            }
                        }
                        

                        Или вы мне сейчас попытаетесь сказать, что ошибка компиляции — это «уведомить»?

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

                        Вы начинаете понимать суть проблемы.

                        Ага, круглые колёса — это плохо

                        В том и дело, что они не круглые, а полукруглые.


                      1. mayorovp
                        17.07.2022 13:56

                        Ну и где тут обёртка?


                        class Scratch {
                            public static void main(String[] args) throws IOException {
                                ByteArrayInputStream stream = new ByteArrayInputStream(new byte[] { 1 });
                                stream.close();
                            }
                        }


    1. AnthonyMikh
      15.07.2022 01:30
      +6

      Плохих языков не бывает

      Бывает, ещё как бывает. C — плохой язык. C++ — плохой язык. Go — плохой язык. 1С, прости г-пди — плохой язык.


      1. nikolas78
        15.07.2022 01:36
        +1

        А хорошие бывают?


        1. 0xd34df00d
          15.07.2022 01:50
          +14

          Нет. Бывают чуть менее плохие.


          1. nikolas78
            16.07.2022 18:43

            Странно…


        1. AnthonyMikh
          15.07.2022 02:02

          Солидарен с Дедфудом: хороших нету, есть лишь менее плохие.


      1. developer7
        15.07.2022 01:50

        Для контроллеров на чём писать? Если не С то что?


        1. nin-jin
          15.07.2022 01:56
          +1

          BetterC


        1. AnthonyMikh
          15.07.2022 02:01
          +1

          На Rust


          1. developer7
            15.07.2022 02:53

            Я имею ввиду 8 битники. AVR, PIC и прочее. Там чуть ли не на асме надо писать


            1. cepera_ang
              15.07.2022 03:12
              +1

              https://github.com/avr-rust — есть же что-то и под эту мелочь для Rust’a. C принципиальной точки зрения ничто не мешает писать на Расте и получать тот же код в бинаре, что и при написании на асме.


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


              1. 0xd34df00d
                15.07.2022 04:16
                +4

                А для микроконтроллера какие требования? Он же не будет торчать в открытый интернет

                О, держите оптимиста.


                1. cepera_ang
                  15.07.2022 04:30

                  Что и 8-битники в интернет пускают? А там поместится TCP-стек-то хотя бы? (расписался в собственном полном незнании темы, лол)


                  1. mikhanoid
                    15.07.2022 13:35

                    Есть uTCP. Туда вообще умельцы много чего помещают. Например, виртуальную lisp-машину с реализацией http-сервера поверх неё.


                  1. developer7
                    15.07.2022 16:11

                    Я когда то писал TCP/IP стек на С. Даже писал ещё ниже уровень PPP А только поверх него уже IP и далее TCP. Было очень давно, подробностей не помню, но кода получилось довольно мало. Это было во времена первых GPRS модемов. В жирный AVR уместилось бы. Конечно вероятно не все ситуации код мог переварить, но минимальный рабочий вариант получился. Там не так страшно — пришедший пакет упакован как матрёшка из данных. Просто надо найти адреса последовательно где какой протокол начинается и добраться до данных. Сами пакеты TCP/IP примитивны и просты.


                    1. cepera_ang
                      15.07.2022 17:29
                      +1

                      Круто!


                      Я ж не говорю, что это невозможно, мне просто интересно — делают ли так на самом деле :) Ну и что там на таком МК ещё поместится, если он будет в сеть торчать и что-то обрабатывать? То есть одно дело, когда у тебя сложная система, что-то там из сети прилетает, что может поломать и использовать во зло и таких примеров просто бесконечность. А другое дело, самый мелкий МК с прошивкой в пять тысяч строк и даже торчащий в интернет — ну даже сломали его, и? Лампочкой помигают за автора? :)


                      А уже на какой-нибудь ESP32 Rust вполне как дома.


                      1. developer7
                        15.07.2022 19:42

                        Ну контроллеры ставят во всякие железячные устройства. Лампочкой поморгать или ещё чего. Или наоборот — отослать сигнал. Там и требуется только например по GPRS отослать на какой нибудь IP булеву переменную, что у тебя например огурцы на даче поливать надо ))) Хотя сейчас например даже в самом захудалом GSM модеме свой TCP стек.

                        Если контроллер только для передачи сигнала через net — то там нечего ломать. А если на приём. То я не сильно представляю где голый контроллер может в сеть смотреть. Это либо всякие свичи и модемы для оптики или ещё что. У всего этого как правило есть свои настраиваемые фаерволы или криптотунели.

                        P.S. Сначала написал комент про лампочку, а потом прочитал ваш ))) Короче все думают про лампочку ))) А Выбор AVR или там STM32 — только в цене по мойму. Берут что подешевле. Хотя STM раньше стоил дешевле AVR — что меня очень удивляло. Сейчас не знаю как.


              1. edo1h
                15.07.2022 12:53
                +2

                Он же не будет торчать в открытый интернет

                зато всякие неожиданные значения на входах — обычное дело


    1. domix32
      15.07.2022 09:55
      +1

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


  1. xcono
    14.07.2022 16:58
    +13

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

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


  1. Devakant
    14.07.2022 17:09

    кто всем сердцем соглашаются с моей филиппикой

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



  1. KGeist
    14.07.2022 17:28
    +3

    В Go нет тип-сумм — и поэтому там реально неудобно написать тип, который представлял бы «либо адрес IPv4, либо адрес IPv6

    В большинстве случаев такое спокойно решается через type switch. Но тут, думаю, нужно изначально проектировать по-иному — напр. работать не с конкретными типами, а с интерфейсами, и тогда без разницы что под капотом — ipv4, ipv6 или номер квартиры.


    нo не допускает перегрузки операторов, напоминая о той давней истории Java, когда a == b не было идентично a.equals(b)

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


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

    По старинке — обернуть в read-only интерфейсы. Вообще мне больше импонирует идея view-интерфейсов, т.к. они более гибкие, чем какой-то один прибитый гвоздями механизм на уровне языка.


    В целом я бы сказал, что для 90% случаев существующие примитивы — good enough. В 10% случаев нужны танцы с бубном. В каких-то языках из-за перфекционизма танцы с бубном будут больше 10%, зато всё теоретически красиво. Всё-таки, Go замышлялся как простой язык.


    1. siziyman
      14.07.2022 18:25
      +13

      Всё-таки, Go замышлялся как простой язык.

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


      1. Sin2x
        14.07.2022 18:52
        -6

        Первый же пример абсолютно нелеп и притянут за уши -- Го серверный язык и работа с файловыми атрибутами на винде ему нужна как собаке пятая нога. И что мы видим как контрпример? Естественно, раст! Опять же, без комментариев. Само собой, это просто объективная критика Го, а никакая не попытка пропихнуть Раст. Да, всё так.


        1. siziyman
          14.07.2022 19:05
          +7

          Го серверный язык и работа с файловыми атрибутами на винде ему нужна как собаке пятая нога.

          • Тогда можно а) не поддерживать Windows б) не поддерживать соответствующие файловые системы

          • "Го серверный язык" где написано? На оф.сайте го не вижу ни слова о том, что на винде его запускать нельзя или не нужно (более того, я сам в продакшн код на го из-под винды писал).

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


          1. Sin2x
            14.07.2022 19:12
            +2

            Я прочитал первую статью ещё когда она вышла, а вторая только укрепила моё мнение относительно автора и его мотиваций. Заглянул тут ещё ради смеха на ютуб канал автора -- раст, раст, раст. Один сплошной раст. Для меня всё очевидно как божий день. Но если кто-то верит в то, что автор просто вдруг на ровном месте решил pro bono покритиковать Го, это его дело.


            1. Gordon01
              14.07.2022 19:32

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


              1. Sin2x
                14.07.2022 19:34
                +1

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


                1. nin-jin
                  14.07.2022 19:44
                  +1

                  1. Sin2x
                    14.07.2022 19:47
                    -3

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


                    1. siziyman
                      14.07.2022 20:36
                      +1

                      Специфическое отношение у кого? У вас лично?

                      Нигде никакого массового "специфического отношения" к расту я не видел.


                      1. Sin2x
                        14.07.2022 20:40

                        А я вижу везде -- на хабре, опеннете, ЛОРе, твиттере, реддите, хакерньюс, you name it. Далеко ходить не надо: https://www.google.com/search?q=why+people+hate+rust


                      1. siziyman
                        14.07.2022 20:50
                        +4

                        Далеко ходить не надо: https://www.google.com/search?q=why+people+hate+rust

                        А теперь подставьте туда java, javascript, php, python и go (golang к сожалению недостаточно распространённое название - а зря).

                        Вы-таки не поверите, но побеждают JS и PHP - а технически как раз go, но там слово очень уж неудачное - а у Раста выдача, подозреваю, чуть больше, чем у той же джавы, просто потому, что Rust - это ещё и название сравнительно популярной компьютерной игры.


                      1. Sin2x
                        14.07.2022 20:59
                        -2

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


                      1. siziyman
                        14.07.2022 21:10
                        +5

                        При чём тут гугл? 

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

                        Эта ссылка была просто для примера

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

                        И даже эта статья, которая вроде бы должна была быть о Го, превратилась в срач о расте.

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


              1. cepera_ang
                14.07.2022 19:51
                +5

                Конкретно на хабре есть несколько шумных нелюбителей, для которых любое сравнение это «пытаются впарить свой сраный %подставитьязык%». А так нормально всё.


            1. siziyman
              14.07.2022 20:41
              +6

              если кто-то верит в то, что автор просто вдруг на ровном месте решил pro bono покритиковать Го

              Не "на ровном месте", а (как написано в статьях) потому что он активно на нём писал - в том числе на работе - и пытался с ним "подружиться".

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

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

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


          1. onlinehead
            14.07.2022 20:07
            +2

            Ну вот про файлы, chmod и Windows это прям... не уникальная проблема.

            Вот к примеру боль автора питоновского модуля oschmod:

            Even though Python's os.chmod() sets read, write, and execute file permissions, on Windows, os.chmod() basically has no effect. Even worse, Python on Windows gives no warnings or errors. If you think you set file permissions on Windows with os.chmod(), you're wrong!

            Ну то есть буквально в Go скопировали поведение Python.

            Хорошо ли это? Нет, могли бы и нормально сделать.

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

            Стоило ли из-за этого "не поддерживать Windows"? Нет. По крайней мере ровно в той степени, в которой тогда надо "не поддерживать Windows" в Python. Остальное то (наверное) работает. Nice небось тоже на Windows кривой почти везде и молча делает ничего, но ничего, пока никто не расстроился.


            1. siziyman
              14.07.2022 20:34
              +1

              Ну да, я не питонист.

              Хорошо ли это? Нет, могли бы и нормально сделать.

              Ага, всё так.

              Можно ли это понять? Да, можно

              Нет, не можно, когда вы делаете строго типизированный язык (я тут могу много материться по поводу interface {}, но язык всё-таки строго типизированный) в конце нулевых, когда, помимо другого подхода к типизации, мир и концепции дизайна ЯП несколько отличаются от тех, в реалиях которых Гвидо дизайнил Пайтон или даже тех, в которых он довыпускал Python 2.2, в котором появился chmod.


              1. onlinehead
                14.07.2022 22:16

                Нет, не можно, когда вы делаете строго типизированный язык

                Так а причем тут строго типизированный язык, если я говорю об одном конкретном наезде про chmod?

                Наговнокодить в кросс-платформенной реализации чего либо достаточно просто. Особенно если эта платформа не является целевой. В целом странно ожидать, что chmod будет работать в windows, где в принципе нет битовой маски свойств, правда? Но наверно ошибочку таки стоило бы писать.


                1. mayorovp
                  14.07.2022 22:37
                  +2

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


                  Если бы пакет, предоставляющий Chmod, назывался бы не "os", а "os.unix" или "os.linux" — претензий бы к нему было меньше.


                  1. onlinehead
                    14.07.2022 22:50
                    -1

                    Если не лениться читать, то в описании пакета os в Go написано следующее:

                    Package os provides a platform-independent interface to operating system functionality. The design is Unix-like, although the error handling is Go-like; failing calls return values of type error rather than error numbers. Often, more information is available within the error. For example, if a call that takes a file name fails, such as Open or Stat, the error will include the failing file name when printed and will be of type *PathError, which may be unpacked for more information.

                    The os interface is intended to be uniform across all operating systems. Features not generally available appear in the system-specific package syscall.


                    1. AnthonyMikh
                      15.07.2022 01:45
                      +4

                      The os interface is intended to be uniform across all operating systems. Features not generally available appear in the system-specific package syscall.

                      Установка прав доступа через битовую маску — это и есть та самая "feature not generally available", но в os она таки почему-то есть.


                  1. KGeist
                    15.07.2022 14:02
                    -1

                    Тут дилемма — если наваять most common denominator, т.е. только те фичи, которые есть во всех OS, то API работы с окружением будет ограничено в фичах, от этого страдала Java, например. Другой вариант вообще не делать общего API, но тогда из коробки вообще ничего нет. Выбор Unix-поведения как дефолтного считаю на практике обоснованным, т.к. целевая аудитория Go это всё-таки Unix-подобные системы, которых большинство, и Windows тут скорее исключение, чем правило. Такова реальность — в итоге в самом Windows добавили WSL, posix compatibility layer; инструменты разработчика портируются с Linux на Windows, и не наоборот.


                    1. mayorovp
                      15.07.2022 15:13
                      +1

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


      1. KGeist
        15.07.2022 14:35
        +3

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


        Тут, думаю, нужно впервую очередь смотреть на практику. В целом, на Go довольно просто писать код. Но доказать, что код корректный, сложнее, чем, например, в Rust. И тут мы упираемся в то, что по большому счёту все холивары основываются на субъективных ощущениях, интуиции. Очень мало у нас опираются на исследования и метрики по поводу того, как та или иная фича влияет на разработку. А иначе мы просто топчемся на месте. Недавно открыл для себя термин evidence-based software engineering, по нему есть литература, напр. одноимённая книга Дерека Джонса.


        1. siziyman
          15.07.2022 15:14
          +1

          В целом, на Go довольно просто писать код.

          Ну вот в том и дело, что автор статьи (как и я) писал на Го код профессионально довольно продолжительное время, и пришёл к совсем другим выводам. Я с автором в этом согласен.


        1. cepera_ang
          15.07.2022 17:33

          Погуглите ещё формальные методы и automated reasoning tools. И вот семантика раста и сложившееся вокруг него коммьюнити оказались весьма подходящими для того, чтобы такие тулзы делать. Убойный набор — язык, который проверяет множество инвариантов + мощное тестирование (property based testing и прочий fuzzing) + формальная верификация = безбажный софт.


  1. Dgolubetd
    14.07.2022 18:29
    +6

    Только в Марте этого года (а ему сколько уже, 12 лет?) в Go добавили generics и этим все сказано.


    1. mapron
      14.07.2022 19:13
      +7

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


      1. nin-jin
        14.07.2022 19:22
        -4

        1. mapron
          14.07.2022 19:23
          +3

          Эм? я знаю что такое generics, вопрос не в этом. что «этим всё сказано».


          1. nin-jin
            14.07.2022 19:28
            -3

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


            1. mapron
              14.07.2022 19:30
              +3

              Нет, не знаю. Просвятите? Вы и правда считаете, что я от нечего делать спрашиваю о том, что знаю сам? Смысл какой?


              1. nin-jin
                14.07.2022 19:52
                -11

                То есть вы не знаете, что такое обобщённое программирование. Узнать о нём вы можете по ссылке выше.


                1. mapron
                  14.07.2022 19:56
                  +11

                  Мы чет по кругу ходим. Можете придерживаться нейтрального тона?

                  Давайте сначала. Я C++ разработчик. GP я вполне себе на каком-то уровне уменю в этом языке.
                  Я читал новость о том что в Go добавили generic-и, выглядит как что-то (на совсем поверхностный взгляд незнакомого с Go) позволяющее работать в GP парадигме. Насколько это соответствует мощи шаблонов С++ — не берусь сказать. Возможно, не соответствует. В любом случае что
                  а) в Go все нормально сейчас с GP
                  б) или в Go добавили generics но их сильно мало
                  я все еще не понимаю, как эта информация что их уже добавили в этом году соотносится с «этим все сказано», с какой частью статьи это коррелирует.

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


                  1. nin-jin
                    14.07.2022 20:03
                    -18

                    Ок, следующая подсказка: https://github.com/search?q=language%3AGo&type=code


                  1. Source
                    15.07.2022 02:19
                    +2

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


                    1. KGeist
                      15.07.2022 13:11
                      +3

                      Это миф про то, что "принципиально" не хотели. Если поискать через wayback machine, то официальный faq уже в 2013 году (раньше не нашёл) писал о том, что они открыты к добавлению дженериков, но пока нет понимания, как лучше реализовать.


                      1. Source
                        15.07.2022 13:25
                        +1

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


                      1. KGeist
                        15.07.2022 13:50
                        +2

                        Авторы создали Go, потому что устали ждать долгой компиляции проектов на C++ в проектах Google. Изначальная идея Go была в том, чтобы это был простой good enough язык, который легко масштабируется на большие кодовые базы at scale и при этом быстро компилируется. По сути основные первоначальные решения отталкивались именно от этого — быстрая компиляция больших проектов (что иронично, когда сейчас один из основных use case'ов Go это микросервисы). Отсюда запрещены циклические зависимости, поэтому в язык добавлен structural typing, поэтому нет наследования, поэтому местами синтаксис немного странный — для быстрого парсинга, и т.д. Дженерики, шаблоны — они значительно могут замедлить время компиляции и сильно раздуть код (code bloat), если их неправильно приготовить. Поэтому много времени ушло на то, чтобы найти правильный баланс, т.к. авторы, видимо, были травмированы опытом в C++. Go часто по фичам сравнивают с Rust, но там вроде время компиляции не возведено в абсолют, и я слышал истории, что в Rust со скоростью работы компилятора не так всё гладко. То, что авторы Go в рантайме в итоге реализовали для оптимизации компилятора, похоже на generic code sharing при реификации дженериков в C#, которые там давно есть. Странно, что так долго к этому приходили, возможно были трудно решимые проблемы с семантикой/синтаксисом, чтобы было backward compatible. Т.е. тут основной косяк авторов в том, что первоначальный драфт языка не проектировался с учётом расширения его под дженерики, напр. теперь map[int]int смотрится странно.


                      1. mikhanoid
                        15.07.2022 13:59
                        +1

                        Мне, конечно, до авторов Go далеко, но, вот, всё же, зря они пошли на поводу у сообщества. Добавили бы лучше generic functions. И синтаксис такой бы вписался бы лучше в язык, и по выразительности они достаточны, и по производительности хуже не были бы, учитывая текущую реализацию generic-ов.


                      1. KGeist
                        15.07.2022 14:49

                        Всё-таки основной use case дженериков это обобщённые контейнеры. Из-за этого по факту в Go всего два типа контейнеров — слайсы и мапы, что далеко от идеала. Как наличие только generic-функций решило бы этот вопрос?


                      1. nin-jin
                        15.07.2022 14:45
                        +2

                        С++ компилируется долго из-за кривого дизайна, унаследованного от C. Go корректней сравнивать с D, который и компилируется быстро, и дженерики были сразу, а не через 12 лет. И много чего ещё умеет, чего не умеет Go.


                      1. KGeist
                        15.07.2022 14:55
                        +2

                        Многие хвалят D, но остаётся подвисшим вопрос — почему он не взлетел, если он настолько хорош? Был аргумент, что за ним не стояла большая корпорация, но за последнее время появилось несколько языков вроде Zig, к которым сейчас, субъективно, больше интереса, чем к D. Дело ещё не в языке, а в тулинге например. Может быть, с тулингом что-то не так? В Go много хорошего, что есть из коробки, не касается языка как такового.


                      1. nin-jin
                        15.07.2022 15:25

                        почему он не взлетел, если он настолько хорош?

                        • Если за холмом трава зеленее, то почему все прыгают с обрыва?

                        • Ну все туда бегут и я побежал.

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

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


                      1. Sin2x
                        15.07.2022 15:04
                        +1

                        Я бы не сказал, что чистый Си компилируется медленно. Полчаса для проекта размера ядра Линукс это немного. Плюсы это другой разговор. Так что аргумент про кривой дизайн требует как минимум раскрытия.



                      1. Sin2x
                        15.07.2022 17:46

                        Это не кривой. Просто в D лучше, спору нет.


                      1. nin-jin
                        15.07.2022 20:07
                        -1

                        Заново парсить файл в каждом месте его включения - не криво? А что же тогда криво?


                      1. Source
                        15.07.2022 15:36
                        +2

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


                      1. eyudkin
                        15.07.2022 15:21

                        Это неправда.

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

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

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

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

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


                      1. siziyman
                        15.07.2022 15:35
                        +1

                        Дженерики как в джаве сильно нагружают гц

                        Чем, пардон, джавовые дженерики нагружают ГЦ больше, чем любые другие?

                        лишают вас возможности нормального дебага в рантайме

                        Во-первых можно делать их reified (хотя кмк это поощряет некоторые сомнительные практики в разработке, но не суть), во-вторых, и с type erasure всё в рантайме прекрасно дебажится.

                        Дженерики как в плюсах замедляют время компиляции

                        Ну вот только в плюсах не дженерики, угу. Шаблоны - несколько не то же самое.


                      1. mayorovp
                        15.07.2022 18:06

                        Чем, пардон, джавовые дженерики нагружают ГЦ больше, чем любые другие?

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


                      1. nin-jin
                        15.07.2022 15:50
                        +2

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


                      1. mikhanoid
                        15.07.2022 21:19

                        Не факт. Вы не учитываете усложнение алгоритма вывода типов. БОльшая часть правил вывода в том же Haskell, процентов 90, - она про ограничения и generic-и (конструкторы типов) как раз. А работает проверка и вывод типов всегда. И там сложность, минимум, квадратичная.


                      1. nin-jin
                        15.07.2022 21:31
                        -1

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


                      1. mikhanoid
                        15.07.2022 21:41

                        Так необходимо вывести instance.


                      1. nin-jin
                        15.07.2022 21:52

                        Или указать явно. Это ортогональные вещи.


                      1. mikhanoid
                        15.07.2022 21:57

                        Так явное указание требует вывода и проверки ограничений, всё равно.


                      1. nin-jin
                        15.07.2022 22:28
                        -1

                        Сверка типов - тривиальная операция. Вывод тут никакой не нужен.


                      1. 0xd34df00d
                        15.07.2022 22:16

                        Вывод типов в haskell98 очень простой и тупой. Сложно (неразрешимо сложно) выводить типы, когда у вас есть всякие type families, GADT'ы и прочее.


      1. lebedec
        14.07.2022 20:05
        +16

        Обобщение в широком смысле слова — это ключевая аналитическая задача программиста в процессе разработки решения и моделирования предметной области.   

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

        Кроме технической составляющей, я бы еще отметил, что адепты Go все эти 12 лет себя и окружающих фанатично убеждали что дженерики не нужны "by design". Однако, реальная практика всё же вынудила признать некомпетентность изначальных идей.    

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

        Ваш капитан очевидность. 


        1. mapron
          14.07.2022 20:19
          +7

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

          Ваш капитан очевидность.

          Ну спасибо что хоть кто-то уделил минутку внимания чтобы объяснить что там сказано)

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

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

          Я прочитал предложение как "… статья конечно хороша, но вот только в Go уже есть дженерики с марта"
          а по факту коммент был похоже
          «плюсую статье, все по делу. одно лишь факт (»только") что в марте ЭТОГО года добавили..." далее по тексту.
          Возможно из-за этого и был тупняк.

          Всем извините, можете минусить мой тупизм дальше)


          1. evocatus
            15.07.2022 01:37
            +6

            Дело не просто в том, что не было дженериков, а в том, что было: статическая строгая типизация. Сразу понятно к чему это приводило - когда реализации одного и того же метода интерфейса для разных типов приходилось писать вручную, есть целые библиотеки с кучей функций типа AddIntInt, AddInt32Int32, AddUint32Uint32 и т.д. И кодогенерация, как в "старых добрых" 60-х. Хотя уже тогда были языки с динамической типизацией вроде разных LISP, а Smalltalk появился в 1972. А Go притворяется, что сейчас 70-е. Это такой Паскаль с CSP. Со всеми вытекающими.


            1. mapron
              15.07.2022 01:38

              Как программисту на С++ мне это слушать как страшную сказку приходится) Сочувствую Go-разработчикам. Не, строгость это хорошо. Это одобряю. Но вот этот вот AddUint32Uint32 ужасно же.


            1. AnthonyMikh
              15.07.2022 01:47
              +3

              Можно ещё вспомнить классику.


          1. 4reddy
            15.07.2022 15:05
            +1

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

            * За тупизм извиняем.


        1. mikhanoid
          15.07.2022 08:51

          Вот Вы говорите "наиболее популярный и эффективный". А на какой статистике Вы основываете это утверждение?


          1. lebedec
            15.07.2022 10:15

            Надеюсь, вы этот вопрос написали истины для, а не потроллить. 

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

            Возьмем индекс TIOBE и посчитаем популярность языков: 

            Python + Java + C# + Visual Basic + Swift + PHP = 38%
            C + JavaScript + ASM + SQL + Go + C++ = 29%

            Чисто формально по этим цифрам дженирики наиболее популярный способ даже против суммы всех "не дженериков", а если сравнивать по отдельности, вывод будет еще основательнее.


            1. mikhanoid
              15.07.2022 11:08
              +1

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


    1. Gordon01
      14.07.2022 19:23
      +3

      Ну как добавили... как и почти все остальное в го они half-baked:

      type Integer interface {

      ~int | ~int8 | ~int16 | ~int32 | ~int64

      }

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

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


      1. KGeist
        15.07.2022 13:26

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

        Я давно слежу за разработкой go и это совсем не то, впечатление, которое я получил. Как минимум, каждый год проводится survey для понимания приоритетов сообщества, я участвую в каждом. Отсутствие дженериков было обозначено как проблема номер один. Любой желающий может предложить proposal. Проблема в том, что большинство proposals ещё более half-baked, чем то, что предлагает ядро разработчиков из Гугла. В стиле "я видел фичу Х в другом языке, хочу так же". Детали не проработаны, backward compatibility не проработано, и т.д.


  1. varanio
    14.07.2022 18:58

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

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


    1. siziyman
      14.07.2022 19:06
      +9

      А зачем писать комментарии, если получается написать только "Не нравится - не ешь"? :)

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


    1. lebedec
      14.07.2022 19:11
      +7

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

      (с) Ф. Кривин

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


      1. ReadOnlySadUser
        14.07.2022 20:08

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

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


        1. siziyman
          14.07.2022 20:38

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

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


        1. lebedec
          14.07.2022 21:28
          +2

          Понимаю, о чем вы говорите. Несовершенство информационных технологий часто увеличивает видимость ложных ценностей и оставляет в тени реальные достижения. 

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

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

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


          1. mikhanoid
            15.07.2022 14:33
            -1

            Да бросьте. Медийное давление, создаваемое Rust-сообществом просто беспрецедентно. С Go даже близко такого нет. Даже с Haskell в своё время такого не было. Куда ни глянь - везде только Rust и обсуждают. Ну, или другие языки в контексте того, насколько они хуже Rust. В каналах языковых телеграмма тоже сплошной Rust. Фанаты крайне активны.


            1. siziyman
              15.07.2022 15:24
              +1

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


              1. mikhanoid
                15.07.2022 21:27

                Ну... Социальные пузыри у всех разные. К сожалению. Я живу в каналах дизайна ЯП и компиляторов. А что, в Вашем пузыре реально пиарят Go изо всех сил?


                1. siziyman
                  15.07.2022 21:31
                  +1

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

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


                  1. mikhanoid
                    15.07.2022 21:54

                    Не, его часто вспоминают словами о том, какое же это Го..., а вот Rust - золото. Совершенно, кстати, не понятно, чего Rust-овцы недолюбливают так сильно именно Go. Типа, одна из граней противостояния Google и Mozilla, начавшегося с браузеров?


                    1. siziyman
                      15.07.2022 21:59

                      Давайте вы не будете мне рассказывать, какие я читаю отзывы о Го, ладно? :)

                      Нет, я не вижу никаких сколько-то регулярных выкриков "го - какашка, вперёд в раст".

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


                      1. mikhanoid
                        15.07.2022 22:11

                        Так я же про упоминание Go в тех каналах, которые я читаю.


      1. varanio
        15.07.2022 15:39

        поясню. Дело в том, что абсолютное большинство гошников, которых я знаю , перешли на го с другого языка. И я в том числе. Поэтому мы прекрасно видим и недостатки и достоинства языка. Любой кто писал на го - и так знает, где ему что мешает по сравнению с языком X. И стоят ли эти недостатки того, чтобы с ними мириться или нет. Статья пытается убедить непойми в чём, короче.


    1. AnthonyMikh
      15.07.2022 01:53
      +3

      … или Расте (чудовищный порог входа)

      А вот не факт. Не, с тем, что у Go порог входа ниже, я спорить не буду. Но я вот недавно читал статью, где авторы, на минуточку, весь проект в какой-то момент переписали с C++ на Rust — и там есть, в частности, такое:


      Rust can be challenging for beginners. But our interns proved otherwise. They picked up Rust within one or two weeks — even with no prior Rust/C++ expertise <...>

      Это, конечно, anecdotical evidence, но всё же один из доводов в поддержку моей точки зрения, что слухи о сложности Rust несколько преувеличены.


      1. Source
        15.07.2022 02:31
        +3

        Да люди просто насмотрятся как на Rust выглядят interop c С-либами, и потом боятся, что там весь код так выглядит. По факту Rust уж точно проще C++, который многие из нас ещё в универе изучали и ничего.


    1. Source
      15.07.2022 02:27
      -1

      Сейчас есть определенный хайп вокруг Python и Go. И многие новички по факту начинают изучать эти языки в результате маркетингового обмана. Так что говорить о них правду вполне может быть полезно для IT-сообщества в целом.

      Потому что, чтобы понять насколько плох тот или иной ЯП, надо для начала хотя бы 5 разных языков изучить, а лучше 10)


    1. 4reddy
      15.07.2022 15:30

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

      Все вышесказанное относится и ко мне, если что :)


  1. mentalclear
    14.07.2022 21:49
    -4

    Я 7 месяцев работю тестером в достаточно большой американской комании где большая часть Back End сделанна на Go + gRPC. Я не слышу воплей девлоперов (у меня в команде их 5) что они не могут делать свою работу потмоу, что выбор языка кривой, и надо было выбрать чтото другое. Их когда нанимали, им говорили начем все написано, не хотели бы выбрали другую работу. Что за проблема? Ну не нравится тебе язык этот... не пиши на нем, не нравится что на работе на нем пишут - поменяй работу. Столько времени человек убил чтобы написать это все... такой дешевый заход на попытку привлечь к себе тонну внимания и развести срач... детский сад.


  1. miga
    14.07.2022 22:20
    +5

    Автор совсем, критически не понимает, зачем нужен голанг.

    4 года назад я пришел в большую контору (Убер, если конкретно) писать на голанге, при том что до этого я в основном занимался питоном, а все мои знания голанга ограничивались пройденным tour.golang.org (спойлер: этого достаточно). Так вот, через неделю я отрелизил первую версию библиотеки, которой с минимальными изменениями продолжает пользоваться весь убер.

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

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

    А так-то конечно да, гошный стдлиб - срамота, все потуги с управлением зависимостями до появления модулей (помните были такие glide и dep?) - это вообще откровенная диверсия - много, много всего очень плохо. Но просто и не стояло задачи написать идеальный язык :)

     Кстати, наброшу - с обработкой ошибок начиная с 1.13 все более-менее нормально :)


    1. cepera_ang
      14.07.2022 22:37
      +11

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


      1. miga
        14.07.2022 22:47
        +2

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

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


        1. AnthonyMikh
          15.07.2022 01:58
          +1

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

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


          1. mikhanoid
            15.07.2022 09:24
            +1

            Если это однократное вложение затягивается на годы, как с Haskell, например, в силу особенностей экосистемы, то стоит ли оно того? Rust или C++ тоже простыми языками не назовёшь. Кроме того, важна метрика: время до запуска бажного MVP. Потому что баги бывают не только в коде, типах и указателях, но и в самой идее, в организации интерфейса, etc.

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

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


            1. nin-jin
              15.07.2022 09:31

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


              1. mikhanoid
                15.07.2022 13:31
                +1

                Зачем гоферу сутки изобретать велосипед? Чай не во времена телетайпов живём. Взял готовую реализацию, подправил в ней что-то под себя, и вперёд. Ну, не 5 минут займёт, а 15. Зато потом можно будет алгоритм под свои задачи подстраивать, параметризовать каким хитрым образом. У generic-библиотек существенный недостаток: железобетонный интерфейс, который не так часто достаточен, как хотелось бы. Приходится изловчаться разными методами. Просто сложность в другое место переезжает, вот и всё.

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


                1. nin-jin
                  15.07.2022 14:33

                  Отладка, тестирование, документирование, ревью, поддержка - всё это тоже включено в 15 минут?

                  После С++ любой язык будет как глоток свежего воздуха. Вовсе не обязательно из одной крайности впадать в другую.

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

                  Один только звездец с сортировками чего стоит:

                  Hidden text
                  // A Change is a record of source code changes, recording user, language, and delta size.
                  type Change struct {
                  	user     string
                  	language string
                  	lines    int
                  }
                  
                  type lessFunc func(p1, p2 *Change) bool
                  
                  // multiSorter implements the Sort interface, sorting the changes within.
                  type multiSorter struct {
                  	changes []Change
                  	less    []lessFunc
                  }
                  
                  // Sort sorts the argument slice according to the less functions passed to OrderedBy.
                  func (ms *multiSorter) Sort(changes []Change) {
                  	ms.changes = changes
                  	sort.Sort(ms)
                  }
                  
                  // OrderedBy returns a Sorter that sorts using the less functions, in order.
                  // Call its Sort method to sort the data.
                  func OrderedBy(less ...lessFunc) *multiSorter {
                  	return &multiSorter{
                  		less: less,
                  	}
                  }
                  
                  // Len is part of sort.Interface.
                  func (ms *multiSorter) Len() int {
                  	return len(ms.changes)
                  }
                  
                  // Swap is part of sort.Interface.
                  func (ms *multiSorter) Swap(i, j int) {
                  	ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]
                  }
                  
                  // Less is part of sort.Interface. It is implemented by looping along the
                  // less functions until it finds a comparison that discriminates between
                  // the two items (one is less than the other). Note that it can call the
                  // less functions twice per call. We could change the functions to return
                  // -1, 0, 1 and reduce the number of calls for greater efficiency: an
                  // exercise for the reader.
                  func (ms *multiSorter) Less(i, j int) bool {
                  	p, q := &ms.changes[i], &ms.changes[j]
                  	// Try all but the last comparison.
                  	var k int
                  	for k = 0; k < len(ms.less)-1; k++ {
                  		less := ms.less[k]
                  		switch {
                  		case less(p, q):
                  			// p < q, so we have a decision.
                  			return true
                  		case less(q, p):
                  			// p > q, so we have a decision.
                  			return false
                  		}
                  		// p == q; try the next comparison.
                  	}
                  	// All comparisons to here said "equal", so just return whatever
                  	// the final comparison reports.
                  	return ms.less[k](p, q)
                  }
                  
                  var changes = []Change{
                  	{"gri", "Go", 100},
                  	{"ken", "C", 150},
                  	{"glenda", "Go", 200},
                  	{"rsc", "Go", 200},
                  	{"r", "Go", 100},
                  	{"ken", "Go", 200},
                  	{"dmr", "C", 100},
                  	{"r", "C", 150},
                  	{"gri", "Smalltalk", 80},
                  }
                  
                  // ExampleMultiKeys demonstrates a technique for sorting a struct type using different
                  // sets of multiple fields in the comparison. We chain together "Less" functions, each of
                  // which compares a single field.
                  func main() {
                  	// Closures that order the Change structure.
                  	user := func(c1, c2 *Change) bool {
                  		return c1.user < c2.user
                  	}
                  	increasingLines := func(c1, c2 *Change) bool {
                  		return c1.lines < c2.lines
                  	}
                  	decreasingLines := func(c1, c2 *Change) bool {
                  		return c1.lines > c2.lines // Note: > orders downwards.
                  	}
                  
                  	OrderedBy(user, increasingLines).Sort(changes)
                  	fmt.Println("By user,<lines:", changes)
                  
                  	OrderedBy(user, decreasingLines).Sort(changes)
                  	fmt.Println("By user,>lines:", changes)
                  }

                  В нормальных языках это делается гораздо проще:

                  struct Change {
                  	string user;
                  	string language;
                  	int lines;
                  }
                  
                  Change[] changes = [
                  	{"gri", "Go", 100},
                  	{"ken", "C", 150},
                  	{"glenda", "Go", 200},
                  	{"rsc", "Go", 200},
                  	{"r", "Go", 100},
                  	{"ken", "Go", 200},
                  	{"dmr", "C", 100},
                  	{"r", "C", 150},
                  	{"gri", "Smalltalk", 80},
                  ];
                  
                  void main()
                  {
                      
                  	changes.multiSort!( q{ a.user < b.user }, q{ a.lines < b.lines } );
                  	writeln( "By user,<lines:", changes );
                  
                  	changes.multiSort!( q{ a.user < b.user }, q{ a.lines > b.lines } );
                  	writeln( "By user,>lines:", changes );
                  
                  }


                  1. mikhanoid
                    15.07.2022 14:42

                    Я не шибко великий специалист по Go, но мне кажется, реализация там чрезмерно усложнённая. Я бы проще написал.


                    1. nin-jin
                      15.07.2022 15:04

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


                      1. mikhanoid
                        15.07.2022 20:49

                        А какие ограничения решение должно учитывать? Самое простое - сделать две разные реализации интрфейса "под задачи", а чтобы не писать каждый раз длинные if-then-else в реализациях Less для сравнений по ключам сделать функцию-композиции сравнений.


                  1. KGeist
                    15.07.2022 15:12

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


                    1. nin-jin
                      15.07.2022 15:27
                      +1

                      Сортировка - это один из тысяч алгоритмов. Для Го теперь надо писать свой аналог STL. Но на примере C++ мы видим к чему всё это приводит, если язык изначально не планировался для мета программирования.


          1. khabib
            15.07.2022 10:31
            +1

            Это в каких языках нету подводных камней?


      1. Myateznik
        14.07.2022 23:50
        +7

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

        Т.е. ровно так же можно про любой язык говорить да и в целом про библиотеку/инструмент/подход/идею/etc. Хоть про Rust из разряда у вас не Servo, не блокчейн/etс и вообще не экспериментируйте, вон есть C. Зачем вам TypeScript, вы не Microsoft. Не используйте React, вы не Facebook. У вас JavaScript, ой ну его нафиг прототипное наследование... К чему придраться и на чём сделать упор подобной критики всегда найдётся.

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

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

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

        Касаемо различных технологий из Google, которыми многие пользуются и от которых достаточно много пытаются отговаривать (а это именно так) тоже отдельно хочется сказать. Неужели ни кто, посмотрев на Starlark/Bazel/Protocol Buffers/FlatBuffers/Android/Fuchsia/Kubernetes/gRPC/etc до сих пор не понял, что подход Google это максимальная автоматизация и куча codegen...

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

        Но сам факт генерации кода пусть и не полный тот же GitHub Copilot (нравится или нет) или IntelliSense/IntelliCode могут достаточно сильно ускорить процесс написания кода, а следовательно и решения задач автоматизации, что является двигателем прогресса по крайней мере в IT. Причём кодо-генерация в целом может удешевлять будущие разработки: напиши один раз универсальный генератор для того же распространённого CRUD и экономь время и деньги на создание однотипных конструкций на языке ANY_LANG_PLACEHOLDER (естественно до первой встречи со специфичным использованием/применением).

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

        А так получилась статья из разряда Little-endian vs Big-Endian, Binary vs Ternary (уже Quad, привет квантовые компьютеры), A vs B, etc. Как говорится вам шашечки или ехать, в итоге ни то, ни другое, а только философское рассуждение на тему что лучше и лучше ли оно вообще. Если философствовать то есть один ответ: мы все работая с любым набором инструментов/языков/техник/подходов делаем всё не правильно по тому, что мы даже не в состоянии определить, что правильно. Мы в науках то даже не уверены на сколько применяемые сейчас подходы в той же физике верны и применимы... За пройденную историю уже не раз видели как то, что мы считали идеалом оказывалось совсем не идеалом, да и в целом точка зрения оказывалась только под одним углом, а под другим оказывается всё работает совсем по другому.


        1. lebedec
          15.07.2022 09:02
          +1

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

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

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

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

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

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

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


          1. Myateznik
            15.07.2022 14:37

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


    1. leventov
      14.07.2022 22:54
      +4

      Порог входа в Питоне не сильно выше чем в Го. Да и Джавы/Колтина, в принципе, тоже. Затем, способов писать на самом деле плохой код, pitfalls типа захвата переменных по значению в цикле, и других способов наделать трудно отлавливаемых багов тоже не принципиально меньше, чем в Питонах-Джавах-Котлинах. Поэтому ваше утверждение спорно. При этом я хорошо понимаю, о чем вы пишете, я сам пару лет назад пришел в команду писать на Го, даже не дочитав tour, и со всеми другими членами команды было то же самое.


      1. miga
        14.07.2022 23:07
        +1

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

        Можно, конечно, чисто механически натаскать человеков - вот тут перед функцией "@app.route('/list')" пиши и оно будет тебе гет запрос обрабатывать, но это для них чисто магия будет. А голанге за неделю можно прям боль-мень разобраться и понять как оно и под капотом работает.


        1. leventov
          15.07.2022 09:47
          -1

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

          Да даже ванильный HTTP-стек в го написан так что хрен разберёшься как он работает.

          Но это все лирика, 95% средненьких программистов туда не полезут никогда (они в принципе не лазят никуда. Многие даже не знают, как переходить на дефинишен чего-либо кроме кода проекта, и не пользуются ИДЕшками, которые это позволяют).

          Имеет значение только способность читать и писать код проекта, как он есть, плюс понимать логику фреймворков. Так вот, в Джаве оно точно не сложнее, чем в Го. Ну ок, в Питоне и Котлине с их перегрузкой операторов уже может быть посложнее. Хотя зависит от проекта. Если на проекте не используются фреймворки, которые активно используют перегрузку операторов, то и ок. Научиться читать и писать Питон и Котлин тогда не принципиально медленнее (если вообще медленнее), чем Го.

          И заметьте, это не труизм, потому что это явно не так для C++, Rust, Scala, C#. Впрочем и на этих языках можно найти обозримые сабсеты, но на практике мало кто выдерживает такие стайлгайды. Хотя если кто-то строго использует C++ Core Guidelines и использует современные анализаторы кода, внезапно C++ тоже превращается в приемлемый продакшен-язык.


    1. Zuy
      15.07.2022 07:34

      Вот, комментарий прямо в точку. Я только добавлю немного взгляда изнутри. Дело не столько в качестве программистов в Гугл, а в том, во что превратился там С++ и код ревью на нём.

      Любой код на С++ это портянки объявлений переменных. Даже простую консольную утилиту для себя невозможно написать на чистом std. Каждый второй ревьюер будет объяснять, что надо делать по другому. В итоге реально недели ревью простого кода.

      С Go эта проблема решилась. Ревью проходится за день или два. Для большинства вещей уже есть описанные правила, как делать. Язык стал инструментом решения задач а не соревнование в крутизне.


      1. siziyman
        15.07.2022 08:51
        +2

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


    1. LinearLeopard
      16.07.2022 02:57
      +1

      >при том что до этого я в основном занимался питоном, а все мои знания голанга ограничивались пройденным tour.golang.org (спойлер: этого достаточно). Так вот, через неделю я отрелизил первую версию библиотеки, которой с минимальными изменениями продолжает пользоваться весь убер.

      А написание на питоне заняло бы больше времени?


      1. Cerberuser
        16.07.2022 07:09

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


        1. LinearLeopard
          16.07.2022 11:37
          +1

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

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

          P.S. Проверил сайт с вакансиями UBER, что у go, что у python куча упоминаний, но в основном в контексте "Expertise in one or more object oriented programming language (e.g. Java, Go, Python, C++)". Как-то про технологии не пишут.

          P.P.S. Google и Meta, вроде, не против найма новых python разработчиков, даже прости господи, Yandex таким занимается, может и нанимают для постоянного переписывания сервисов, но, кажется, если бы можно было/имело смысл переписать всё на go, они бы уже справились.


  1. mikhanoid
    15.07.2022 08:48

    Для языковых холивоинов должен быть отдельный ад.

    Ну в самом деле, если знаете, как сделать правильный язык, - делайте, да пишите на нём. Критерием того, что язык правильный, является его высокая продуктивность. Если вы сделаете правильный язык, то с небольшой компанией единомышленников сможете на нём написать что-нибудь интересное, и народ потянется. Керниган и Ричи смогли даже на отстойном по мнению многих Си, и вы сможете. Экосистема языка запустится и начнёт жить. Вот и всё. Остальное - религиозные войны. Что теория типов, что особенности синтаксиса, что пресловутый nil и т.д. Пока религия не подтверждена практикой - это пустая болтовня, какой бы красивой и логичной она ни была бы.

    О nil. Как разница, от чего программа ведёт себя некорректно: от того, что по nil к памяти обратились, или от того, что не те два числа сложили, или от того, что в select забыли сокет передать? Это просто ошибки, которые бывают. Почему особое вниманием именно nil? Программы по другим причинам не вываливаются с исключениями? Взять тот же Rust, в котором нет проблем с nil. В программах на Rust повсеместно понатыканы unwrap: что-то пошло по непредусмотренному пути, программа вылетает. И? Давайте теперь изобретать язык, в котором unwrap невозможен? А что делать тогда с ситуациями, когда у программы нет информации для обработки возникшей ситуации? Просто выход с exit(code != 0)? Ну, ok, но чем это будет отличаться по сути от вываливания с исключением, если просто логика программы неверная?


    1. Helltraitor
      15.07.2022 10:11
      +1

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

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

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

      Необоснованная критика. Зачем тогда в Go используются фигурные скобки? Это же все от лукавого. Мой тейк в том, что системы типов и удобный синтаксис упрощают, ускоряют и делают разработку более надежной, что неоднократно подтверждается с выходом новых языков. Например Kotlin, который как Java, только лучше.

      О nil. Как разница, от чего программа ведёт себя некорректно...

      Разница в ровно в том, что как nil необходимо проверять в программе (а можно и не проверять, забыть - никто тебе и слова не скажет). Если говорить о nil как о не валидной ссылке не объект, то тут усе замечательно сказали более свежие языки: нам не нужен ни null, ни null pointer exception. В одних языках это решают через type? - менее прогрессивный подход, говорящий о том, что там может быть нуль и стоит его проверить перед использованием; и более прогрессивным - примитивами из функциональных языков.

      В ненавистном (любителями ассемблера от Google) Rust нельзя получить значение не обработав все возможные ситуации. Тот же unwrap - решение проблемы. Программист говорит компилятору: верни мне валидное значение или упади.

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

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

      Претензия к nil, null заключается прежде всего в их неинформативности. У исключений есть текст, у option, result есть метод expect, который принимает текст и позволяет более подробно сообщить об ошибке, а с другой стороны есть магические числа и нуль - ну упало, что ты от меня хочешь :(


      1. mikhanoid
        15.07.2022 12:08
        -1

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

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

        Необоснованная критика. Зачем тогда в Go используются фигурные скобки? Это же все от лукавого. Мой тейк в том, что системы типов и удобный синтаксис упрощают, ускоряют и делают разработку более надежной, что неоднократно подтверждается с выходом новых языков. Например Kotlin, который как Java, только лучше.

        В чём отличие Вашего заявления от следующего? "Земля плоская, потому что регулярно выпускаются книги и проводятся конференции, утверждающие, что она плоская."

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

        https://arxiv.org/abs/1901.10220

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

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

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


        1. 0xd34df00d
          15.07.2022 19:08
          +1

          Selectel недавно рассказывал, почему они с Haskell перешли на Go.

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


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

          Это несерьёзно, потому что конкретно вам я уже давал другую ссылку на другое исследование, где показывался профит от тайпскрипта для кода на JS.


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

          Докажите статически, что её там не будет, и всё :]


          1. mikhanoid
            15.07.2022 19:34

            И как я для float-ов это докажу за приемлемое время? Тут вон ребята из Gaulois для градиентного спуска в самой примитивной его форме доказательство писали 2 года вдесятером. Да и то, все реальные вычисления у них были на C++ и просто покрыты аксиомами (при чём, для Real, а не для Float), а не доказательствами корректности. И на плохих данных, там легко возникнут бесконечности.

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

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

            Про TypeScript - это частный случай. Сам JS задизайнен странным образом, не самым удачным. Но даже в таком случае TS помогает выловить лишь 15% ошибок - это не сокращение времени отладки прямо в разы. А процесс разработки затягивается далеко не на 15%. Я сравнивал для себя время решения одинаковых задач на Scheme и Haskell.

            К слову, о последнем: а что, сейчас у нас много Haskell-программистов, которые быстрее решают задачи за меньшую зарплату? Я вот, например, зная, насколько процесс программирования на Haskell выматывающий, тоже бы брал за это +50% к своим обычным запросам.


            1. Nbx
              15.07.2022 20:07

              TS помогает выловить лишь 15% ошибок — это не сокращение времени отладки прямо в разы
              Ну и повышает удовлетворение программиста от процесса в разы. А это уже много стоит.


              1. mikhanoid
                15.07.2022 21:22

                Так если это важно, тогда какие вообще вопросы? Кто-то получает удовольствие от Си, кто-то - от Раста, кто-то - от Лиспа, кто-то - от Го. Вопрос закрыт простым ответом: что вам нравится, то и используйте. Нет?


            1. 0xd34df00d
              15.07.2022 21:01

              И как я для float-ов это докажу за приемлемое время? Тут вон ребята из Gaulois для градиентного спуска в самой примитивной его форме доказательство писали 2 года вдесятером. Да и то, все реальные вычисления у них были на C++ и просто покрыты аксиомами (при чём, для Real, а не для Float), а не доказательствами корректности. И на плохих данных, там легко возникнут бесконечности.

              На C++ и я бы за годы не доказал.


              Но даже в таком случае TS помогает выловить лишь 15% ошибок — это не сокращение времени отладки прямо в разы.

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


              Я сравнивал для себя время решения одинаковых задач на Scheme и Haskell.

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


              Я вот, например, зная, насколько процесс программирования на Haskell выматывающий, тоже бы брал за это +50% к своим обычным запросам.

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


              1. mikhanoid
                15.07.2022 21:39

                Что это говорит?

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

                Это ошибки, которые были обнаружены в последующих коммитах

                В смысле? Исследователи брали код в версии до правки бага, переписывали его на TS и Flow, и смотрели, вылезет ли ошибка компиляции. То есть, баг был обнаружен и исправлен.


                1. siziyman
                  15.07.2022 22:00
                  +1

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


                  1. mikhanoid
                    15.07.2022 22:15

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


                    1. siziyman
                      15.07.2022 22:21

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


                1. 0xd34df00d
                  15.07.2022 22:13
                  +2

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

                  Ну надо же что-то доказывать!


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


                  В смысле? Исследователи брали код в версии до правки бага, переписывали его на TS и Flow, и смотрели, вылезет ли ошибка компиляции.

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


  1. ccpro
    15.07.2022 10:11
    +2

    тогда я впервые оказался в Портленде, штат Орегон, столице кофе, гранжа, ненастья

    вообще-то это про сиэтл


  1. Rustacean
    15.07.2022 14:36
    +7

    Go для нашей команды оказался реальной болью, когда мы решили писать на нём кэширующий прокси-сервер. Рейс-кондишны приходится отлавливать регулярно, ведь http.Request, который передаётся по цепочке обработчиков (в том числе сторонних) - это мутабельная незащищённая структура. Причём такие штуки отлавливают и в стандартной библиотеке: https://github.com/golang/go/issues/30597

    А ещё мы отловили баг в библиотеке http/2, которому уже идёт второй год и чинить его, видимо, слишком дорого и некому. При определённых условиях сервер просто-напросто зависает: https://github.com/golang/go/issues/42534

    А теперь взять и переписать всё - дорого. Возможно, будем в будущем слезать потихоньку в сторону Rust или ещё чего.


    1. orekh
      16.07.2022 06:28
      -3

      Человек с ником Rustacean рассказывает что переходит с Go на Rust - хм, не вижу ничего подозрительного :3


    1. me-zundig
      16.07.2022 11:22
      -1

      Обе иши не ваши, переходите на пайтон или перл, чтобы не было боли, там все хорошо.


  1. KGeist
    15.07.2022 15:20

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

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


    1. Rustacean
      15.07.2022 16:32

      Нет здесь никаких странностей для тех, кто работает с сетевым ПО. Мы используем под капотом сервер Caddy. Вполне обычная история, когда пишется промежуточный обработчик http-реквеста в цепочке (это и в другом подобном ПО будет решаться похожим образом)

      func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
      

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


      1. KGeist
        17.07.2022 01:02

        Я так и не понял, в чём проблема. Обычно фильтры/middleware выполняются на той же горутине, и ставить мьютексы нет нужды. В Caddy как-то по-другому? Не помню, что бы встречал рейс-кондиншны на http.Request, т.к. middleware работают под той же горутиной, а если нужно что-то обработать в новой горутине, то архитектурно не совсем верно туда кидать весь http.Request вместо конкретных данных, которые нужны. Можете привести пример, где приходится ставить мьютексы?

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


        1. Rustacean
          17.07.2022 11:52

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

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

          В качестве примера можете поисследовать код Caddy. Хотя опять же, нет смысла это делать, отрицая наличие проблемы.


  1. Rustacean
    15.07.2022 16:48
    +4

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


  1. virtualizationc
    15.07.2022 19:42
    +1

    Все или ничего (так не будем же делать ничего)

    <пример с нулевым значением по дефолту для полей структуры>

    Большинство примеров в статье можно было бы прокомментировать в стиле "это поведение четко определено и зафиксировано в документации, остальное - это несовпадение видения автора и позиции создателей языка". Го довольно opinionated, с этим нужно считаться, если выбираешь этот стек.

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

    Не очень понятно, с какими такими универсальными линковщиками все работают? Может быть автор имел в виду стек gcc? Довольно редкий кейс, чтобы тулзы для технологии X работали для технологии Y. Как и у других технологий, у го есть свои инструменты. Кроме того, программы на го точно так же можно отлаживать и инспектировать используя стандартные инструменты на уровне OS.

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

    <прочие недовольства интеграции с c>

    Изложено так, как будто это проблема. На практике нет. (го рантайм весит 1-2 мегабайт). Что касается отслеживания дескрипторов и прочего - примерно то же самое будет и с интеграцией другого языка с GC и си.

    А ещё вы можете легко и непринужденно не заморачиваться по поводу многих вещей, когда пишете код на Rust. <пример с UTF-8 и сторонним крейтом camino>

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

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

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

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


  1. vitiok78
    15.07.2022 19:51
    +2

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

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

    А если вам надо в ядро Линукса, так берите Rust, не задумываясь! Там он очень даже к месту.


    1. Source
      15.07.2022 21:51

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

      А маленькую программульку почему бы не написать на более выразительном языке? Кода получится в 2-3 раза меньше и объять взглядом его будет ещё проще.


      1. nin-jin
        15.07.2022 21:58
        +2

        1. Source
          15.07.2022 23:12

          Ещё раз: выше в коментах вспомнили, что именно скоростью компиляции авторы Go оправдывают свои спорные решения. Никто вроде не утверждал, что они в этом преуспели.

          А по поводу статьи, вы специально искали график, где D выглядит лучше всего?)


          1. nin-jin
            15.07.2022 23:27
            -3

            Это наиболее репрезентативный график.


        1. Alex_ME
          17.07.2022 13:34

          Ничего не могу сказать про D и Go, но время компиляции C++ быстрее растет от активного применения темплейтов, а не от количества функций.


      1. Nbx
        15.07.2022 21:59
        +2

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


        1. BugM
          16.07.2022 02:13

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


      1. vitiok78
        15.07.2022 22:15

        Я описал много пунктов, а не только скорость компиляции. Они экономят время в совокупности, а не по отдельности.

        Да и насчёт выразительности языка я не соглашусь. 90% выразительности - это простота и быстрота читаемости. Остальное - чепуха. Вы пробовали читать код на Go? Его поймет ребенок. И не требуется тратить время на тома со стайл-гайдами. Если итерацию можно сделать пятнадцатью разными хитрыми образами, это не добавляет выразительности языку. Чем "тупее" и прямолинейнее программа, тем меньше шансов в ней запутаться, тем проще её поддерживать в команде.


        1. siziyman
          15.07.2022 22:25
          +5

          Вы пробовали читать код на Go? Его поймет ребенок. 

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

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

          Чем "тупее" и прямолинейнее программа, тем меньше шансов в ней запутаться

          Ну вот "тупее и прямолинейнее" - это про какой-то другой язык, увы.


        1. 0xd34df00d
          15.07.2022 22:30
          +5

          Вы пробовали читать код на Go?

          Да. Неприятный опыт, предпочитаю не вспоминать.


          В глазах рябит от проверок на err, и за кучей частностей начинает теряться суть.


        1. Source
          15.07.2022 23:19
          +2

          Вы пробовали читать код на Go?

          К сожалению, да. Чтобы код был понятнее, он должен быть лаконичным и отделять happy path от всего остального, а если ещё DSL можно сделать, то в итоге может и правда даже ребёнок поймёт. Вот только в Go нельзя by design сделать ни то, ни другое, ни третье.

          Я описал много пунктов, а не только скорость компиляции. Они экономят время в совокупности, а не по отдельности.

          Описали. Но все эти пункты применимы и к другим языкам. У Go тут нет какой-то уверенной позиции по этим пунктам. Разве что по простоте деплоя он в лидерах.

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


  1. dmbreaker
    16.07.2022 22:10
    -3

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


    1. nin-jin
      16.07.2022 23:42
      +1

      У вас причина и следствие перепутались.


    1. DarkEld3r
      17.07.2022 11:22
      +1

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


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


      Ну и последнее, насчёт набора разработчиков. Тут тоже не всё так просто, иначе на условном хаскеле никто бы вообще коммерческие проекты не писал.


    1. nikolas78
      17.07.2022 12:11

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


  1. your_rubicon
    17.07.2022 07:39
    +2

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


    1. Borz
      17.07.2022 09:29
      -2

      в Go "нет" объектов.
      И то, что вам попался код, в котором разработчики создавали структуры напрямую, а не использовали для этого отдельно объявленный метод-конструктор - это показатель уровня кривизны рук и лени тех разработчиков


      1. nikolas78
        17.07.2022 12:18
        +2

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