Комментарии 369
Вторая программа выводит на экран:
2009/11/10 23:00:00 Working with a=47, b=0
Не понял претензии в этом случае. Мы добавили в структуру еще одно поле, явно не указали ему значение, оно инициализировалось нулем, передали структуру в функцию и она нам распечатала значение. Что не так? Компилятор должен был выдать ошибку из-за того, что мы не указали явно значение поля структуры?
В сущности, мы изменили сигнатуру функции,
Но ведь сигнатура функции не поменялась, она как принимала на вход структуру Params, так и принимает
По-моему претензия в том что параметры у функции по-умолчанию обязательны, а поля структуры — нет и инициализируются значением по-умолчанию. Это, с точки зрения автора, говорит об ошибке проектирования языка.
Да, добавлю лишь то, что в Rust вы не можете инициализировать структуру, которая не реализует trait Default, не указав все поля, которые есть. И даже если реализует этот trait, в инициализаторе явно надо писать ..Default::default() вроде, показывая что остальные поля будут инициализированы значениями по умолчанию
Зато когда вы напишите ..Default::default() вам откроется уникальная возможность добавить новое поле, забыв его проинициализировать
Не совсем так - это будет ровно такое же поведение что и в Go, т.е. инициализация значением по умолчанию, но это явно и вы для этого должны приложить усилия (либо руками реализуя Default либо через #[derive(Default)]), в отличии от неявного поведения, которое никак не выражено синтаксически в вашем коде.
Совершенно согласен с утверждением, что явное лучше не явного
Иметь возможность обязательно инициировать все поля и иметь возможность явно прописать когда это не нужно - очень хорошо
Но лично я - буду за именно обратный путь, меня устроит если появится возможность объявлять структуры так, чтобы при их инициализации нужно было бы инициализировать все поля
Это именно путь когда инструменты языка сужают возможности, а не расширяют
Имхо такой путь прозрачней
Правда кто я такой чтобы моё мнение кого-то волновало ))
меня устроит если появится возможность объявлять структуры так, чтобы при их инициализации нужно было бы инициализировать все поля
Подождите, в Rust же именно так и есть? или я вас не понял? Как раз в нем если ничего не указывать явно (с помощью derive), не реализовывать Default trait, будет именно такое поведение
У меня была нужда проверять автоматически, что структура заполнена. Это были структуры со словом Config в названии. Для этого можно легко настроить линтер. Работает отлично и спасало
Эта штука в Go напоминает проблему null'ов, по какой-то причуде названной фичей и расширенной. Всё-таки лучше, когда возможность отсутствующих значений явно прописана ввиде Option<Value or None> вместо того чтобы ожидать их везде.
Ну в этом ведь и состоит дао Го (явно унаследованное от юниксового KISS): не надо тратить лишнее время чтобы настучать это самое ..Default::default() (горизонтальное и два вертикальных двоеточия, ух), а потом ещё ходить по декларациям и проверять, где оно прописано. Все структуры ведут себя в этом аспекте одинаково. Простота как она есть.
Возможно претензия к не явности, которая ведёт к детективным историям по поиску багов, которые не так уж и невероятны, на которые будет потрачено время, за которое будут платить деньги. И этих трат можно было бы избежать дав возможность явно указывать обязательность инициализации поля структуры.
В том же TypeScript эта возможность предоставлена, и лично мне сэкономила немало времени.
Да, в более других языках это легко сделать, даже если изначально язык предоставляет дефолтный конструктор с необязательной инициализацией всех полей:
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 ) );
}
}
}
В 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),
},
)
}
Так ведь, в данном случае, это ещё больший костыль, который внешнему пользователю (=тому, кто структурой пользуется) даёт ложное чувство того, что поле действительно необязательно, а пользователю структуры всё так же оставляет необходимость каждое из этих полей проверять на отсутствие.
Не говоря о НЕтипобеопасности
ну, можно и так - тут потери типа уже нет. Правда теперь в лог пишется адрес, а не значение поля. Но тут либо шашечки (примитивы с 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 - меньше писанины. На то он и примитив, а не объект
когда примитив можно явно не указывать и ему присваивается default value
Когда это поведение по умолчанию, которое ещё и невозможно изменить - это ужас-ужас, потому что это усложняет поддержку кода, а "написать конструктор/инициализатор структуры до конца" - это, извините, меньшая из проблема в разработке.
Далеко не всегда default value типа имеет какой-либо смысл в реальном мире в том контексте, в котором этот тип используется в структуре. Хотя ладно: когда его нет, это ещё ничего, хуже, когда это значение по умолчанию смысл реально имеет - и потом поди догадайся, забыл автор его инициализировать или там и правда этот нолик стоит и с ним нужно работать (и, например, дебажить, почему у вас где-то косяк в коде дальше - проблема в вашей логике или этот нолик забыли инициализировать, что привело к неконсистентному состоянию данных в этой структуре).
У нас есть проект, где бэк на Go, где вот так приходит факт, что поле author пустое у объекта
{ title: "", author: { id: "", firstName: "", lastName: "" } }
Или enum'ы приходят так { someEnum: "XXX_UNKNOWN", }
опять же потому что "XXX_UNKNOWN" — это дефолтное значение.
Очень часто в данных есть огромная разница между 0
и Some(0)
.
.
Компилятор должен был выдать ошибку из-за того, что мы не указали явно значение поля структуры?
да
Компилятор должен был выдать ошибку из-за того, что мы не указали явно значение поля структуры?
Да. Честно, я не понимаю, зачем эту "фичу" вообще реализовали, она даже больше кода в компиляторе требует.
Претензия высосана из пальца, так как го выдаёт ошибку если не все поля инициализированы в структуре, но он сам указал, чтобы остальные поля были 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
}
Так ещё лучше: получается, что, чтобы Go выдал ошибку, нам нужно не учитывать имена полей, а вместо этого держать в голове их порядок?
Всё так же, как и с вызовом через функцию, ни кто не указывает имя параметра при вызове функции и всё нормально и ни вызывает ни у кого проблем.
И в статье явно делалось замечание, что это вообще нереально и вон какой го плохой.
Так же, IDE спокойно подсвечивает имена полей, если их не указать явно, поэтому не вижу никаких проблем.
Можно указывать, но можно и не указывать. А если указали, то не обессудьте - вот тут для вашего удобства у нас такое поведение дополнительно зашито, читайте справочник по нашему самому простому языку в мире, стр 1531, третий абзац снизу. Я бы ещё понял, если бы дефолтное значение задавалось явно, как kwargs в питоне:
type Params struct {
a int32
b int32 = 0
}
Не надо держать. IDE подсветит.
В первом случае я указал явно field `a` со значением, тогда b
будет иметь значение `0` по умолчани.
Для таких случаев в го надо писать конструктор, который будет принимать все обязательные параметры. А создавать структуру напрямую при имеющемся конструкторе нехорошо. В любом языке можно стрельнуть себе в ногу.
Не нравится язык - не пишите. Зачем себя заставлять, уговаривать, искать недостатки? Язык - инструмент, притом не универсальный. Плохих языков не бывает, но бывают программисты, которые неправильно выбрали инструмент для реализации чего-либо.
Мне например проще управляться с указателями, чем понять код где через слово self-self-self или this-this-this.
Потому что он топит за Раст, очевидно же, хотя это и языки с совершенно разными применениями и скоупом. Для 2022 года довольно типичный rant. Сейчас вот смотрю плашку справа, Go 122 вакансии, Rust 21 -- не даёт покоя это любителям раста аж до скрежета зубовного, кушать не могут.
Нет, вы это сами себе придумали. :)
Не пишу на Раст. Не топлю за переход на один конкретный язык. Это не мешает мне утверждать, что Go - пример отвратительного языкового дизайна, и для того, чтобы стало лучше, чем с ним (если вы конечно не фанатик), достаточно сменить язык на любой другой популярный, подходящий по предметной области. В фронте есть тайпскрипт, в бэке - что угодно от C++ (там конечно своих can of worms хватает), языков с явным рантаймом вроде Java/Kotlin/Scala и C#/F#, и до вещей для любителей экзоткики вроде Haskell.
Amos? Не узнаю в гриме.
Если вы намекаете, что я это какой-то другой юзер - я хз, кто этот человек, но он не я. А этим никнеймом я пользуюсь давно и "исключительно".
Суть-то всё ещё не в этом, а в том, что вместо того, чтобы как-то разбирать хорошую, содержательную статью (с которой можно валидно не соглашаться, но для этого надо разбирать статью), вы выбираете атаковать автора. :)
Автор статьи Amos Wenger -- поэтому мне непонятны слова "Нет, вы это сами себе придумали. :)" от кого-то, кроме него. Только он может это сказать.
Я высказываю своё субъективное мнение относительно того, какую цель имела эта статья в конкретном треде под конкретным комментарием об этом -- и если бы в ней не было прямого указания Раста, это мнение было бы другим.
Хорошо, вместо этого я мог бы назвать вас неприятным манипулятором, который решил додумать за автора, что и зачем он делает - но кажется, это хуже, нет? :)
Потому как даже среди тех, кто статью всячески ругал и защищал го в комментариях HN, реддита, и куда ещё там его статьи шерились, такого нелепого мнения я не встречал.
Если вас вдруг это волнует - пишу это как человек, вакансий на рабочих языках которого сильно больше, чем на го.
Я уже написал всё, что хотел -- я считаю, что автор под критикой Го прикрывает продвижение Раста. Sapienti sat, dixi.
P.S. В обсуждении на HN упоминаний Раста 111 штук: https://news.ycombinator.com/item?id=31205072 Без комментариев.
Я тоже dixi, в общем-то, но повторюсь: - вместо того, чтобы комментировать статью, вы комментируете действия автора (хотя даже если всего лишь прочитать статью в оригинале - перевод листал по диагонали - можно увидеть, что такие смехотворные попытки дискредитации там тоже прокомментированы, и "почему тут упоминается Раст так много, и почему это на самом деле не имеет значения" в том числе).
А сравнивать язык с тем, на котором сейчас в основном работаешь/пишешь, притом, что оба языка были задизайнены в сопоставимый временной период - эт конечно ужас-ужас и реклама, ага. А главное непонятно, зачем реклама.
Прям таки и большой выбор языков для бэка... Тащить java и производные либо отдаться мелкомягким? Просто отличный выбор :)
А остальные языки уже не компилируются что ли?
Для бэка довольно много языков по факту. Если опираться на аргумент "у Go такая привлекательная асинхронная среда выполнения и сборщик мусора, что они компенсируют все остальное", то можно в качестве альтернативы взять упомянутый в статье Elixir, у которого и асинхронная среда выполнения и сборщик мусора сильно лучше, чем у Go. К тому же, при необходимости в него можно добавить щепотку Rust, если вам где-то в проекте нужна числодробилка.
Человек дальше джавашарпа носа не высовывал, а вы его пугаете совсем иной парадигмой.
Ближе всего к мейнстриму эта штука: https://vibed.org/
Если вы про версию 0.9.5, то она "зачахла" в прошлом месяце. 0.9.4 вполне стабильна. Ну а что лично вас пугает или нет не имеет значения, мы не о вас говорили. А глупо - делать вид, что не знаете о разных подходах к версионированию у разных проектов, и объявлять сырым проект, не требующий ежедневных заплаток.
Вы, видимо, веткой изначально ошиблись, т.к. Haskell предлагали мне. А вы с чего то решили пованговать что я видел, а что нет.
Под "зачахла" я подразумеваю, что активность коммитов существенно снизилась, см. график по ссылке, продублирую вам её: https://github.com/vibe-d/vibe.d/graphs/contributors
Ну, и вы всерьёз считаете активным проект, у которого между версиями 0.9.4 и 0.9.5 проходит примерно год? А 384 issues намекают, что стабильность весьма условна. На половину из них даже никакого ответа нет, что на практике, скорее всего, значит что нет ни одного человека, который занимается поддержкой этого проекта за зарплату.
Не ошибся. Это ветка "что бы посоветовать человеку вместо го". Не будьте таким эгоцентричным.
Ну и гадать по графикам вы не умеете. До середины 2018 шла активная работа над двумя мажорными версиями 0.7 и 0.8. В середине 2018 развитие седьмой версии было завершено.
Проект над которым продолжают работу - активен. Зрелому проекту частые релизы ни к чему. Всего 384 issues только 16 из которых - баги, что весьма не плохой результат. Ну а на зарплате там никто не сидит, да.
Блин, чувак, пиши себе на D, никто ж тебе не запрещает.
Но нафига ты влез в ветку сравнения Elixir c Haskell, которые оба уже много лет имеют веб-фреймворки, до которых vibe.d как до луны что по фичам, что по стабильности (88 issues у Yesod и 26 у Phoenix). А ты пытаешься нас убедить, что 384 - это мало. Нет, это over дохера для веб-фреймворка. Ладно бы это только цифра была, ты зайди на Github, посмотри, что по большинству issues никакого обсуждения нет, им даже не присвоены никакие метки. С таким подходом к разработке кол-во issues будет только расти год от года и сколько там среди них багов никто не знает, потому что их никто тупо даже не читает. Что это, если не заброшенность?
Зрелому проекту частые релизы ни к чему.
Зрелому то да, только vibe.d до зрелости пока не добрался. Где пруфы, что авторы принципиально не планируют версию 1.0? На их сайте я такого тезиса не увидел. Или вы просто выдаёте желаемое за действительное?
Захотел и влез. Если вам что-то не нравится - закрывайте браузер и плачьте в подушку.
Овердохера - это 5к ишьюсов у GHC против 3к у DMD. И что? Да ничего. Тоже мне гадание по гитхабу.
Во-первых, некорректно с темы фреймворков на тему самих языков перепрыгивать.
А во-вторых, с каждым коментом ты закапываешь D всё глубже и глубже. Я интереса ради зашёл в их багзиллу ??♂️
И что я вижу: 4719 issues found. Видимо, с тех пор как ты заходил в issues tracker своего любимого ЯП, он успел ещё почти 2k issues набрать.
И чего ты сравниваешь с GHC, который себя как исследовательский проект позиционирует? Или ты посмотрел на Elixir с его 26 issues и обосрался от зависти? xD
Можешь даже 249 issues от Erlang/OTP приплюсовать.
А то вы со своим D даже хипстерский Crystal в 4 раза по кол-ву issues обогнали.
Просто у Дмитрия склонность форсить проекты, которые "не взлетели". К слову сказать, действительно интересные, классные технологии. Но, к сожалению, нужные 2,5 энтузиастам :)
Дам бесплатный совет. Вы никак не переубедите человека. И даже каплю сомнения не посеете в его голове. Он просто не слышит, не хочет слышать.
Прошу меня извинить, что я влез в ветку сравнения Elixir c Haskell.
Ну а какой смысл рассказывать людям про проекты, которые "взлетели"? Они и так про них знают. Каждый раз, когда я вижу очередное нытьё про Go или C++, React или Angular, мне становится грустно от того, сколько времени люди убивают на бестолковые решения, вместо того, чтобы вложить его с большей пользой для "взлёта" чего-то, что может вытянуть индустрию из этого болота.
В этом я могу вас понять. Но D, к сожалению, закопали сами разработчики, сначала расколов и так небольшое комьюнити на Phobos и Tango прям аккурат в момент релиза 1.0. А потом и полгода не прошло, как бросились вторую мажорную версию языка пилить. В довершение ко всему этому ещё и не уловили тренд на OpenSource. Тем самым отложив интеграцию с gcc лет на 10.
А программисту хочется хотя бы иметь ощущение, что авторы ЯП понимают, что они делают, и придерживаются хоть какой-то генеральной линии. Возможно, в этом и причина популярности Go. Да, генеральная линия его разработчиков - треш и угар, но они неукоснительно её придерживались, как минимум, 8 лет.
Да-да, у го прекрасная интеграция с гцц, а дженерики не раскалывают сообщество. Всё, что вы перечислили, на популярность не влияет вообще.
Да-да, у го прекрасная интеграция с гцц
Тем не менее, через 3 месяца после выхода Go 1.0 она уже была. А сколько лет с релиза D 1.0 прошло до включения в GCC?
а дженерики не раскалывают сообщество
Потенциально раскалывают. Но языку уже 10 лет, теперь он может себе позволить хоть несовместимую версию 2.0 выпустить, это уже не сильно заафектит его популярность.
Всё, что вы перечислили, на популярность не влияет вообще.
Поделитесь тогда своим мнением почему D настолько непопулярен?
А чего Cloud Haskell до стабильной версии не дотащили и забросили?
Не нравится мне shared memory, даже под соусом STM.
Так то мне многие идеи Haskell импонируют, но OTP - это прям самое мощное и самое подходящее, что я видел, для веб-разработки среди порядка 20 ЯП.
Под BEAM, кстати, появился ML-подобный язык, в активной разработке сейчас: Gleam. Как автор признаётся, он хотел его сделать похожим на Haskell, но из-за негативной обратной связи отказался от этой затеи.
Жаль. Строго типизированные акторы были бы интересны. Но это, наверно, на уровне самого языка надо делать, т.к. объём работ большой и авторы отдельной библиотеки на одном энтузиазме далеко не уедут.
Мимопроходил - а Akka Typed в скале - это не те самые строго типизированные акторы?
Ну, там основной смысл в том, что вы можете начать думать в терминах процессов - на верхнем уровне всё есть процесс. Когда это реализуется на уровне отдельной библиотеки, то такого кайфа уже не будет. Так как авторы других библиотек далеко не всегда будут поддерживать эту модель.
Я вообще за минимальный и тупой язык
Как же вы с Haskell уживаетесь? Я бы не назвал его ни минималистичным, ни тупым.
Лично мне распределённый STM больше понравился.
По-моему, DSTM, как и CloudHaskell, тоже давно заброшен.
А можно несколько примеров этих альтернатив?
Слышал, что Idris "исправляет" какие-то моменты в хаскеле, но он ещё и минималистичный и расширяемый?.. А есть шансы, что он начнёт теснить хаскель? Или преимущества не настолько большие, чтобы перевесить отсутствие библиотек и инфраструктуры?
Эх, был у меня план погрузиться как следует в хаскель, а потом взяться за идрис, но пришлось внезапно менять работу и теперь пока не до этого.
Комунити у хаскела шибко токсичное в собственной илитарности и гайдов/доков не сказать чтобы достаточно. Ну и плюс иногда чтобы было быстро приходится делать довольно уродливо, на мой взгляд. Плюс батарейки в комплекте вроде не очень вкусные, если я конечно его с Ocaml не путаю.
Я бы сказал, что это либо про коммьюнити из этак 2005
Телега на самом деле не моя, но программистов которые пытались вкатиться в функциональщину. Обычно самым большим минусом зовут консерватизм/элитаризм языка ("в 1970е уже все изобрели") и закидывание шапками за отсутствие знаний из теорката и прочих смежных дисциплин.
Prelude, с одной стороны, действительно стрёмный
опять же я не столько за стандартные библиотеки, сколько за УДОБНЫЕ инструменты каким стал cargo у Rust. Сборка, управление пакетами, всякие флаги оптимизации, подпись/публикация пакетов и куча прочего по большому счету не связанного непосредственно с кодом - все из одного места и без большой боли. Опять же я на настолько функциональных языках, как Haskell, длиннее Hello world не писал, поэтому по большей части ссылаюсь на опыт других людей и допускаю, что не так плох чёрт, как его малюют.
Я бы в Lean'уры пошёл, пусть меня научат. Но вцелом это все маленько сбоку от моей сферы интересов, для остального ржавчины пока хватает.
Поэтому и не рассматриваю это как что-то на чем я стану программировать в качестве основной работы, даже если очень хочется. А вот попытаться пошаманить с мат.гипотезами самый кайф, если иметь достаточно бэкраунда как оно должно работать и как вообще подходить к решению такого рода задач. У меня пока не хватает ни мозгов и ни целеустремленности, чтобы полноценно погрузиться в тему и влиться в сообщество трушных математиков, которые делают ее вычислимой, поэтому эти гештальты мне ещё только предстоит закрывать.
least butthurt gopher
Автор как раз аргументированно подсказывает почему язык может не понравиться, заботливо оставляя читателю возможность сделать выбор писать на нём или не писать.
Больше похоже "на вот пять спорных недостатков - давайте к нам в rust". При этом не приводится даже как же эти недостатки в rust решены.
Нет там никакого "давайте к нам в Rust", вы это сами себе придумали. :)
Считать го плохо, просто отвратительно задизайненным языком можно, даже не предлагая после этого один язык для перехода/замены, потому что, гм, в последние 15 лет все мейнстримные языки (в т.ч. те, которые старше, чем эти 15 лет) решили эти же проблемы способом, который не требует буквально читать мысли авторов спеки языка, как приходится делать с го.
Звучит как-то неконкретно. Можно пару примеров?
Мутабельность данных, от которой нельзя избавиться - ключевые слова final, const и иже с ними (val/var) есть давно в примерно каждом языке, на котором я писал и который я помню.
Неумение разделять данные и ошибки, данные и отсутствие данных - всякие там "монады" (на самом деле не во всех языках они реализованы стандартно как честные монады - например, джавовый Optional монадические законы нарушает) Optional/Maybe/Try.
Неотключаемое значение 0 по умолчанию для числовых полей структур (забыл проинициализировать - страдай), которое притом не кидает ошибок компиляции - ну достаточно было просто так не делать, что и произошло в других языках.
В golang есть const. Почему вы и автор статьи вдруг решили что нет? Я встречал исключения java которые отправлялись по почте программисту. Там было 500 Mb текста (просто обернул try все приложение tomcat). Естественно это письмо ему не пришло. Это точно лучший способ обрабатывать ошибки? Был еще такой вариант try, а результат игнорируем. При этом я часто встречал, как на обработку ошибок забивали совсем. К примеру дергаем какую-нибудь функцию из winapi(у которой есть задокументированное возвращаемое сообщение об ошибке) и не обрабатываем ошибку совсем. Потом приходим и делаем мозги сисадмину, как же так - почта не отправляется. Смотрю в логи: а на почтовый сервер никто даже не постучался. По мне так в go не так уж плохо с ошибками, если есть возвращаемая ошибка, то ее нужно явно проигнорировать, либо не обрабатывать никаких возвратов из функции совсем. Есть еще вариант "собирался обработать, но забыл". Но для страховки от таких ошибок сейчас есть инструменты.
Опять же. Сейчас в принципе можно программировать на go в режиме "java-программиста": просто на каждую ошибку вызываем panic и log.Fatal, а в main recover и циклическая перезагрузка приложения, но зачем?
В 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}
лучше только неабсурдностью, практическая полезность всё ещё нулевая.
Джавовые эксепшны и трай-кэтч всё ещё неидеальны, но они в моих глазах лучше, чем то, что предоставляет го - вы уж извините, но абсурдный пример как серьёзный (контр)аргумент я воспринимать не могу
..который позволяет использовать только 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 никому и не нужен. Но такую ошибку может только новичек совершить, и то, тот что невнимательно вводный курс прошел на сайте.
Go с самого начала наследовал именно синтаксис этих языков с поправкой на упрощение синтаксиса и форматирования.
Динозавры. Так где там rust/python/java/c# для микроконтроллеров? Почему ардуинщики на них не пишут? Почему когда речь заходит про java или micropython, то там речь про ну вот мы написали обвязку вокруг сишного SDK. А где реальные "дрова" оборудования на rust? А чего это никто еще c++ api из windows до сих пор не выкинул и не заменил на .net?
Вот буквально вчера работал в MPLABIDE. И представляешь, там реализация switch на c для микоконтроллеров PIC18 отсутствует.
Rust для микроконтролеров вполне используется.
Не затруднит показать хоть один реальный проект где не мигают светодиодом и не используют spi/i2c. А что нибудь где например используются прерывания и сон устройства. Короче покажите проект на rust(без использования родного SDK) который использует возможности хотя бы одного контроллера на 100 % gpio/i2c/adc/dac/spi/interrupts/sleep/etc. Потому что фреймворков умеющих мигать светодиодом я видел сотни. А вот когда дело касается реальнызх проектов, то увы и ах.
Тут и среди RTOS печальная картина. А когда дело доходит до того чтобы операционка использовала все возможности железа, то не всегда справляется, а если еще учесть что все RTOS на c++ в лучшем случае...
Так SDK написанный, как правило, на c - это все, что способен выполнить ваш код <на современном ЯП>. Т. е. единственная его функция вызвать код на С, а дальше зона ответственности заканчивается, т.е. вы запустили rust, который вроде безопасен, но вся безопасность заканчивается на реализации кода на С за который вы не отвечаете, если там в коде кто-то выудит ваши секреты, вы же не отвечаете? Потому моё отношение такое. Хотите доказать, что ваш язык современен, производителен и безопасен - вперед. Спецификции большинства процессоров со всей периферией давно в широком доступе, но что-то не вижу я распространения таковых в широком доступе, вроде бы есть одна ОС на чистом rust, но и у той распространенность и поддержка железа уступает reaсt os. Равно как и существуют прототипы ОС на go. Черт, я даже драйвер для dht-22 на raspberry pi на go написал. Но утверждать, что за rust или go будущее не берусь. Слишком много "перспективных" языков было похоронено за последние 20 лет.
Java. В свое время заявлялась как безопасный кроссплатформенный язык у которого отсутсвуют проблемы с памятью. Существовал вариант и для микроконтроллеров JavaME. Сейчас скорее мертв чем жив. Ну или по крайней мере в микроконтроллерах уступает С. В кровавом энтерпрайзе активно теснится другими языками.
До нее были Delphi/Pascal.
В свое время (середина нулевых) да. Я вот помню, как многие производители писали консоли управления raid-контроллерами на java, телефоны поддерживающие приложения на javame. Чуть позже телефоны отпали. там появились приложения на c/c++ для windows mobile и symbian, но java me долгое время поддерживали устаревшие промышленные GSM модемы и некоторые станки с ЧПУ. Консоли raid-контроллеров кстати тоже очень быстро вернулись на c++.
А, ну и андроид к чему изначально тяготел и был буквально привязан? К java.
Android. Я может удивлю, но в свое время некоторые драйверы вполне себе на java писали. Особенно касалось всяких там USB-токенов или весов, или каких-нибудь фискальных регистраторов. Та что там, и прототипы ОС на java были. Так что ничто не ново.
Опять же, что такое консоль управления RAID-контроллером. По большей части это конечно инфа в web-интерфейсе, но есть драйвер и ряд прямых команд этому драйверу вызывающих например создание или перестройку массива, и все это точно работало не через web-api.
rust/python/java/c# для микроконтроллеров
за трех последних не скажу, но у раст embed/bare metal есть и цветёт полным цветом. Даже на хабре писали, не говоря уже про официальный шоукейс. Про дрова в статье уже написал - блютус стек андроида, аналогично у Fuchsia, в Линуксе пока на котиках эксперементируют, поэтому в мейнстриме окисленного кода пока нет, хотя Линус уже грозился в следующей версии выпустить немного. На одной из конференций один чувак выступал с рассказом как они ту же ржавчину для спутникового ПО использовали.
да конечно
В с++ можно передать массив как константный указатель на неизменяемые данные и компилятор будет знать что внутри функции его менять нельзя. В го нельзя указать что массив в функцию передается только для чтения.
А в c и с++ это по-другому?
там можно указать файл и строку откуда это вызвано, только всегда ли нужно?
Даже не представляю, когда это может быть не нужно. Вот прилетел к вам багрепорт. Как искать будете место возникновения исключительной ситуации?
Если я в проекте открыл единственный конфиг и мне прилетело что я не могу его открыть, то по большому счету мне все равно, я знаю когда и откуда его открыл, тем более там даже имя файла возвращается в ошибке. Если ситуация не уникальная, то я или другие программисты на go пишу развернутое сообщение об ошибке, "дескать в функции такой то я пытался открыть файл и мне вернулось следущее - дальше цитирование..." В чем проблема? Форматировать сообщения я могу как хочу. В том числе динамически добавлять или убирать файл и строку откуда вызвана ошибка.
А теперь представьте, что не вы один на проекте, а проект не Hello World, а код писали вообще не вы.
Ну да, вы всегда можете руками написать свой кривой стектрейс.
И как же я жил до этого 10 лет? Вроде пользовался чужими либами, но что-то ни разу не возникало проблем с определением источника ошибок. Притом дописывать чужие либы именно с целью определения проблемы в коде практически не доводилось. Не помню такого случая. В основном это были дополнительные фичи.
Я подозреваю, что программисты сознательно выбравшие го, и желающие поделиться кодом, как-то самостоятельно пришли к выводу, что нужно писать код так, чтобы ни у кого не возникало необходимости в поисках ошибок досконально прочесывать твой код и как-то догадались об информативной обработке ошибок.
У вас либо предвзятость подтверждения, либо телепатия. Всем остальным сообщение "не могу прочитать такой-то файл" ничего не говорит о том, где и почему был вызов того кода, который привёл к вызову другого кода, который обратился к читалке конфига, один из методов которой и упал.
Т. е. мысль о том что код на go достаточно легко читается и отслеживается, что отследить сообщение об ошибке до источника не большая проблема вам в голову не приходит?
Это же простой язык тут не бывает как в с++:
void begin(const char* hostname, uint16_t port)
...
void begin(IPAddress ip, uint16_t port)
в принципе не может быть двух функций с одинаковым названием в программе, если одна из них не часть стороннего пакета.
Так я уже указал. Двух функций с одинаковым именем быть не может. Так что достаточно найти собщение об ошибке, а дальше тех кто его выводит. Если это не твой код, то там как правило сообщения уникальные, тебе остается пронумервать все точки, где это сообщение выводит твой код. Случаи, где return err мне попадаются достаточно редко(как правило это я сам, так я и не делюсь кодом по причине того, что стыдно). Если что-то выкладываю, то стараюсь чтобы там было все обработано.
Что, и имена методов тоже все уникальные для всех объектов?
А в c и с++ модификатор const можно добавить к любому типу данных, и инициализировать любым значением.
В с ваш пример не компилируется. в С++ работает, но есть ньюанс "не константа, а read-only variable" , тогда так https://stackoverflow.com/questions/47632706/immutable-struct-in-golang
как и с любой частью структуры, которую изменять нельзя(см. нытье автора про указатель, который неподконтрольный код может изменить). Просто не даем указатель на всю структуру, а создаем функции меняющие отдельные элементы структуры, но не имеющие доступа к другим элементам.
Таким образом. Все чего яко-бы нет в <язык программирования> на самом деле есть, но как правило делается способом отличным от того, что имел в виду <автор утверждения>, и от того ему лично неудобным. Это кстати относится к любому срачу: Windows vs Linux, MSO vs LO etc.
Просто не даем указатель на всю структуру, а создаем функции меняющие отдельные элементы структуры, но не имеющие доступа к другим элементам.
Развести горы копипасты вместо написания одного слова immutable - очень по гошному, да.
Вы же понимаете, что с подобным подходом вы создаете богатую почву для критики любого ЯП?
Развести горы копипасты для <действия>, которое я у себя делаю в два клика.
Например в go мне не нужно начинать Hello World с создания класса или объявления namespaces как в C#. Я же не заявляю что шарперы развели копипасту.
Есть не большая разница между "плюс 2 строки" и "в 2 раза больше строк".
откуда взялось "в два раза больше строк"? У вас есть проект целиком состоящий из констант, которые непременно нужно изменять при старте?
Вроде обязательное форматирование табами столько места не занимает.
immutable не предполагает изменений вообще. Они один раз создаются и далее есть уверенность, что никто ничего случайно не изменит.
Так все просто. Просто создаем структуру и указатель, но не создаем методов способных изменить структуру, только чтение. Или что, опять длинно?
ну или изначальный const, к структурам не применим, но сообщение об ошибке вполне способен сохранить или число.
Опять же в структурах есть еще возможность обращаться вк параметрам по регистру. Если параметр начинается с прописной буквы, а не с заглавной, то за пределом пакета такой параметр без "метода" не вызвать.
Вам язык явно мешает это делать. Костылями мы все умеем пользоваться. Самыми разными.
Но тут случай как с дженериками. 10 лет доказывали что они не нужны, а потом добавили. Нужны все таки. Иммутабельность тоже добавят еще через 10 лет. С ней правда удобнее программы писать.
Ага 100500 одинаковых методов для чтения значений, прекрасно.
В Джаву завезли специальную языковую конструкцию чтобы дать возможность делать сложные иммутабельные объекты. Которые естественно можно инициализировать чем угодно.
Ну да, кому они нужны?
Вы не заявляете, а шарперы заявляют: https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements
в какой-то из новых версий шарпа (вроде .NET 6.0) это не требуется. специально для hello-world-проектов завезли, можно не указывать класс и неймспейс. подставит по умолчанию.
А нужно? Для этого есть более подходящий язык? Т. е. на 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....
А в чём проблема? Пишете return, join, и вперёд. Руководств по монадам на Go предостаточно.
что вам не нравится в приведенном вам примере? Ошибка не проигнорирована. Она обработана
Ну тогда джавист из вашей истории, обернувший всё тело программы в трай-кэтч, тоже обработал ошибку, чо. Тоже сделал rethrow.
Проверяемые компилятором исключения в Java.
Контроль мутабельности, чистоты и потокобезопасности компилятором в D.
checked exceptions в джаве кстати как раз одно из спорных и непопулярных решений. Другой вопрос, что даже оно лучше, чем то, что наворотили в го.
А что там спорного? Хомячкам говнокодить не даёт?
try-catch-based логика отвратительно читается
Не хуже чем if, switch, for и тд. Претензию тут можно предъявить разве что к тому, что во многих языках зачем-то сделали, что переменные, объявленные в try не доступны в catch.
хуже тестируется
Это о чём вообще?
более "чистые" в смысле флоу кода механизмы возврата и обработки ошибок.
Речь про монады? Вот уж что действительно плохо читается, так это возня с монадами. Не даром в том же расте появился макрос try, а потом и просто вопросик означающий, что "тут может вылететь птичка" будто где-то она вылететь не может.
А ещё есть очень много откровенно unrecoverable ситуаций.
Восстанавливаемые они или нет решать уж точно не в месте их возникновения.
У ифа, свитча, фора, и прочих куда более очевидная логика перехода/ветвления, чем у try-catch. У них это "проверь условие на входе - неверно - иди в другой блок [и проверь условие там, если надо]". У try-catch это "видишь вот этот блок и абсолютно всё, что в нём вызывается? В любой момент абсолютно что угодно из блока этого может сделать плохую магию, и ты перескочишь вот в один из тех других блоков" (кэтчей-то бывает несколько).
А ещё если у трая большое тело, контекст теряется только в путь.
Захотели потестировать? Убедитесь, что интересующий вас эксепшн в трай-блоке тестируемого кода кидает та самая строка, о которой вы думаете, а не другая на 10 выше/ниже/глубже, потому что иначе вы не знаете, что вы протестировали на самом деле.
Альтернативные решения таким, как правило, не страдают.
Вы высасываете из пальца. В try передаётся блок кода (размер которого вы контролируете сами), который либо исполнится как ожидается, либо будет ожидаемый переход в catch с пояснениями. Монады работают точно так же.
Тестировать надо поведение, а не строки. И уж точно не стоит завязываться в тестах на не пойми какие исключения. Впрочем, в монаде вам точно так же может прилететь что попало, если вы не переупаковываете ошибки.
либо будет ожидаемый переход в catch
В какой момент кода и в каком состоянии системы он произойдёт? :)
Тестировать надо поведение, а не строки.
Вот именно: тестировать поведение, когда вы не можете проверить, какая из зависимостей на самом деле выкинула ошибку, не очень удобно.
Не поверите, в случае любой исключительной ситуации.
Зачем вы проверяете поведение зависимостей? Что вы будете делать, когда зависимость поменяется? Будете переписывать все тесты?
Вы, очевидно, проверяете не поведение зависимости, а поведение тестируемого кода при условии нештатного поведения зависимости.
Давайте посмотрим на классику — интерфейс 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, которые всё равно уронят весь код, если вы их не обработаете руками, и которые так же бесполезны.
Заставляет ли джава обработать все ошибочные сценарии? Нет
Заставлять она и не должна. Её задача - уведомить какие исключения могут быть, чтобы программист принял решение, выносить ли их в собственный контракт. или обработать. От монад они тут ничем не отличаются, кроме поведения по умолчанию
Заставит ли меня каждый вызов оборачивать в try/catch? Да
Не врите.
не смог прочитать и не смог, залоггировал и дальше поехали
if в данном случае ничем принципиально от try-catch не отличается.
Три проверяемых исключения, которые в 90% случаев бесполезны,
Их хорошо бы объединить в CipherExceotion.
и еще 2, которые всё равно уронят весь код
Ну так, лучше бы выпилили UnchekedException вообще.
Заставлять она и не должна.
Тогда почему она пытается, заставляя явно эти исключения во что-то оборачивать?
Её задача — уведомить какие исключения могут быть, чтобы программист принял решение, выносить ли их в собственный контракт. или обработать.
Судя по приведенным выдержкам из джавадоков с этой задачей с этой задачей справляются, кхм, джавадоки. Если мне нужно понять, какая может вылететь птичка — я смотрю в них, потому что может быть и unchecked exception, который мне всё равно не мешало бы обработать.
Не врите.
NO U.
Ну так, лучше бы выпилили UnchekedException вообще.
Ну вот когда выпилят, тогда и поговорим. А пока что checked exceptions в джаве — нечто несуразное, неудобное и безуспешно пытающееся усидеть на двух стульях.
Не пытается и не заставляет. Чего вы фантазируете?
Джавадоки не проверяются компилятором.
Ага, круглые колёса - это плохо, потому, что существуют ещё и овальные. Вот как выпилят все овальные, тогда и поговорим об использовании круглых.
Не пытается и не заставляет. Чего вы фантазируете?
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
}
}
Или вы мне сейчас попытаетесь сказать, что ошибка компиляции — это «уведомить»?
Джавадоки не проверяются компилятором.
Вы начинаете понимать суть проблемы.
Ага, круглые колёса — это плохо
В том и дело, что они не круглые, а полукруглые.
Плохих языков не бывает
Бывает, ещё как бывает. C — плохой язык. C++ — плохой язык. Go — плохой язык. 1С, прости г-пди — плохой язык.
BetterC
На Rust
Есть uTCP. Туда вообще умельцы много чего помещают. Например, виртуальную lisp-машину с реализацией http-сервера поверх неё.
Если контроллер только для передачи сигнала через net — то там нечего ломать. А если на приём. То я не сильно представляю где голый контроллер может в сеть смотреть. Это либо всякие свичи и модемы для оптики или ещё что. У всего этого как правило есть свои настраиваемые фаерволы или криптотунели.
P.S. Сначала написал комент про лампочку, а потом прочитал ваш ))) Короче все думают про лампочку ))) А Выбор AVR или там STM32 — только в цене по мойму. Берут что подешевле. Хотя STM раньше стоил дешевле AVR — что меня очень удивляло. Сейчас не знаю как.
Он же не будет торчать в открытый интернет
зато всякие неожиданные значения на входах — обычное дело
Так человече просто работал в кампании, у которой микросервисы уже были на го, так что он на этом знатно хапнул. Потому он и написал "В настоящее время я часто оказываюсь таким кем-то и уже устал от этого."
Материал о психотерапии, достаточно ознакомиться с группой сочувствующих и пострадавших в комментариях к оригиналу. Остается догадываться вызывают ли у них эти муки наслаждение или все же присутствует некий элемент понуждения. Трудно представить домохозяйку, бывшую владелицу пылесоса Самсунг, ныне гордую обладательницу Philips, которая годами пишет эссе о том, как плох Samsung, как люди себя обманывают продолжая использовать корейскую технику. Это патология или травма.
Очень жаль прощаться со временами, когда научная журналистика не была желтой. Когда материал готовился не для набора комментариев и поведенческих.
кто всем сердцем соглашаются с моей филиппикой
Здесь подразумевается монета? Или опечатка?
В 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 замышлялся как простой язык.
Всё-таки, Go замышлялся как простой язык.
В том и дело, что если прочитать эту и предыдущую популярную статью того же автора про Го, можно убедиться, что го только притворяется простым языком.
Первый же пример абсолютно нелеп и притянут за уши -- Го серверный язык и работа с файловыми атрибутами на винде ему нужна как собаке пятая нога. И что мы видим как контрпример? Естественно, раст! Опять же, без комментариев. Само собой, это просто объективная критика Го, а никакая не попытка пропихнуть Раст. Да, всё так.
Го серверный язык и работа с файловыми атрибутами на винде ему нужна как собаке пятая нога.
Тогда можно а) не поддерживать Windows б) не поддерживать соответствующие файловые системы
"Го серверный язык" где написано? На оф.сайте го не вижу ни слова о том, что на винде его запускать нельзя или не нужно (более того, я сам в продакшн код на го из-под винды писал).
Ну а по дальнейшим комментариям ещё раз отправлю внимательно читать обе статьи. Да, человек сравнивает с тем, что ему привычно, но я почему-то в состоянии натянуть эти аналогии и на привычные мне джаву, котлин и скалу, то, что в статье примеры кода на расте, меня ничуть не трогает.
Я прочитал первую статью ещё когда она вышла, а вторая только укрепила моё мнение относительно автора и его мотиваций. Заглянул тут ещё ради смеха на ютуб канал автора -- раст, раст, раст. Один сплошной раст. Для меня всё очевидно как божий день. Но если кто-то верит в то, что автор просто вдруг на ровном месте решил pro bono покритиковать Го, это его дело.
А почему в русскоязычном комьюнити так оголотело не любят раст? Есть какая-то фундаментальная причина или это просто технологическое отставание от запада?
Это вопрос к сообществу, а я обсуждаю конкретную статью, где под видом критики Го я вижу пропихивание Раста. Вот за такое, очевидно, и не любят.
Не очень подходит, потому что "новых" языков много, а специфическое отношение именно к расту. Если подумать, всё-таки, видимо, дело не в самом языке, а именно в его сообществе и том, как это сообщество язык продвигает.
Специфическое отношение у кого? У вас лично?
Нигде никакого массового "специфического отношения" к расту я не видел.
А я вижу везде -- на хабре, опеннете, ЛОРе, твиттере, реддите, хакерньюс, you name it. Далеко ходить не надо: https://www.google.com/search?q=why+people+hate+rust
Далеко ходить не надо: https://www.google.com/search?q=why+people+hate+rust
А теперь подставьте туда java, javascript, php, python и go (golang к сожалению недостаточно распространённое название - а зря).
Вы-таки не поверите, но побеждают JS и PHP - а технически как раз go, но там слово очень уж неудачное - а у Раста выдача, подозреваю, чуть больше, чем у той же джавы, просто потому, что Rust - это ещё и название сравнительно популярной компьютерной игры.
При чём тут гугл? Эта ссылка была просто для примера, а основанием для комментария является мой личный опыт, потому что я сижу на всех перечисленных ресурсах. Везде к расту одинаково полярное отношение -- или фанатичная любовь или ненависть. И даже эта статья, которая вроде бы должна была быть о Го, превратилась в срач о расте. В общем-то, как я уже написал, я сказал по этой теме всё, что хотел, ещё в самом первом своём комментарии, добавить нечего, и переливать из пустого в порожнее я не любитель, тем более, что есть ограничение по карме. Рынок всё порешает.
При чём тут гугл?
Ну не знаю, вы сказали, что раст везде как-то особенно не любят, и привели на него ссылку. Вы мне скажите. :)
Эта ссылка была просто для примера
Примера чего? "Специфического отношения"? Как эта ссылка показывает, что отношение к нему более специфическое, чем к любому другому языку, который я вобью в гугл таким же образом?
И даже эта статья, которая вроде бы должна была быть о Го, превратилась в срач о расте.
Едва ли не единственный человек, который хоть что-то здесь постоянно пишет о расте - вы, кажется. Ещё в одном диалоге в комментариях его между делом упомянули как один из примеров, срача нет. Заметьте, я сразу сказал, мне на раст побоку, я нахожу попытку атаки автора статьи вместо её содержания смехотворной.
если кто-то верит в то, что автор просто вдруг на ровном месте решил pro bono покритиковать Го
Не "на ровном месте", а (как написано в статьях) потому что он активно на нём писал - в том числе на работе - и пытался с ним "подружиться".
pro bono - не вижу проблемы, люди вон в опенсорс коммитят активно в нерабочее время - с моей точки зрения, буквально работают вместо отдыха. Люди выступают на конференциях. Люди вон вообще зачем-то пиво пьют, и даже деньги за это платят, а это такая мерзость!
Это я всё к чему: у разных людей разные предпочтения и интересы. Те, кто ведёт блоги, сюрприз-сюрприз, получают удовольствие от написания статей о чём-либо.
Я вот тоже сижу и критикую Го в комментариях на хабре, и вы не поверите, никакая масонская ложа мне ничего за это не платит.
Ну вот про файлы, 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 withos.chmod()
, you're wrong!
Ну то есть буквально в Go скопировали поведение Python.
Хорошо ли это? Нет, могли бы и нормально сделать.
Можно ли это понять? Да, можно, Windows машин что у авторов языка, что у меинтейнеров скорее всего или не было вообще, или был минимум, на котором ничего под Windows и не писалось.
Стоило ли из-за этого "не поддерживать Windows"? Нет. По крайней мере ровно в той степени, в которой тогда надо "не поддерживать Windows" в Python. Остальное то (наверное) работает. Nice небось тоже на Windows кривой почти везде и молча делает ничего, но ничего, пока никто не расстроился.
Ну да, я не питонист.
Хорошо ли это? Нет, могли бы и нормально сделать.
Ага, всё так.
Можно ли это понять? Да, можно
Нет, не можно, когда вы делаете строго типизированный язык (я тут могу много материться по поводу interface {}, но язык всё-таки строго типизированный) в конце нулевых, когда, помимо другого подхода к типизации, мир и концепции дизайна ЯП несколько отличаются от тех, в реалиях которых Гвидо дизайнил Пайтон или даже тех, в которых он довыпускал Python 2.2, в котором появился chmod.
Нет, не можно, когда вы делаете строго типизированный язык
Так а причем тут строго типизированный язык, если я говорю об одном конкретном наезде про chmod?
Наговнокодить в кросс-платформенной реализации чего либо достаточно просто. Особенно если эта платформа не является целевой. В целом странно ожидать, что chmod будет работать в windows, где в принципе нет битовой маски свойств, правда? Но наверно ошибочку таки стоило бы писать.
Ну так что это за кросс-платформенность, когда взято API одной конкретной платформы и остальные поддерживаются как получилось?
Если бы пакет, предоставляющий Chmod, назывался бы не "os", а "os.unix" или "os.linux" — претензий бы к нему было меньше.
Если не лениться читать, то в описании пакета 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.
Тут дилемма — если наваять most common denominator, т.е. только те фичи, которые есть во всех OS, то API работы с окружением будет ограничено в фичах, от этого страдала Java, например. Другой вариант вообще не делать общего API, но тогда из коробки вообще ничего нет. Выбор Unix-поведения как дефолтного считаю на практике обоснованным, т.к. целевая аудитория Go это всё-таки Unix-подобные системы, которых большинство, и Windows тут скорее исключение, чем правило. Такова реальность — в итоге в самом Windows добавили WSL, posix compatibility layer; инструменты разработчика портируются с Linux на Windows, и не наоборот.
Да, простота может быть разная. Простота использования, простота реализации, простота поддержки кода. Брэйнфак очень простой язык, но пользоваться им невозможно.
Тут, думаю, нужно впервую очередь смотреть на практику. В целом, на Go довольно просто писать код. Но доказать, что код корректный, сложнее, чем, например, в Rust. И тут мы упираемся в то, что по большому счёту все холивары основываются на субъективных ощущениях, интуиции. Очень мало у нас опираются на исследования и метрики по поводу того, как та или иная фича влияет на разработку. А иначе мы просто топчемся на месте. Недавно открыл для себя термин evidence-based software engineering, по нему есть литература, напр. одноимённая книга Дерека Джонса.
Только в Марте этого года (а ему сколько уже, 12 лет?) в Go добавили generics и этим все сказано.
Если знаете, что это, то знаете и с чем оно борется, и о последствиях, если 12 лет эту борьбу не вести.
То есть вы не знаете, что такое обобщённое программирование. Узнать о нём вы можете по ссылке выше.
Давайте сначала. Я C++ разработчик. GP я вполне себе на каком-то уровне уменю в этом языке.
Я читал новость о том что в Go добавили generic-и, выглядит как что-то (на совсем поверхностный взгляд незнакомого с Go) позволяющее работать в GP парадигме. Насколько это соответствует мощи шаблонов С++ — не берусь сказать. Возможно, не соответствует. В любом случае что
а) в Go все нормально сейчас с GP
б) или в Go добавили generics но их сильно мало
я все еще не понимаю, как эта информация что их уже добавили в этом году соотносится с «этим все сказано», с какой частью статьи это коррелирует.
Про то что там за борьба была 12 лет — не в курсе, и статья про парадигму уж точно ее не раскрывает.
Ок, следующая подсказка: https://github.com/search?q=language%3AGo&type=code
Суть в том, что авторы языка принципиально не хотели вводить generic-и в Go, призывая сообщество к говно-решению вопроса (писать кучу boilerplate-кода). Теперь generic-и добавили, но догадайтесь сколько говнокода уже написано за эти годы и сколько лет понадобится, чтобы исправить ситуацию.
Это миф про то, что "принципиально" не хотели. Если поискать через wayback machine, то официальный faq уже в 2013 году (раньше не нашёл) писал о том, что они открыты к добавлению дженериков, но пока нет понимания, как лучше реализовать.
Ну, это ж ещё хуже. Авторы по сути сами признали, что не умеют в дизайн языка. Сначала что-то нерасширяемое на коленке набросали, в сообщество закинули, и только потом стали понимание искать.
Авторы создали 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 смотрится странно.
Мне, конечно, до авторов Go далеко, но, вот, всё же, зря они пошли на поводу у сообщества. Добавили бы лучше generic functions. И синтаксис такой бы вписался бы лучше в язык, и по выразительности они достаточны, и по производительности хуже не были бы, учитывая текущую реализацию generic-ов.
С++ компилируется долго из-за кривого дизайна, унаследованного от C. Go корректней сравнивать с D, который и компилируется быстро, и дженерики были сразу, а не через 12 лет. И много чего ещё умеет, чего не умеет Go.
Многие хвалят D, но остаётся подвисшим вопрос — почему он не взлетел, если он настолько хорош? Был аргумент, что за ним не стояла большая корпорация, но за последнее время появилось несколько языков вроде Zig, к которым сейчас, субъективно, больше интереса, чем к D. Дело ещё не в языке, а в тулинге например. Может быть, с тулингом что-то не так? В Go много хорошего, что есть из коробки, не касается языка как такового.
почему он не взлетел, если он настолько хорош?
Если за холмом трава зеленее, то почему все прыгают с обрыва?
Ну все туда бегут и я побежал.
Может быть, с тулингом что-то не так? В Go много хорошого, что есть из коробки, не касается языка как такового.
Что там есть такого уникального? Рантайм чекер рейс кондишенов, который является росписью в неспособности языка от них обезопасить?
Я бы не сказал, что чистый Си компилируется медленно. Полчаса для проекта размера ядра Линукс это немного. Плюсы это другой разговор. Так что аргумент про кривой дизайн требует как минимум раскрытия.
Получилась опять ситуация, что язык применяют не для того, где он силён. Быстрая компиляция больших кодовых баз для микросервисов как раз роли не играет.
Это неправда.
В предыдущем языке Роба Пайка (наследие которого кстати в го чувствуется) дженерики были. С ними такой прикол, что реализовать их совсем не так просто, и это не потому, что авторы не умеют в дизайн языка. Да что там, проблема даже не в дизайне, а в реализации.
Дженерики как в джаве сильно нагружают гц и лишают вас возможности нормального дебага в рантайме.
Дженерики как в плюсах замедляют время компиляции, что для больших проектов критично.
Соответственно, команде го, в которой работает совсем не так много людей, потребовалось время, что определиться с тем, как технически удачнее и с большим компромиссом будет реализовать дженерики. Ну и написать их, дело тоже не быстрое.
Имхо, они конечно с этим вопросом затянули и стоило бы сделать это пораньше, но что сделано, то сделано.
Дженерики как в джаве сильно нагружают гц
Чем, пардон, джавовые дженерики нагружают ГЦ больше, чем любые другие?
лишают вас возможности нормального дебага в рантайме
Во-первых можно делать их reified (хотя кмк это поощряет некоторые сомнительные практики в разработке, но не суть), во-вторых, и с type erasure всё в рантайме прекрасно дебажится.
Дженерики как в плюсах замедляют время компиляции
Ну вот только в плюсах не дженерики, угу. Шаблоны - несколько не то же самое.
Это всё пыль в глаза, а вы и уши развесили. Вместо обобщённого кода вам предлагают копипастить. А компилировать в несколько раз больше кода - это всяко медленнее, чем несколько раз инстанцировать один шаблон.
Не факт. Вы не учитываете усложнение алгоритма вывода типов. БОльшая часть правил вывода в том же Haskell, процентов 90, - она про ограничения и generic-и (конструкторы типов) как раз. А работает проверка и вывод типов всегда. И там сложность, минимум, квадратичная.
Обобщение в широком смысле слова — это ключевая аналитическая задача программиста в процессе разработки решения и моделирования предметной области.
Конкретно дженерики — наиболее популярный и эффективный способ реализовать обобщенное программирование на строго типизированных языках, как показал опыт. Настолько эффективный, что даже языки с динамической типизацией вроде Python пытаются притащить дженерики в свое окружение. Нужно пояснять в чем ирония?
Кроме технической составляющей, я бы еще отметил, что адепты Go все эти 12 лет себя и окружающих фанатично убеждали что дженерики не нужны "by design". Однако, реальная практика всё же вынудила признать некомпетентность изначальных идей.
Этот пример с дженериками достаточно очевидный и показательный чтобы отметить в целом всю несостоятельность и глупость дизайна Go. Поэтому используется такая фраза как "этим всё сказано".
Ваш капитан очевидность.
Этот пример с дженериками достаточно очевидный и показательный чтобы отметить в целом всю несостоятельность и глупость дизайна Go. Поэтому используется такая фраза как «этим всё сказано».
Ваш капитан очевидность.
Ну спасибо что хоть кто-то уделил минутку внимания чтобы объяснить что там сказано)
Про то что изначально в Go не было планов на дженерики я тоже наслышан. Просто мне почему-то показалось что корневой комментарий пытался оспорить постулаты статьи этим «всё сказано», а так он еще больше поддерживает.
А, еще видимо я слово «только» не в том значении прочитал.
Я прочитал предложение как "… статья конечно хороша, но вот только в Go уже есть дженерики с марта"
а по факту коммент был похоже
«плюсую статье, все по делу. одно лишь факт (»только") что в марте ЭТОГО года добавили..." далее по тексту.
Возможно из-за этого и был тупняк.
Всем извините, можете минусить мой тупизм дальше)
Дело не просто в том, что не было дженериков, а в том, что было: статическая строгая типизация. Сразу понятно к чему это приводило - когда реализации одного и того же метода интерфейса для разных типов приходилось писать вручную, есть целые библиотеки с кучей функций типа AddIntInt, AddInt32Int32, AddUint32Uint32 и т.д. И кодогенерация, как в "старых добрых" 60-х. Хотя уже тогда были языки с динамической типизацией вроде разных LISP, а Smalltalk появился в 1972. А Go притворяется, что сейчас 70-е. Это такой Паскаль с CSP. Со всеми вытекающими.
Можно ещё вспомнить классику.
Тот неловкий момент, когда на середине полёта в яму задумался о том, что, наверное, и не стоило в неё прыгать. Обожаю такие "метакомментарии".
* За тупизм извиняем.
Вот Вы говорите "наиболее популярный и эффективный". А на какой статистике Вы основываете это утверждение?
Надеюсь, вы этот вопрос написали истины для, а не потроллить.
Такой статистики, конечно, не существует. Но мы можем сделать статистическое предположение. Предположим, что разработчик в любом случае использует дженерики, реализованные в языке. Даже если он не пишет их в своём коде, опосредованно он всё равно получает пользу от дженериков в стандартной и сторонних библиотеках. Тогда общая популярность языка будет косвенно указывать на эффективность и популярность дженериков.
Возьмем индекс TIOBE и посчитаем популярность языков:
Python + Java + C# + Visual Basic + Swift + PHP = 38%
C + JavaScript + ASM + SQL + Go + C++ = 29%
Чисто формально по этим цифрам дженирики наиболее популярный способ даже против суммы всех "не дженериков", а если сравнивать по отдельности, вывод будет еще основательнее.
Изначально в go были ограниченные дженерики -- слайсы, мапы и каналы. Но свои собственные обобщённые типы программисты создавать не могли.
Ну как добавили... как и почти все остальное в го они half-baked:
type Integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
до функционала дженериков в TS, расте или других подобных языках им еще 12 лет...
На мой взгляд, главная проблема го в том, что это закрытая разработка, всем рулит небольшая группа людей из гугла и на интересы сообщества им наплевать
это закрытая разработка, всем рулит небольшая группа людей из гугла и на интересы сообщества им наплевать
Я давно слежу за разработкой go и это совсем не то, впечатление, которое я получил. Как минимум, каждый год проводится survey для понимания приоритетов сообщества, я участвую в каждом. Отсутствие дженериков было обозначено как проблема номер один. Любой желающий может предложить proposal. Проблема в том, что большинство proposals ещё более half-baked, чем то, что предлагает ядро разработчиков из Гугла. В стиле "я видел фичу Х в другом языке, хочу так же". Детали не проработаны, backward compatibility не проработано, и т.д.
А что, кто-то насильно заставляет писать на Go? Не понимаю смысла этой статьи. Не нравится производительность - пиши на Си (больше заморок с памятью) или Расте (чудовищный порог входа). Не хватает выразительности - пиши на более выразительном языке (но будь готов отстаивать на кодревью правильность слоёв абстракции).
Нет такого закона, что все должны писать на Go и страдать, и нет такого закона, что все должны слезать с Go, потому что Раст круче.
А зачем писать комментарии, если получается написать только "Не нравится - не ешь"? :)
Критику можно обсуждать, опровергать, соглашаться, вот это вот всё. Это в конце концов позволяет сделать язык лучше. Но нет же. :)
- В споре рождается истина...
- Что ты, Сократ, не надо! Спорить с богами бессмысленно, выпей-ка лучше яду!
(с) Ф. Кривин
На мой взгляд, критическая статья прекрасный способ повлиять на сложившуюся ситуацию, с которой ты не согласен. Вы знаете какие-то еще цивилизованные способы?
Вклинюсь тут немного, хотя ничего против самой статьи не имею, даже понравилась, если подумать.
Тем не менее, на мой взгляд, лучший способ в 2022-м году сделать так, чтобы кто-то чем-то не пользовался, о чём-то не говорил или вообще никогда не увидел какой-то информации - это молчание. Любое слово, критическое или поддерживающее, которое привлекло внимание людей - делает только хуже, ибо создаёт "рекламу". Поэтому молча не использовать и не жаловаться - лучшая стратегия.
Ну это кое-как можно расценивать как способ, если вы просто радикально что-то ненавидите и хотите, чтобы оно вымерло любой ценой. Вот только это не работает с тем, что уже популярно и имеет аудиторию - то есть, например, го.
А вот обсуждая недостатки и объясняя альтернативы, вы можете добиться того, что кто-то обратит на них внимание и или предпримет что-то, чтобы пофиксить их в критикуемом, или рассмотрит для себя альтернативы, где их в таком объёме не будет.
Понимаю, о чем вы говорите. Несовершенство информационных технологий часто увеличивает видимость ложных ценностей и оставляет в тени реальные достижения.
Но авторитеты вроде Google вкладывают достаточно средств для создания хайпа и рекламы собственных технологий, чтобы закрепить выгодные им тенденции в культуре разработки даже в ущерб реальному технологическому прогрессу.
Молчание в такой ситуации — не лучшая стратегия. Наоборот, конструктивная критика только и остается для реального продвижения и разрушения ложных ориентиров.
Противостояние Rust и Go в подобных статьях и комментариях не случайно. Хотя Rust предлагает реальные инновации в программировании, он вынужден отыгрываться на втором плане из-за рекламно успешного, но технически посредственного Go.
Да бросьте. Медийное давление, создаваемое Rust-сообществом просто беспрецедентно. С Go даже близко такого нет. Даже с Haskell в своё время такого не было. Куда ни глянь - везде только Rust и обсуждают. Ну, или другие языки в контексте того, насколько они хуже Rust. В каналах языковых телеграмма тоже сплошной Rust. Фанаты крайне активны.
Интересно, в каком мире вы живёте, потому что я не встречал такого ни в одном не-растовом языковом чате.
Ну... Социальные пузыри у всех разные. К сожалению. Я живу в каналах дизайна ЯП и компиляторов. А что, в Вашем пузыре реально пиарят Go изо всех сил?
В моём пузыре вообще редко какие-то языки пиарят. Но го вспоминают чаще раста, хотя всё ещё в моих глазах несущественно редко.
впрочем, не удивлюсь, что в каналах дизайна ЯП и компиляторов го не вспоминают, потому что на этих фронтах достижений у языка минимум
Не, его часто вспоминают словами о том, какое же это Го..., а вот Rust - золото. Совершенно, кстати, не понятно, чего Rust-овцы недолюбливают так сильно именно Go. Типа, одна из граней противостояния Google и Mozilla, начавшегося с браузеров?
Давайте вы не будете мне рассказывать, какие я читаю отзывы о Го, ладно? :)
Нет, я не вижу никаких сколько-то регулярных выкриков "го - какашка, вперёд в раст".
Я вот джавист (плюс-минус - я коммерчески писал на джаве, котлине, скале, тайпскрипте и го - на джаве и скале больше всего - и ни разу в жизни не трогал раст), конкретно го я тоже не люблю больше среднего.
поясню. Дело в том, что абсолютное большинство гошников, которых я знаю , перешли на го с другого языка. И я в том числе. Поэтому мы прекрасно видим и недостатки и достоинства языка. Любой кто писал на го - и так знает, где ему что мешает по сравнению с языком X. И стоят ли эти недостатки того, чтобы с ними мириться или нет. Статья пытается убедить непойми в чём, короче.
… или Расте (чудовищный порог входа)
А вот не факт. Не, с тем, что у 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 несколько преувеличены.
Сейчас есть определенный хайп вокруг Python и Go. И многие новички по факту начинают изучать эти языки в результате маркетингового обмана. Так что говорить о них правду вполне может быть полезно для IT-сообщества в целом.
Потому что, чтобы понять насколько плох тот или иной ЯП, надо для начала хотя бы 5 разных языков изучить, а лучше 10)
Незрелый и однобокий аргумент, на мой взгляд. Особенно в контексте обсуждения технической статьи. Что значит "не нравится производительность - пиши на Си"? С таким же успехом можно было и не писать этот комментарий, если не понимаете/не приемлете отношения автора статьи к языку Go.
Все вышесказанное относится и ко мне, если что :)
Я 7 месяцев работю тестером в достаточно большой американской комании где большая часть Back End сделанна на Go + gRPC. Я не слышу воплей девлоперов (у меня в команде их 5) что они не могут делать свою работу потмоу, что выбор языка кривой, и надо было выбрать чтото другое. Их когда нанимали, им говорили начем все написано, не хотели бы выбрали другую работу. Что за проблема? Ну не нравится тебе язык этот... не пиши на нем, не нравится что на работе на нем пишут - поменяй работу. Столько времени человек убил чтобы написать это все... такой дешевый заход на попытку привлечь к себе тонну внимания и развести срач... детский сад.
Автор совсем, критически не понимает, зачем нужен голанг.
4 года назад я пришел в большую контору (Убер, если конкретно) писать на голанге, при том что до этого я в основном занимался питоном, а все мои знания голанга ограничивались пройденным tour.golang.org (спойлер: этого достаточно). Так вот, через неделю я отрелизил первую версию библиотеки, которой с минимальными изменениями продолжает пользоваться весь убер.
В этом и есть суть голанга - дать возможность большому количеству средненьких (а зачастую и откровенно плохоньких) программистов совместно писать достаточно хороший код - достаточно хороший, чтобы с ним можно было жить в проде, и достаточно плохой, чтобы не было жалко его выкинуть как только потребуется.
Гугл просто решал свои задачи, ну и заодно людям дал попользоваться.
А так-то конечно да, гошный стдлиб - срамота, все потуги с управлением зависимостями до появления модулей (помните были такие glide и dep?) - это вообще откровенная диверсия - много, много всего очень плохо. Но просто и не стояло задачи написать идеальный язык :)
Кстати, наброшу - с обработкой ошибок начиная с 1.13 все более-менее нормально :)
Ну, допустим, с тем же кубером не все так однозначно, но с голангом проблемы гугла в принципе совпадают с проблемами масс - хороших погромистов мало, а дело делать как-то надо.
С голангом можно нанять хоть каких-то (пхпшников, сишников - пофиг), за неделю-другую их натаскать на голанг (и - важно - обучить их, как делать разные вещи идиоматично - в голанге действительно много гласных и не очень соглашений, которым закрывают разные подводные камни) и вперед, фигачить в продакшен. Я, например, так делал, нормально.
(и — важно — обучить их, как делать разные вещи идиоматично — в голанге действительно много гласных и не очень соглашений, которым закрывают разные подводные камни)
Или взять другой язык, в котором этих подводных камней нету. Да, выучить Go проще. Но изучение языка — это однократное вложение (так что предельная ценность простоты изучения языка нулевая), а вот с Go-специфичными проблемами придётся сталкиваться постоянно.
Если это однократное вложение затягивается на годы, как с Haskell, например, в силу особенностей экосистемы, то стоит ли оно того? Rust или C++ тоже простыми языками не назовёшь. Кроме того, важна метрика: время до запуска бажного MVP. Потому что баги бывают не только в коде, типах и указателях, но и в самой идее, в организации интерфейса, etc.
А дальше берём одну и ту же задачу, и смотрим, как она на разных языках решается, и с какой скоростью.
Вот так всё просто, на самом деле. Только почему-то народ предпочитает витать в абстрактных рассуждениях о тех или иных схоластических тонкостях.
Если уж говорить про скорость разработки, то пока гофер будет сутки изобретать очередной велосипед, дишник воспользуется богатой библиотекой обобщённых алгоритмов за 5 минут.
Зачем гоферу сутки изобретать велосипед? Чай не во времена телетайпов живём. Взял готовую реализацию, подправил в ней что-то под себя, и вперёд. Ну, не 5 минут займёт, а 15. Зато потом можно будет алгоритм под свои задачи подстраивать, параметризовать каким хитрым образом. У generic-библиотек существенный недостаток: железобетонный интерфейс, который не так часто достаточен, как хотелось бы. Приходится изловчаться разными методами. Просто сложность в другое место переезжает, вот и всё.
На C++ и на Haskell я пописал достаточно долго, чтобы испытать облегчение от перехода на Go, а потом и вообще на Lisp, именно по той причине, что выражать свои задумки на них гораздо проще.
Отладка, тестирование, документирование, ревью, поддержка - всё это тоже включено в 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 );
}
Я не шибко великий специалист по Go, но мне кажется, реализация там чрезмерно усложнённая. Я бы проще написал.
Это реализация из документации. А как бы вы написали?
А какие ограничения решение должно учитывать? Самое простое - сделать две разные реализации интрфейса "под задачи", а чтобы не писать каждый раз длинные if-then-else в реализациях Less для сравнений по ключам сделать функцию-композиции сравнений.
Может так?
package main
import (
"fmt"
"sort"
)
type Change struct {
user string
language string
lines int
}
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},
}
func main() {
sort.Slice(changes, func(i, j int) bool {
return (changes[i].user == changes[j].user && changes[i].lines < changes[j].lines) || changes[i].user < changes[j].user
})
fmt.Println(changes)
}
В нормальных языках это делается гораздо проще
Получается go тоже нормальный?
Сортировка в стандартной либе это наверное самая известная проблема, в т.ч. авторы Go в курсе, что решение такое себе. Сейчас есть инициатива сделать по-нормальному после добавления дженериков.
Это в каких языках нету подводных камней?
В целом соглашусь смысл статей вполне имеет место быть, только мне лично одно не нравится в этих статьях - утверждение с посылом "вы не гугл, вам это не светит, не нужно и вообще сидите на своём месте".
Т.е. ровно так же можно про любой язык говорить да и в целом про библиотеку/инструмент/подход/идею/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. Как говорится вам шашечки или ехать, в итоге ни то, ни другое, а только философское рассуждение на тему что лучше и лучше ли оно вообще. Если философствовать то есть один ответ: мы все работая с любым набором инструментов/языков/техник/подходов делаем всё не правильно по тому, что мы даже не в состоянии определить, что правильно. Мы в науках то даже не уверены на сколько применяемые сейчас подходы в той же физике верны и применимы... За пройденную историю уже не раз видели как то, что мы считали идеалом оказывалось совсем не идеалом, да и в целом точка зрения оказывалась только под одним углом, а под другим оказывается всё работает совсем по другому.
Я считаю каждый сам должен решать что использовать, зачем, как и вообще на сколько это кому-то нужно. Не нужно постоянно всех отговаривать и тем более пытаться продать "альтернативу, которая вообще лучше".
Давайте предположим, что люди нацелены на добро в первую очередь. Ваш сотрудник или автор статьи в интернете критикует технологии не для того, чтобы ущемить вашу волю и право выбора.
Критик делится собственным опытом решения проблем, часто с помощью альтернатив, чтобы в конечном итоге экономить вам время в поиске истины. Вы ведь не можете лично проверить все технологии на свете.
Касаемо различных технологий из Google, которыми многие пользуются и от которых достаточно много пытаются отговаривать (а это именно так) тоже отдельно хочется сказать.
Часто технологии применяются потому, что они созданы компаниями, считающимися авторитетными. Без каких-либо объективных причин десятки проектов содержат, но не могут использовать эффективно: круглые люки, микросервисы, ангуляры, куберы и т.д.
Критические замечания направлены на разрушение этой апелляции к авторитету, чтобы каждый мог реально сам решить что использовать, на основе объективных аргументов, а не популярности компании изготовителя.
Особенно это актуально для разработчиков, которые занимают рядовые позиции и вынуждены работать с тем, что им спускают архитекторы и технические директора, которые эмоционально оценивают своё производство на уровне гугла, амазона или фейсбука.
Давайте предположим, что люди нацелены на добро в первую очередь. Ваш сотрудник или автор статьи в интернете критикует технологии не для того, чтобы ущемить вашу волю и право выбора.
Если бы все были идеальны и всегда желали добра, а главное всегда критиковали технологии с единственной благой целью, но увы нет. Да даже если так, желая только добра можно столько всего кардинально противоположного наворотить, что выглядеть будет как целенаправленное вредительство.
Конкретно в этой статье посыл именно из ряда, "ради добра прям советую даже не используй это", хоть конечно критика затрагивала не только сам Go, другим языкам тоже досталось, однако главный объект критики в статье именно Go и что главное по всему тексту он прям вообще ни для чего не годится, только вот Google и вон те ещё ребята.
Критик делится собственным опытом решения проблем, часто с помощью альтернатив, чтобы в конечном итоге экономить вам время в поиске истины.
Самое интересное, у критика решение проблем сошлось только к самому простому решению - предложение альтернативы, проще этого разве что вообще сказать "вам это не нужно". Какого-то прям глубокого разбора "проблем" и их решения тут не было.
Более того автор в тексте ссылается на команду разработчиков, говорит что они профи в Go, шарят за внутрянку и прочее, по этому им можно и простительно использовать Go. А ведь этой ссылкой автор признаёт, что он далеко не такой же профи в Go, что внутрянку он не изучал, в сравнении вон с теми ребятами. Но при этом его позиция выстроена так, как будто он разобрался в недрах Go и предлагаемой альтернативы на столько, что вот такие есть слабые места и вот почему так получилось, что они слабые.
Опять таки как я уже писал, ровно таким же образом можно критиковать вообще любую технологию, посмотрев на неё сверху. Однако айсберг маленький только над водой, а почему у айсберга такая форма, а не другая и прочее это вообще не нужно разбирать как будто и главное это вообще ни на что не влияет.
Часто технологии применяются потому, что они созданы компаниями, считающимися авторитетными. Без каких-либо объективных причин десятки проектов содержат, но не могут использовать эффективно: круглые люки, микросервисы, ангуляры, куберы и т.д.
Давайте тогда быть честными, часто всегда технологии созданы кем-то и как правило это крупные компании/организации, считающиеся авторитетными. И что главное почему-то этими технологиями все пользуются только опираясь на авторитетность создателей без каких то других объективных причин и это не в десятках проектов, а буквально в каждом и ни где это не используется максимально эффективно.
Критические замечания направлены на разрушение этой апелляции к авторитету, чтобы каждый мог реально сам решить что использовать, на основе объективных аргументов, а не популярности компании изготовителя.
Если мы будем так разрушать каждую апелляцию к авторитету на право и на лево, тогда каждый должен полностью независимо с нуля вести сначала изучение физических объектов и процессов, потом самостоятельно на выше изученном создавать свои вычислительные машины, концепции (почему вообще байт код и почему двоичный?), языки и т.д. Это будет уже не прогресс, а топтание на одном месте, даже больше похоже на челлендж из разряда найди все возможные способы достижения цели. Ну серьёзно.
Особенно это актуально для разработчиков, которые занимают рядовые позиции и вынуждены работать с тем, что им спускают архитекторы и технические директора, которые эмоционально оценивают своё производство на уровне гугла, амазона или фейсбука.
А это уже про обратную связь, вы ведь можете пообщаться с архитектором, с тех. диром, предложить свой взгляд, приведя достаточно убедительные аргументы, если вы действительно разбираетесь в том почему ваше предложение лучше выбранного.
Поймите, даже архитекторы и технические директора не всё знают, по тому, что действительно прям каждую технологию потрогать в принципе не возможно. Ну и главное, как будто рядовые разработчики совсем не эмоциональные и без каких либо амбиций...
Ещё раз я согласился с тем, что статьи такого формата имеют место быть, но и указал недостаток такого формата, в первую очередь это негативный окрас по отношению к рассматриваемой технологии с посылом "не трогай", потеря объективности т.к. в погоне за поиском и приведением недостатков приводятся универсальные недостатки, применимые ко многим технологиям сразу в т.ч. к тем, которые тут же позиционируются как альтернатива.
Ещё раз, автор попробовал, нашел какие-то не устраивающие его места, решил поделиться своим опытом работы с технологией, ок покажи конкретные примеры, без ссылок на абстрактные случаи. Если у тебя и правда добрая цель и ты делишься опытом, а не просто своим негативным отношением, то поделись решением, если нашел его, не нашел решение, ну хотя бы разобрался почему тут так, а не как ожидалось, расскажи об этом.
Порог входа в Питоне не сильно выше чем в Го. Да и Джавы/Колтина, в принципе, тоже. Затем, способов писать на самом деле плохой код, pitfalls типа захвата переменных по значению в цикле, и других способов наделать трудно отлавливаемых багов тоже не принципиально меньше, чем в Питонах-Джавах-Котлинах. Поэтому ваше утверждение спорно. При этом я хорошо понимаю, о чем вы пишете, я сам пару лет назад пришел в команду писать на Го, даже не дочитав tour, и со всеми другими членами команды было то же самое.
Ну уж нет, позвольте с вами не согласиться - питон намного больше и сложнее голанга, про джаву с котлином и говорить нечего.
Можно, конечно, чисто механически натаскать человеков - вот тут перед функцией "@app.route('/list')" пиши и оно будет тебе гет запрос обрабатывать, но это для них чисто магия будет. А голанге за неделю можно прям боль-мень разобраться и понять как оно и под капотом работает.
Это ни чем не отличается от гошных фреймворков. Даже, я бы сказал, из-за низкой экспрессии языка и, как следствие, опоры фреймворков на кодогенерацию, там вообще очень сложно разобраться. Посмотрите какой-нибудь gqlgen например.
Да даже ванильный HTTP-стек в го написан так что хрен разберёшься как он работает.
Но это все лирика, 95% средненьких программистов туда не полезут никогда (они в принципе не лазят никуда. Многие даже не знают, как переходить на дефинишен чего-либо кроме кода проекта, и не пользуются ИДЕшками, которые это позволяют).
Имеет значение только способность читать и писать код проекта, как он есть, плюс понимать логику фреймворков. Так вот, в Джаве оно точно не сложнее, чем в Го. Ну ок, в Питоне и Котлине с их перегрузкой операторов уже может быть посложнее. Хотя зависит от проекта. Если на проекте не используются фреймворки, которые активно используют перегрузку операторов, то и ок. Научиться читать и писать Питон и Котлин тогда не принципиально медленнее (если вообще медленнее), чем Го.
И заметьте, это не труизм, потому что это явно не так для C++, Rust, Scala, C#. Впрочем и на этих языках можно найти обозримые сабсеты, но на практике мало кто выдерживает такие стайлгайды. Хотя если кто-то строго использует C++ Core Guidelines и использует современные анализаторы кода, внезапно C++ тоже превращается в приемлемый продакшен-язык.
Как мы себя обманываем, только бы продолжать пользоваться Golang