Comments 358
Я бы еще добавил, что в большинстве случаев советуют использовать одну из самых ужасных вещей в программировании на мой взгляд — кодогенерацию.
Он же вроде для междуязыковой компиляции. А зачем такое в рамках одного языка?
А еще есть lombok. И мне почему-то, кажется, что оба эти проекта подходят под пункт: "Мы боремся с косяками языка".
А с js ситуация еще хуже, потому что там у людей еще и выбора нет.
Без ответа на эти вопросы исходное утверждение выглядит как «кит сильнее слона».
Если ядро призвано только синхронизировать интерфейсы взаимодействия, то, возможно, проще будет поддерживать консистентность используя кодогенерацию, так как она обеспечивает меньшую свзяность проектов между собой. А если должна быть еще какая-то общая бизнес-логика, то лучше писать ядро.
А если вернуться к Go, то она еще и реализована довольно не удобно — ее нужно запускать каждый раз в ручную (по крайней мере из того, что я слышал).
Если уж кодогенерацию использовать, то модификация исходников для кодогенерации должна автоматически приводить к перегенерации кода в момент компиляции, а этого в Go нет.
Разработчики Go — не были фанатами IDE и потому использовали «старый стиль», когда кодогенерация является одним из инструментов, а не «табу», с которым борются всеми возможными способами…
Это где же в современных ide кодогенерация?
Ну и плоха она по ровно одной причине: результат часто плохо читаемый и нужно ещё дополнительно учить инструмент кодогенерации и дрессировать его. А все для того, что бы обойти косяки языка (например, разницу между примитивными типами и объектами в Java).
var result = await db.Query(SQLResources.GetProducts);
Это где же в современных ide кодогенерация?Везде. Начиная от автоматического создания кучи бойлерплейта Wizard'ами, до вполне себе «классической» кодогенерации вещей типа R.java.
Просто считается, что когда IDE геренирует тонны бойлерплейта, которые потом вставляются в ваш проект и засоряют его тоннами строк кода, который вы не писали, то это — хорошо. А когда вы сами, руками пишите скриптик, который порождает код — то это ужас, качмар, низ-зя. Не положено вам магией заниматься. Лицензии от гильдии магической потому что нет.
Ну и плоха она по ровно одной причине: результат часто плохо читаемый и нужно ещё дополнительно учить инструмент кодогенерации и дрессировать его.Ну насчёт читабельности — это уж что вы сделаете, то и будет… А что инструмент нужно учить — ну так библиотеки, которыми вы пользуетесь тоже, как бы, правильно использовать без обучения не получится.
Просто считается, что когда IDE геренирует тонны бойлерплейта, которые потом вставляются в ваш проект и засоряют его тоннами строк кода, который вы не писали, то это — хорошо.
Я так не считаю. Разве что в случае с ресурсными файлами, как мне указали правильно, и, например, настройкой GUI через стороннее приложение.
Но довольно странно защищать кодогенерацию, которую приходится использовать для того, что бы обойти отсутствие дженериков в языке. Или там, которая будет автоматически пробрасывать ошибки наверх, например.
Разве что в случае с ресурсными файлами, как мне указали правильно, и, например, настройкой GUI через стороннее приложение.А чем ресурсные файлы уникальны? Чем ORM, RPC, FSM хуже? Тем, что ваша IDE их не знает? Ну так научите! Или успокойтесь уже и признайте, что «магическая лицензия» для кодогенерации не нужна.
Но довольно странно защищать кодогенерацию, которую приходится использовать для того, что бы обойти отсутствие дженериков в языке.Кодогенерация вместо дженериков в языке — это, несомненно, костыль. Но неясно, насколько велика проблема. Мне, на практике, дженерики не были так уж сильно нужны и особых проблем я от необходимости поддерживать их руками никогда не испытывал. Возможно в тех, проектах, которые делаете вы — ситуация другая, было бы интересно посмотреть на проект, где дженерики занимают столь существуенную часть, что их отсутствие реально мешает.
Или там, которая будет автоматически пробрасывать ошибки наверх, например.А вот этого, пожалуйста, не надо. «Автоматическое пробрасывание ошибок наверх» — это то, с чем создатели Go пытаются извести. Можно эту точку зрения любить или ненавидеть, но если вам нужно «пробрасывать ошибки наверх» — то вам точно не нужен Go.
Потому что вы связываете xml и ваш код. Если вы связываете сторонние сущности и ваш код, тогда вам приходится использовать кодогенерацию. Особенно если эти сторонние сущности еще используются в программах, которые написаны на разных языках.
Опять же, вы приписываете мне какую-то странную приверженность IDE и "магической лицензии", но я просто считаю кодогенерацию не очень удобной и стараюсь ее избегать как можно чаще. Особенно в рамках одного языка, где казалось бы фич языка должно хватить. Но вот господам с Go и Java приходится страдать.
А вот этого, пожалуйста, не надо. «Автоматическое пробрасывание ошибок наверх» — это то, с чем создатели Go пытаются извести. Можно эту точку зрения любить или ненавидеть, но если вам нужно «пробрасывать ошибки наверх» — то вам точно не нужен Go.
Не затруднит ли вас показать код популярного проекта, где все ошибки обрабатываются вот ровно на месте и не наполнены кодом вида:
if err != nil {
return nil, err;
}
Кодогенерация вместо дженериков в языке — это, несомненно, костыль. Но неясно, насколько велика проблема. Мне, на практике, дженерики не были так уж сильно нужны и особых проблем я от необходимости поддерживать их руками никогда не испытывал. Возможно в тех, проектах, которые делаете вы — ситуация другая, было бы интересно посмотреть на проект, где дженерики занимают столь существуенную часть, что их отсутствие реально мешает.
Берите любой крупных проект на go и попробуйте сделать grep "interface{}" -R .
в его репозитории. Я не эксперт, но мой взгляд, почти каждый interface{}
будет из-за проблемы с отсутствием дженериков. Я вот только что грепнул alertmanager и prometheus. И даже в alertmanager нашлось место этому чуду:
./template/template.go:func (t *Template) ExecuteTextString(text string, data interface{}) (string, error) {
./template/template.go:func (t *Template) ExecuteHTMLString(html string, data interface{}) (string, error) {
./template/template.go:type FuncMap map[string]interface{}
./template/internal/deftmpl/bindata.go:func (fi bindataFileInfo) Sys() interface{} {
Я всегда считал, что наоборот: код, сгенерированный визардами и т.п. — это плохо. Во первых, если внести в него изменения — при повторной генерации они пропадут. Во вторых, сгенерённый код не должен попадать в version control. В третьих, это вообще что-то вроде obj-файла, в нормальных условиях мне не надо его видеть.
Короче: кодогенерация на этапе сборки — нормально, кодогенерация при написании кода — фу-фу-фу.
Ну а "считается" — вроде как считается, что стандартные инструменты кодогенерации лучше самописных, поэтому мы наворачиваем горы темплейтов в C++ там, где код мог сгенерить скрипт из пяти строк...
Когда хочется написать чтото действиетельно сложное, (пытаясь простыми средствами реализовать сложную конструкцию или недостающую) то обычно простой код может превратиться в очень труднопонимаемый.
Язык отличный, жаль только, что команда разработки слишком увлечена впиливанием новых фишечек, а не доведением готовых до стабильного релиза.
Компилятор, как и stdlib всё еще имеют баги, которые препятствуют использованию D в продакшне. Увы, это язык скорее "для души" нежели для работы.
Ну хз, у нас сейчас переписывают на Rust то, что было на D именно из-за нестабильности языка и багов.
В начале разработки(4-5 лет назад) постоянно натыкался на баги в компиляторе/стандартной библиотеке. За последний год если только несколько багов в новой функциональности нашёл.
Единственная проблема крупная на данный момент — консервативный GC, который в моём клиенте умудряется течь, чем несказанно портит жизнь.
Главная проблема комьюнити — они любят трепаться о всяких новых технологиях, но никто не хочет тот же самый GC сделать precise.
У Вас клиент наверное под x86 без 64?
Странно что он течет под x86-64, т.к. по идее проблема "фальшивых" указателей на этой платформе стоит не так остро как на 32 разрядных системах.
Жаль это слышать, надеюсь они наконец-то дотестят и сольют пулл реквест precise gc с мастером.
А сколько примерно объектов в памяти у Вас в среднем? Просто для статистики, хочу лучше понять масштаб проблемы уктечек на стандартном GC
Как можно видеть, даже создание 1 массива без указателей заставляет приложение течь на Windows особенно.
Точное число я не измерял, но из-за этого приложение быстро зажирает под несколько гигабайт, даже если активных данных — 90 МБ.
Это один из важгейших вопросов — но я не понимаю что разработчики D вообще про него думают…
Можете попробовать Nim, там тоже нативный код с опциональным GC, к тому же ведётся работа над деструкторами, кросс-компиляция как в Си (Nim компилируется в Си), никаких виртуальных машин и максимальная производительность (на уровне близком к чистому Си при правильном использовании языка)
Так вот, примерно 90% задач гугла вполне решается на этом самом «С для дураков» без использования кодогенерации, рефлексии, шаблонов, ООП и чего либо еще, и самое главное, что в итоге написанный разработчиками любого уровня код на Go смогут понять любые другие разработчики, даже если они в компании работают сутки и пришли сразу после ВУЗа.
Более того, при уходе всех оригинальных разработчиков из команды проект не придется выбрасывать весь, потому что в нем никто не может разобраться, а получится передать другой команде обычных программистов, и они смогут подхватить его в относительно короткие сроки.
Простота поддержки, простота отладки и поиска ошибок, доступность даже для новичков, и минимальные шансы выстрелить себе в ногу — вот что нужно компаниям уровня Гугла для большей части их кода. А оставшуюся меньшую часть можно писать на чем угодно, хоть на ассемблере, если есть такая необходимость.
примерно 90% задач гугла вполне решается на этом самом «С для дураков»
Откуда такая цифра «90%»? Всякие intelligent personal assistant'ы, беспилотные автомобили и другие AI-проекты, которыми так годится Гугл, входят в эти 90% задач? А Google Chrome?
Из всего вышеперечисленного только Chrome уже написан, и браться его переписывать на Go с нуля нет никакого смысла, все остальное — почему нет? Для хардкорной математики все равно будут использованы готовые библиотеки на С или Фортране (FFI у языка есть, сопряжение хоть и не без проблем, но работает), а для основной grunt work язык Go вполне подходит. Они на нем теперь даже initramfs пишут, так что я не удивлюсь, если напишут и что-нибудь из ML (AI все же слишком сильный термин, на мой взгляд).
Из всего вышеперечисленного только Chrome уже написан, и браться его переписывать на Go с нуля нет никакого смыслаПомимо смысла: писать хороший GUI без богатого ООП очень трудно, хотя и возможно.
AI все же слишком сильный термин, на мой взглядЕсли assistant по замыслу не просто «болталка», вроде Элизы, то AI там нужен мощнее, чем сегодня доступен. Т.о. существующих библиотек явно недостаточно. Нужны собственные научные разработки. Аналогично про беспилотный автомобиль. (Или есть способ прятать внутри живого пилота :)
Помимо смысла: писать хороший GUI без богатого ООП очень трудно, хотя и возможно.Вот как раз тот ООП, который есть в Go для написания GUI подходит куда больше, чем «классический».
Но GUI в Chrome в основном на JavaScript всё равно, так что тут скорее проблема в специфике продукта, а не в том, что GUI на Go сложно писать…
в Go для написания GUI подходит куда больше
Когда в руках молоток, все вокруг — гвозди
Что в модели ООП пропогандируемой С++/C#/Java сделать не так-то просто: недаром все C++ библиотеки так или иначе завязаны на кодогенерацию. Явную (как в MFC или Qt) или неявную (как в WTL — через шаблоны). В CLOS этой проблемы нет и, собственно, своременный GUI разрабатывался на этой обьектной модели ещё до того, как его увидел Jobs.
ООП в стиле CLOS, принятый в Go решает эту проблему абсолютно естественным способом: так как интерфейсы и их реализация напрямую не связаны с типами, которые их реализуют, то страшные трюки в стиле WTL (когда у вас обьект-предок приходится делать шаблонным, чтобы он мог как-то обратиться к потомку) не нужны.
Впрочем, как я уже сказал, полноценных библиотек виджетов, сравнимых с Qt для Go пока нет, так что сказать на 100%, что всё пройдёт гладко и удастся обойтись без костылей типа кодогенерации (а макросы это тоже кодогенерация, пусть и примитивная) — пока нельзя.
Так вот, примерно 90% задач гугла вполне решается на этом самом «С для дураков» без использования кодогенерации, рефлексии, шаблонов, ООП и чего либо еще, и самое главное, что в итоге написанный разработчиками любого уровня код на Go смогут понять любые другие разработчики, даже если они в компании работают сутки и пришли сразу после ВУЗа.
Интересное умозаключение. А на самом деле большинству приходится делать всякие сервисы, высокопроизводительные серверы, машинное обучение итд. В итоге Go стал по большей мере более производительной альтернативой Python для написания несложных демок/скриптообразного кода.
Простота поддержки
Спагетти-кода, который го провоцирует?
простота отладки
В копипасте?
поиска ошибок
Особенно когда бажный код копипастой размазан по всей кодовой базе вместо использования дженериков, ага.
минимальные шансы выстрелить себе в ногу
Ну да, как же… Gotchas and common mistakes in Go
По количеству WAT Go может влёгкую побороться за второе место после JavaScript.
По количеству WAT Go может влёгкую побороться за второе место после JavaScript.Только за третье и то не факт. Первое-второе места забиты намертво за JavaScript'ом и PHP, которые всё никак не выяснят какой из них кривее.
Что-то во времена студенческие я не видел ни одного учебника по С++ (в особенности от авторов языка) в котором хотя бы 4/5 примеров компилировалисьЕсли что-то не скомпилировалось — так это ж хорошо: вы увидите проблему и её исправите. Это вообще не проблема.
А вот если оно скомпилировалось и делает не то, что ожидалось… это бяда. В этом отношении JavaScript и PHP не переплюнуть… хотя C++ и старается, да.
Если что-то не скомпилировалось — так это ж хорошо: вы увидите проблему и её исправите. Это вообще не проблема.
Ну как сказать. Для человека, который свой первый язык учит по этой книге, которая для него основной источник информации и об языке, и о программировании вообще, это может быть большой проблемой.
Для человека, который свой первый язык учит по этой книге, которая для него основной источник информации и об языке, и о программировании вообще, это может быть большой проблемой.Для книги и обучения — да, это проблема. Для языка — нет. И показателем качества языка это не является ни разу (показателем качества книги — таки да).
Если в книге 3/4 примеров не компилируются или крашатся не из-за ошибок автора-издателя, а из-за того, что раз в год в языке происходят сильные изменения, ломающие обртаную совместимость, то к качеству языка это имеет прямое отношение.
Так что да — указатели они, конечно, ужасны и опасны, но до уровня JavaScript/PHP — не дотягивают…
В этом смысле php намного лучше — пространства для косяков меньше, дефекты дизайна постепенно исправляются, глупости перестают интерпретироваться (в отличие от С++).
И кто теперь более читабельный? Я отдам свой голос D. Его код куда более читаемый, так как он более явно описывает действия.
Типичный пример типичной статьи. Какой читабельный? Go. На D написан типичный ворох специальных символов, который надо декодировать каждый раз, когда ты приходишь к куску кода, который первый раз видишь или позабыл. Не говоря о позорной обработке ошибок Правильный вопрос здесь — какой код короче и это действительно D. Почему-то авторы подобных статей все время это путают. Я это прекрасно знаю по C#. Можно очень интересные вещи понаписать, но потом сам же свой код приходится декодировать, потому что он излишне «выразителен».
У нас есть потрясающие системы контроля версий с отличным теггированием и поддержкой версий, которые создатели Go игнорируют и просто копируют исходные тексты.
Есть такая вещь как reproducible builds. Вендоринг зависимостей с этим совместим, а там уже можно уже выбирать — копировать или сабмодулем делать. Просто импорты со ссылками на репозитории в надежде, что во время билда все это успешно скачается и соберется — нет.
Из всей статьи только дженерики адекватная критика. Их недостает и interface{} нужно всеми силами как-то выпиливать из стандартной библиотеки. «культурный багаж Си» так вообще ересь. Инкапсуляция и абстракция достигается через интерфейсы. Еще большая ересь это критика процедурного стиля. Какая разница как он ощущается, если этот стиль программирования понятен и прост для чтения?
Такое ощущение, что автор статьи студент, которому лишь бы поиграться с языком, в котором побольше фич. Человек будто совсем не понимает задач компаний вроде Гугл.
А как эти две вещи связаны? Храните где хотите, но отвяжите пакеты от VCS и заставте людей делать нормальные пакеты с версиями. Вам же его скачать то все равно с внешнего сервиса нужно.
Видимо, гугл считает, что им удобнее вот так. У них, к примеру, весь C++ код хранится в едином репозитории и собирается целиком. Казалось бы, милое дело — выделить модули, каждый модуль разрабатывать независимо в своем репозитории (и секюрность, и размер репо и билда уменьшить, и команды друг другу мержи и билды ломать не будут), стабильные оттестированные релизы пакетировать и выкладывать на тот же внутренний сервер — красота, все по святцам! Но нет, гуглу оказалось объективно лучше держать все в одной куче и жить на "острие".
Есть такая поговорка "ты не гугл". То, что может казаться (и быть) хорошим и приятным для нас с вами, для компании такого размера может был плохим и вредным. В частности, таким вредным они считают версионирование пакетов. Что логично — нетрудно обеспечить совместимость версии, если у тебя собирается пакет, зависящий от еще пары. Когда у тебя собираются тысячи и десятки тысяч пакетов, зависящих друг от друга, то менеджмент совместимых версий превращается в ад.
Когда у вас так много пакетов, у вас все равно ад.
Лично мне кажется, это потому, что google в целом может положить большой болт и тестировать новый функционал на 10% клиентов. Далеко не все компании так могут, так как не монополисты все-таки :)
Я о суммарном размере билда. Если кто-то изменяет библиотеку в модульной архитектуре, то им надо только проверить, что она собирается; сборка, проверка вышестоящих библиотек — это задача тех, кто будет обновлять зависимости. Если кто-то изменяет библиотеку в гугле, то им надо собрать всё, что ее использует, и поправить всё сломавшееся. Гугл, НЯЗ, использует виртуальную ФЗ (как ClearCase MVFS, чтобы не убивать место на HDD и время программистов миллионами файлов из репо), распределенные билды и хитрые билд-системы, чтобы скорость билдов была адекватной, но билды все равно должны быть сделаны и артефакты все равно должны куда-то упасть.
Если кто-то изменяет библиотеку в модульной архитектуре, то им надо только проверить, что она собираетсяА работоспособность кто проверять будет? Пушкин?
сборка, проверка вышестоящих библиотек — это задача тех, кто будет обновлять зависимости.Ага — вот только они, в большинстве случаев, ни разу не заинтересованы в переходе на новую версию если у них всё «и так работает». И в результате вам либо приходится поддерживать 10 версий библиотеки, либо ваша библиотека оказывается 10 раз форкнута и засунута в разные проекты в разных видах. Либо и то и другое одновременно.
Когда у вас между проектами — административная граница, то у вас, в общем-то, нет выбора. Но если её нет — общий репозиторий лучше. Собственно все большие проекты так всегда и собирались — и UNIX, и OS/360 и многие их последователи.
Только GNU/Linux, по политическим причинам, устроен не так. Ну так то — вынужденная мера, а не то, к чему стоит стремиться.
но билды все равно должны быть сделаны и артефакты все равно должны куда-то упасть.А в случае с несколькими проектами и несколькими репозиториями это не так?
А работоспособность кто проверять будет? Пушкин?
Подразумеваем, что работоспособность библиотеки проверяется. Работоспособность или даже собираемость других библиотек — нет.
Но если её нет — общий репозиторий лучше.
Я с этим спорю, что ли? Я говорю, что для "нас с вами" (use-case типичный опен-сорс проектик) удобнее релизы и версионируемость. Для гугла — удобнее монорепозиторий и жизнь на "голове". Go — язык гугла для гугла; логично, что они использовали для зависимостей в Go ту же философию. Поэтому и статья в целом ("мне Go не нравится, а язнаю Dумный программист => Go не для умных программистов"), и тот комментарий, на который я отвечал ("для меня пакеты удобнее => Go нужны зависимости в пакетах, а не голова репозитория"), мне кажутся наивными. Я попытался намекнуть, что у гугла может быть точка зрения, отличная от ТЗ типичного Васи Пупкина, но это не оценили.
А в случае с несколькими проектами и несколькими репозиториями это не так?
Не так, по той причине, что не надо проверять собираемость вышестоящих библиотек. Грубо говоря, в "модульном" варианте выпуск новой версии Abseil влечет за собой билд библиотеки Abseil и прогон ее автотестов. В монорепозитории — (инкрементальный, но) ребилд всего репозитория из тысяч проектов, и прогон всех автотестов всех этих библиотек.
У нас есть некий код, допустим он типизирован и есть внешний интерфейс у импортируемого модуля.
Что в таком случае будет означать изменение версии?
Изменение API модуля? Совсем не обязательно (в semver это предполагает лишь в мажорных версиях). А что тогда? Непонятно, все равно придется проверять, что же изменилось вручную.
Получается, что система версий не типизируется, а значит не автоматизируется.
А значит, весь вопрос уже заключается в том, как вести для людей лог изменений модуля, и я вовсе не уверен что безликие 3 циферки что-то значат.
И логика без цифр такая.
Если это внутреннее изменение (ну, фикс безопасности, к примеру), то и не нужны никакие новые цифры. Если изменение API, то, опять же, компилятор должен ругнуться. Если изменения API нет, но поведение изменилось — нужно менять название пакета, а старый оставить в покое, обратная совместимость, все дела.
Привязка же к коммитам удобна при параллельной разработке, но внутри одной компании.
А эти все куча цифр в некоторых пакетных менеджерах — попытка костылем подпереть отсутствие статической типизации. Все равно не работает.
Версионность выполняет ровно две функции:
- Человекочитаемость. Когда я вижу, что пакет версии 2.1.5, а я использую версию 0.5.1, то мне надо обновится (и вполне вероятно, поиметь проблем). А когда я вижу, что использую коммит 249f069bdf09be30258c604be27fdce51694706f вместо 249f069bdf09be30258c604be27fdce51694706f это мне ни о чем не говорит.
- Исправность. Есть такая штука, что далеко не у всех людей каждый коммит содержит код, который вообще собирается. А каждая версия программы должна собираться, без этого никак.
Более того, версионность позволяет не только жестко фиксировать версии, но так же и задавать диапазоны версионности, что бы у вас не возникало по три-пять разных версий пакетов в одном и тот же проекте.
Ваши рассуждения возможно имели бы смысл, если бы не проблема, например, с внятными именами пакетов и тем, что настолько жесткая обратная совместимость никому не нужна, можно просто не обновляться, раз уж так нужно.
Есть такая штука, что далеко не у всех людей каждый коммит содержит код, который вообще собирается.И вот «с этой штукой» и нужно бороться. Trybots для этого и существуют.
Более того, версионность позволяет не только жестко фиксировать версии, но так же и задавать диапазоны версионности, что бы у вас не возникало по три-пять разных версий пакетов в одном и тот же проекте.Откуда у вас возьмутся «три-пять» версий пакетов (и вообще пакеты, как таковые) при использовании одного репозитория? Или вы про master/release/release-stable и т.п. ветки? Ну так они «внутри себя» все согласованы…
Откуда у вас возьмутся «три-пять» версий пакетов (и вообще пакеты, как таковые) при использовании одного репозитория? Или вы про master/release/release-stable и т.п. ветки? Ну так они «внутри себя» все согласованы…
Давайте начнем с простого. Если вы работаете в google/facebook/another company где все проекты лежат в одном репозитории (на самом деле в google и facebook это уже тоже не так, у них есть open source) и вообще никак не завязаны на open source либы — я за вас рад.
А если же нет, то все очень просто. Вы скачиваете два разных проекта на go себе в репозиторий, и оказывается, что они используют разные версии пакетов, например, для логгирования. Это вполне реальная ситуация, как мне кажется. Вот у вас и две версии пакета для логгирования в рамках вашего проекта.
на самом деле в google и facebook это уже тоже не так, у них есть open sourceУгу — и это позволяет посмотреть как всё устроено.
Вы скачиваете два разных проекта на go себе в репозиторий, и оказывается, что они используют разные версии пакетов, например, для логгирования. Это вполне реальная ситуация, как мне кажется. Вот у вас и две версии пакета для логгирования в рамках вашего проекта.Спасибо что показали наглядно почему зависимости в Go сделаны так, как они сделаны.
Когда вы скачиваете себе два разных проекта к себе в репозиторий, то они обязаны работать с той версией пакетов, что у вас есть. Можете посмотреть в Chrome или Android: пакеты там не дублируются (за исключением резко патологических случаях типа AngularJS vs Angular, или Pel5 vs Perl6 где разные «версии» лучше рассматривать не как разные версии одного и того же, а два совершенно разных продукта).
Вот чтобы такую проблему не решать Go по умолчанию и берёт всё из trunk'а. Если ваши пакеты, в результате, не заведутся и не заработают — ну да, можно попробовать накостылить что-нибудь. Но по умолчанию — все пакеты должны использовать одной версии. Самой последней.
go get
` и скачиваю из транка новые версии библиотек. Оказывается, что в одной зависимости нескольких моих зависимостей сломалась совместимость. Теперь моя разработка стоит пока все эти библиотеки не пофиксят совместимость с той, что внесла изменения?Обращу внимание, что gitflow не отрицает изменений, ломающих совместимость. То есть в мастер вполне может прилететь такая версия.
Я разрабатываю какой-то продукт и использую множество библиотек.И вот в этот момент — у вас уже проблемы: если вы не понимаете что вы используете и допускаете использование бог-знает-чего, то кто ж вам судья, что у вас что-то сломалось?
Обращу внимание, что gitflow не отрицает изменений, ломающих совместимость. То есть в мастер вполне может прилететь такая версия.Ничего не знаю про gitflow. Знаю что в gerrit есть кнопочка rollback, которая откатывает изменения без вытаскивания их в клиент и прочего. Вот именно на случай, когда в trunk попало что-то, что сломает кучу клиентов.
используете и допускаете использование бог-знает-чего, то кто ж вам судья, что у вас что-то сломалось?
То есть, по вашему, идеология Гоу отрицает использование множества библиотек?
Вот именно на случай, когда в trunk попало что-то, что сломает кучу клиентов
Но у меня ведь нету доступа к такой кнопочке независимой библиотеки.
То есть, по вашему, идеология Гоу отрицает использование множества библиотек?Скажем так: она не поощряет порождение программ из кучи мусора. Сторонние библиотеки, разумеется, использовать можно — но желательно понимать при этом что вы делаете и зачем.
Но у меня ведь нету доступа к такой кнопочке независимой библиотеки.Сделайте клон — появится.
Но вообще идеолигия такая, да: trunk'и всех проектов должны быть совместимы.
Если какой-то проект постоянно ломает API trunk'а и заставляет использовать устаревшие версии — то от него лучше отказаться.
Я не зря сказал «зависимость зависимости». То есть, я ставлю какой-то проект, который в свою очередь зависит от другого проекта. Вы предлагаете форкать оба? А потом поддерживать? То есть вместо того, чтобы в языке было нормальное управление пакетами — вы мне предлагаете костылить с форканием проекта, считаете это хорошим решением и, наверняка, будете утверждать, что у вас нету стокгольмского синдрома? Вы смешной.
Вообще говоря версии тут вам ничем не помогут. А поможет фиксация ревизий. Которая через git submodules реализуется куда лучше. Но это не про го вроде.
А вот подобный радикализм действительно встречается. Мне правда не понятно до конца зачем… Может потому, что в го идут те, кто хочет забыть все сложности и «просто писать код».
Про форкание.
Это сказка про рыбу второй свежести. Если библиотека достойная, то ее код уже готов к использованию. А значит, можно просто взять ее код к себе (соблюдая лицензию, естественно). В качественных пакетах всегда есть описание stable-функций, только их и нужно использовать.
А если вам захотелось взять библиотеку с 1000 критических issues, или зависящую от 1000 таких же кривых библиотек, это уже ваши тараканы, наверное, вы один из миллиона некачественных стартапов.
Еще раз, единственная причина, по которой вам может понадобиться обновить библиотеку — неожиданный критический баг. Это не требует никаких версий и уж точно не может ломать совместимость.
Но не надо обвинять инструменты, просто нужно разделять экспериментальный код, прототипы VS рабочий код.
Вот в первом случае, go get вам в руки, semver с ^ самой новой версией.
Во втором, жесткая фиксация, папка vendor с необновляемым кодом зависимостей, ну а в случае semver жесткий номер версии, вплоть до номера патча.
Еще раз, единственная причина, по которой вам может понадобиться обновить библиотеку — неожиданный критический баг. Это не требует никаких версий и уж точно не может ломать совместимость.
В апстриме может оказаться, что это баг пофикшен после какой-то ломки совместимости. Или вообще явного фикса не было, а при реализации очередной фичи "само пофиксилось".
Если библиотека достойная, то ее код уже готов к использованию
это уже ваши тараканы, наверное, вы один из миллиона некачественных стартапов.
Ах, мир розовых плюшевых единорожков. Миленько. Есть или достойные библиотеки с идеальным кодом, или недостойные с плохим. И есть хорошие стартапы, которые пользуются достойными библиотеками и плохие стартапы, которые пользуются недостойными. И благо, что плохие умерли из-за того, что в Гоу такой хороший подход к управлению зависимостей. Святой Гоу очищает. Ох уж эти религиозные фанатики.
Хочу напомнить, что слабость синтаксиса Гоу очень сильно усложняет развитие библиотек (извините, я понимаю, что у вас в репозитории только идеальные библиотеки, которые развития больше не требуют, ибо они сразу написаны в финальной версии, но, очевидно, я из плохих стартапов и мои библиотеки не такие розовые и плюшевые). Так вот — нету ни аргументов-по-умолчанию, ни переопределения методов. В итоге, если мне надо добавить в метод параметр (ну простите, я не идеальный архитектор, не умею писать сразу финальный код) — я не могу вменяемо просто добавить в этот метод параметр не сломав совместимость.
В итоге, если мне надо добавить в метод параметр (ну простите, я не идеальный архитектор, не умею писать сразу финальный код) — я не могу вменяемо просто добавить в этот метод параметр не сломав совместимость.Плохому танцору… Почему это не мешает разработчикам Linux (я имею в виду ядро), MacOS (я имею в виду Classic), Unix, Windows и многих других систем?
Может проблема не в слабости языка, а в банальном нежелании думать о стабильном API заранее? Ну так в этом случае никакой синтаксический сахар не поможет…
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
Уверен, они не рады необходимости тащить ужасное легаси и поддерживать отвратительный синтаксис подобного вида.
Конечно, я понимаю, что можно заранее добавить параметров на все случаи жизни. Можно нанять штатного телепата. Уверен, в вашем мире единорожков именно так и делают.
Уверен, они не рады необходимости тащить ужасное легаси и поддерживать отвратительный синтаксис подобного вида.Разумеется нет. Программисты — они такие. Им всегда хочется что-нибудь переписать с нуля и всё сделать «правильно». Но когда им позволяют это сделать… технологический лидер — становится бывшим.
Конечно, я понимаю, что можно заранее добавить параметров на все случаи жизни. Можно нанять штатного телепата. Уверен, в вашем мире единорожков именно так и делают.Причём тут «мир единорожков»? Про телепатов — не знаю, но «добавить параметров» — это путь Windows. Есть ещё путь Linux/Unix: если нам нужен параметр в dup2, то появляется dup3 (а dup2, разумеется, остаётся).
Есть много подходов, позволяющих сохранить обратную совместимость. И да, бывают случаи, когда без этого не обойтись. Скажем у GlibC вышла версия 1.0 в 1992м году, а в 1997м — вышла версия 2.0, сломавшая совместимость к чёртовой матери. Просто потому что подход, использованный в GLibC 1.0 оказалось практически невозможно использовать с ELFом. Но вот уже GLibC 2.26, вышедшая несколько месяцев назад — вполне совместима с GLibC 2.0, вышедшей в 1997м.
Правда может быть горька, но это правда: поддержка обратной совместимости — штука нетривиальная, но она обходится дешевле (по всем параметрам, не только денежным: речь идёт о надёжности, в первую очередь), чем постоянное изменение публичного API «в поисках совершенства».
Внутренние API, в рамках одного репозитория — другое дело: тут вы не предполагаете, а знаете, причём точно знаете — что нужно вашим клиентам. В случае же с публичным API — вы можете только предполагать… и очень часто — неправильно.
Им всегда хочется что-нибудь переписать с нуля
Я не говорил про «переписать с нуля» вообще-то, это уже ваши домыслы. Поломка обратной совместимости и переписывание с нуля — это совершенно разные вещи. Ну вот как Юнити к примеру. Сколько раз там ломалась совместимость, а они до сих пор на коне?
Но когда им позволяют это сделать… технологический лидер — становится бывшим.
То есть вы мне кинули статью, где описывается, что от Микрософта люди ушли из-за отвратительного API на более приятные технологии и шаг с значительным опозданием уже не спас ситуацию и вы считаете, что это как-то подтверждает вашу теорию?
Более того, это как раз подтверждает мои тезисы — Гоу отвратительный язык, потому что в нем значительно сложнее развивать API без поломки обратной совместимости. В C# я могу добавить метод с тем же названием, но другими параметрами. В C# я могу добавить в метод новый аргумент и добавить ему значение по-умолчанию и этим сохранить совместимость. В го такого нету, это плохой язык. Если мне необходимо добавить второй аргумент в метод — мне ПРИХОДИТСЯ ломать обратную совместимость или давать другое название метода, менее подходящее — типа dup2
То есть вы мне кинули статью, где описывается, что от Микрософта люди ушли из-за отвратительного API на более приятные технологии и шаг с значительным опозданием уже не спас ситуацию и вы считаете, что это как-то подтверждает вашу теорию?Основной тезис статьи: каким бы ни был API — но отказ его поддержки, как правило, приводит к тому, что люди от вас уходят, да. Очень подробно и с примерами. Скажем на тот же Unix/Linux где API нельзя сказать, что уж прям верх совершенства — но он стабилен (если не касаться десктопа, увы).
При этому уходят люди не на более приятный API (на что был рассчёт у создателей C# и всей .NET экосистемы), а на более доступный.
В C# я могу добавить метод с тем же названием, но другими параметрами.А почему вы считаете, что это хорошо?
В C++ это, в принципе, тоже возможно — однако Google рекомендует этого не делать.
Если мне необходимо добавить второй аргумент в метод — мне ПРИХОДИТСЯ ломать обратную совместимостьДа что это за танцор, блин, такой… Никому не приходится — а ему приходится…
или давать другое название метода, менее подходящее — типа dup2Угу — но если мы учтём, что так рекомендуется делать даже в языках, где это необязательно, то эта проблема станет казаться уже гораздо менее острой.
Ситуация с языком Go, в общем, довольно странная: сам язык — действительно достаточно молод, но вот его разработчики — не совсем. Соотвественно хайпа в нём мало… что не мешает ему иметь сообщество разработчиков, сравнимое по размеру с такими языками, как Swift или Ruby… что достаточно удивительно, если вы вспомните, что Google не продвигает его так агрессивно, как Apple продвигает Swift и шума, подобного тому, что поднят вокруг Ruby-on-Rails тоже нету.
Соотвественно хайпа в нём мало… что не мешает ему иметь сообщество разработчиков, сравнимое по размеру с такими языками, как Swift или Ruby… что достаточно удивительно, если вы вспомните, что Google не продвигает его так агрессивно, как Apple продвигает Swift и шума, подобного тому, что поднят вокруг Ruby-on-Rails тоже нету.
Не буду говорить за всех, но лично я узнал о существовании Ruby и Ruby-on-Rails когда игрался с бесплатными системами управления проектами и наткнулся на Redmine. Про Swift слышал чуть-чуть. Зато про Go из каждого "утюга".
И какой он хороший, и какой он плохой. И почему все должны равняться на него, и почему его нужно выбросить, забыть и никогда не вспоминать. Я не знаю насколько он широко используется, но упоминается практически везде.
Так что хайпа вокруг него куда больше, чем вокруг других языков появившихся после 2000 года, как мне кажется.
Делаю go get
и скачиваю из транка новые версии библиотек
А go get нельзя привязать к тегу?
SemVer.
Как раз недавно рассказывал, почему мы отказались от версионирования на фронте.
unsafePtr у шарпа и явы дженерики — это не шаблоны, а полиморфные типы.
khim в C++ шаблоны сбоку прилепили, а потом внезапно обнаружили, что на них можно программировать. D уже проектировался с нормальной поддержкой шаблонов: сообщения об ошибках понятные, стектрейсы ведут в код шаблона, а не в генеренный код и тд.
Потому что создателям go "далеко за ..." и многое им видится "ненужным, излишним", после проходят годики и начинаются писаться статьи вроде Dave Chany и техническом долге go и том, что если язык назвался mainstream, то от него ждут определенных вещей: управление зависимостями, generics. Но создатели языка действуют в формате "если мы сомневаемся, то не делаем ничего и ждем".
Язык golang великолепен в большом поле задач и за год вполне можно взгрустнуть об отсутствии обобщенных типов лишь раз или два(грусть чаще накатывает от фанатов golang). Но вот станет ли язык mainstream — вопрос открытый.
По мне, несмотря на все громкие заявления о том, как будут вводиться изменения в язык (а таких заявлений была масса в 2017 году), развитие языка в 2017 провалилось: невнятный и непродуманный контекст, поломанные плагины (эпичная "бага" с тем, что они не работают нигде, кроме unix), алиасы, sync.map — это скорее недоразумения, чем развитие языка.
Но время покажет.
На D написан типичный ворох специальных символов, который надо декодировать каждый раз, когда ты приходишь к куску кода, который первый раз видишь или позабыл
А можно, пожалуйста, подробнее для тех кто не в курсе?
На D написан типичный ворох специальных символов, который надо декодировать каждый раз, когда ты приходишь к куску кода, который первый раз видишь или позабыл.
Я не пишу на D, но пример там очень понятный, поскольку похож на любой современный язык, кроме Go
ругают Go или рекламируют D?
точно так. только по сниппетам кода понятно, что автор не дотягивает даже до туповатых, а умным себя считает только по факту того, что пишет на D (оказался умнее всех тех, кто не пишет на этом прекрасном языке)
минусующие (как здесь, так и в карме) могли бы и высказать в чём я не прав, аргументами меня задавить, а не так — плюнул в спину и убежал
[/offtop]
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
var err error
reader := os.Stdin
if len(os.Args) > 1 {
if reader, err = os.Open(os.Args[1]); err != nil {
panic(err)
}
}
text, err := ioutil.ReadAll(reader)
if err != nil {
panic(err)
}
fmt.Println(string(text))
}
Насчет «ада копирования». Подобные задачи (как в примере), где нельзя отделаться интерфейсами и приходится копипастить я встречал крайне редко в повседневной практике. Ну и кодогенерацию никто не отменял. В целом, конечно, печально, что нет шаблонов
C зависимостями не все так и плохо. Есть сайт gopkg, на который льют релизы библиотек, есть утилита glide, который может заморозить все библиотеки(сохранив текущие коммиты библиотек в спец файлик), да и сами google уже почти запилили менеджер dep, скоро собираются вносить в свой toolchain
И последнее заявление:
Еще одна скрипучая проблема в том, что Go — это процедурный язык (подобно тихому ужасу Си). В итоге начинаешь писать код в процедурном стиле, который чувствуется архаичным и устаревшим. Я знаю, что объектно-ориентированное программирование — это не серебряная пуля, но это было бы здорово иметь возможность абстрагировать детали в сами типы и обеспечить инкапсуляцию.
Кто же сказал, что go процедурный язык? В чем проблема обеспечить инкапсуляцию? Хоть интерфейсом, хоть просто выносом в другой пакет
Вам доводилось пользоваться кодогенерацией в своих проектах? Довольно муторное, ненадежное и небыстрое занятие. По мне, это сваливание ответственности с компилятора на пользователей, особенно в части гарантий работы.
Стоит в проекте появиться 5-10 активно используемым кодогенераторам и появляется чувство, что он обложен черными ящиками, в которых могут быть ошибки, подчас трудно отлавливаемые — разбирать сгенеренный код бывает нелегко. Вместо одного гарантированного решения задачи с обобщенными типами получается зоопарк из разных пользовательских решений, которые надо поддерживать. Это банально дорого.
Кодогенерация, на мой взгляд, это не решение, скорее затычка "вы так хотели generics — нате!"
Стоит в проекте появиться 5-10 активно используемым кодогенераторам и появляется чувство, что он обложен черными ящиками, в которых могут быть ошибки, подчас трудно отлавливаемые — разбирать сгенеренный код бывает нелегко.А кто вас заставляет кодогенерировать код, который сложно разбирать?
И 5-10 кодогенераторов — это 5-10 скриптов, которые что-то генерируют или 5-10 типов кодогенераторов (ну там ragel, bison, flex и т.д. и т.п.)? 5-10 типов (каждый со своим языком и описанием) — это уже перебор… собственно Go потому и появился чтобы всякие бесконечные Sawzallы не генерить в бешенных количествах…
Ну вот частый кейс для кодогенерации — это обход отсутствия дженериков. Как результат сделать читаемым, если это будут стены шаблонного кода?
Не в защиту (и не в поддержку тоже), просто хотел, размышляя вслух, сказать — это философский вопрос, надо ли вообще читать иной сгенерированный код. Ведь, взять например шаблоны в C++ — они фактически тоже генерируют код, просто на лету и он нигде не сохраняется. И программист работает с ними — приходится держать в голове, как будут инстанцироваться шаблоны.
Но вы работаете с ними как с частью языка. Про это знают тесты, ide, система проверки кода, компилятор и прочее.А ещё оно неплохо интегрировано в язык. Со сторонней кодогенерацией вроде не так.
Зависит от кодогенерации (мы ведь просто о дженериках говорим). Я не настолько хорошо знаю Go, но вроде там есть какой-то инструментарий кодогенерации прямо из коробки. Понятно что, чем сложнее генерация, тем сложнее поддерживать, но вопрос инструментария — это уже частности, я просто говорил, что под капотом разницы нет, в C++ тоже кодогенерация, и программист сгенерированный код не читает, ему приходится пользоваться головой и инструментами, какие есть. Причём и там не всё радужно, шаблонный код часто совсем неподдерживаемый а сообщения об ошибках в шаблонном коде — нечитаемая портянка на весь экран. :)
в C++ тоже кодогенерация, и программист сгенерированный код не читает, ему приходится пользоваться головой и инструментами, какие есть. Причём и там не всё радужно, шаблонный код часто read-only а сообщения об ошибках в шаблонном коде — нечитаемая портянка на весь экран.
Каша из логов шаблонного кода со временем превращается в понятное (пусть и все еще большое) чтиво, сам в это когда-то не верил. Ну и вообще говоря можно получить код с инстанциированными шаблонами (e.g clang -Xclang -ast-print -fsyntax-only ...
), вдобавок отладчики уже давно выводят типы
Ну, весь вопрос — сколько времени понадобится, чтобы превратилась в понятное чтиво. :) По сути это тоже перенос нагрузки на мозг разработчика. Поддержка тоже местами хромает — в CLion у меня, например, целая куча красного кода из-за С++14, если говорить об IDE.
Это я всё к тому, что, когда кричат "кодогенерация — плохо, шаблоны — хорошо", обычно забывают, что шаблоны — это та же генерация, только внесённая в стандарт языка и (в лучшем случае) обложенная тулингом.
сообщения об ошибках в шаблонном коде — нечитаемая портянка на весь экранС появлением концептов это должно уйти в прошлое.
Неправда ли любопытно: кодогенерация — это рекомендуемый путь, но стоит им пойти и начинаются проблемы.
Так в прошлом проекте использовались генераторы: msgpack для aerospike, easyjson, для клонирования объектов, локальный типизированный кэш, генератор клиента на основе api. Некоторые проекты использовали большее число.
Иногда в сгенерированном коде находились ошибки и тут приходится читать этот код. Но кодогенераторы пишут кто во что горазд (в общем-то и понятно — это просто сторонние пакеты, стандарта на них нет) и разбираться в таком хозяйстве долго и дорого.
Для меня, кодогенерация — это перекладывание ответственности и гарантий с больной головы на здоровую.
Для меня, кодогенерация — это перекладывание ответственности и гарантий с больной головы на здоровую.А какая альтернатива? Шаблоны? Ну так это то же самое, только ещё хуже. Потому что там всё точно также генерируется — только неявно. Причём в случае с кодогенерацией вы можете увидеть и понять — что происходит просто открыв сгенерированный код. А если при открытии сгенерированного файла у вас IDE сжирает несколько гиг памяти, то сразу возникает вопрос: а оно точно нам нада — то при использовании шаблонов можно заметить что «что-то пошло не так», только обнаружив, что линкеру 16GB памяти не хватает и нужно ставить 32GB только чтобы получить один бинарник на гигабайт…
Даже на C++ я часто вижу, что люди используют кодогеренрацию, а не шаблоны. Потому что как средство метапрограммирования кодогенерация зачастую — удобнее.
Кто же сказал, что go процедурный язык? В чем проблема обеспечить инкапсуляцию? Хоть интерфейсом, хоть просто выносом в другой пакет
ООП не исчерпывается инкапсуляцией, есть еще абстрагирование, наследование и полиморфизм. С наследованием Go еще хоть как то справляется, а с 2 оставшимися, на мой взгляд — совсем печалька.
Самым главным в программировании я считаю это умение решать задачи. Для решения задачи есть инструменты, и язык это инструмент, в частности, go тот язык, которым быстро можно овладеть. С моей точки зрения нужно использовать инструмент, который быстрее приведёт вас к решению задачи. Кроме того есть ряд известных преимуществ языка GO, например производительность, в отличие от JAVA.
Предположим что вы решаете задачу, ту, которую до вас не решал никто, на каком языке она будет решена — неважно, важно что решена, именно это и определяет потенциал человека. Простой пример, это гений Перельман, который блестяще решил теорему Пуанкаре. В вашем же случае, умные программисты — это программисты с завышенным ЧСВ. Или как это сейчас модно, знающие лайфхаки, в языках, из разряда, как сделать чтобы коврик в туалете не уезжал из под ног. Именно этот набор знаний, вы и выдаёте за ум.
Более 8-ми лет я пишу прошивки под разные микроконтроллеры, и конечно же на си, который я знаю также, как истинные верующие отченаш. Когда нужно организовать простенький сервер, для приема и обработки данных с железки, я часто пользуюсь Go. И здесь вопроси умения возникает мало. Другое дело, когда нужно помочь с реализацией на Java, или Android. Из-за ООП, мне гораздо сложнее, тк мне необходимо продумать по сути архитектуру и структуру классов. Это даётся мне сложнее, но только по тому что это не основной мой навык.
конечно же на си
А почему не на ассемблере? Значит для Вас важен язык. Это, на мой взгляд, противоречит Вашим словам:
на каком языке она будет решена — неважно
Си — это и есть кроссжелезочный ассесблер
Время это очень ценный ресурс.
Поэтому для меня важно умение решать сложные задачи за максимально короткое время. Поэтому в Go я гораздо быстрее разберусь чем в JAVA
Да, можно сейчас на LUA писать «прошивки», но когда нужна прямая работа с памятью (записать такой-то бит в ячейку с таким-то адресом), или когда на практике знаешь, зачем нужны volatile-переменные, С просто удобнее.
Еще одна скрипучая проблема в том, что Go — это процедурный язык (подобно тихому ужасу Си). В итоге начинаешь писать код в процедурном стиле, который чувствуется архаичным и устаревшим. Я знаю, что объектно-ориентированное программирование — это не серебряная пуля, но это было бы здорово иметь возможность абстрагировать детали в сами типы и обеспечить инкапсуляцию.Интересно, что и в упомянутой книге (перевод) слово «объект» встречается три раза, а слово «класс» — только два: первый раз не по делу, а второй раз:
В Go есть несколько различных типов для представления чисел. Вообще, мыНо если верить Википедии, Go — ОО язык (в отличае от Си):
разделим числа на два различных класса: целые числа и числа с плавающей
точкой. (С.15)
Специальное ключевое слово для объявления класса в Go отсутствует, но для любого именованного типа, включая структуры и базовые типы вроде int, можно определить методы, так что в смысле ООП все такие типы являются классами.Из дальнейшего текста вики видно, что принципы ООП понимаются в этом языке довольно своеобразно.
putStrLn $ show $ foldl1 (+) [1, 2, 3.3]
И это будет работать на всех числах которые могут складываться.
Хорошо решим первую задачу:
import System.Environment
import Data.Char
main = getArgs >>= printFile
where printFile (x:_) = readFile x >>= putStr
printFile [] = getContents >>=
readFile . filter (not . isControl) >>=
putStr
Сколько надо затратить труда, чтобы найти это решение на Haskell? А если добавить обработку исключений? Наверно Go это другая сторона медали и вполне имеет право на существование.
Первый пример крайне просто читается, даже человеком со знанием английского (при условии, что он догадается, что str
-> string
и foldl
-> fold
).
Второе уже требует знания монад и ФП, тогда не должно являться большой проблемой.
А что касается времени на написание — то ФП, это, по моему опыту, совсем другие дебри. "Что-то накидать хоть немного работающее и сделать это быстро" — явно не про оное. Так что думаю сравнение не очень уместно. Впрочем, мой опыт может быть и не столь обширен
main = do
args <- getArgs
stdIn <- getContents
let file = if null args
then filter (not . isControl) stdIn
else head args
content <- readFile file
putStr content
Я использовал do нотацию как мог, чтобы упростить. Правда похоже на императивный код? Я его за минуту написал, а над прошлым вариантом задумался, хотя он много лучше
Что касается сравнения GO с другими языками, в частности Java, то Google разработала Go и начала его активно использовать, чтобы отказаться от зависимости от Oracle. Заметьте одну вещь.
- Oracle — Java
- Microsoft — C#
- Google — Go
- Facebook — php (php Hack)
- Apple — Object-C/Swift
Просто крупные игроки не хотят зависеть от какой-то третьей стороны, поэтому делают свой «улучшенный язык», который и продвигают везде.
Сейчас Google замкнет всю свою систему на GO и станет таким же вендор локом, как и Microsoft, как Apple и прочее =)
Можно ли дополнить список Mozilla с её Rust? Кажется, новые языки создают все кто может.
У go не получилось в этом смысле — проект go-mobile скорее мертвый, чем живой, и сам Google для мобильной разработки советует Kotlin.
Просто крупные игроки не хотят зависеть от какой-то третьей стороны, поэтому делают свой «улучшенный язык», который и продвигают везде.
Да нет, не думаю — для Android, например, Google не стал изобретать новый язык программирования, а просто сделал свою реализацию рантайма.
К тому же, потребность в своём собственном языке никак не влияет на дизайн этого языка. Задачи Google не так сильно отличаются от задач тысяч других компаний — (микро)сервисы с максимальной утилизацией CPU и памяти. Это объясняет горутины, например. Стремление к простоте изучения и близости к C тоже понятна, учитывая тысячи работающих у них студентов, хотя для многих других компаний это свойство языка может быть совершенно ненужным или неуместным. А вот замена дженериков на кодогенерацию или использование зависимостей без чёткого версионирования лично для меня ну совсем непонятны.
использование зависимостей без чёткого версионированияДля лучшего понимания можете глянуть, например, доклад Why Google Stores Billions of Lines of Code in a Single Repository. Там и про кодогенерацию вскользь упоминают.
Получается, что отсутствие версионирования зависимостей работает только для Google с их большим монолитным репозиторием, так?
Выходит, что сама концепция «версионирование зависимостей» становится лишней (в том числе для других языков, вроде Java или Python). А разработчикам Go просто не было смысла тратить много времени на ее проектирование и реализацию. Посему и сделали максимально просто (скорее даже примитивно).
Спасибо! А библиотеку для обмазывания цветом и рамочками вывода в консоль какую лучше использовать?
void main(string[] args)
{
try
{
auto source = args.length > 1 ? File(args[1], "r") : stdin;
auto text = source.byLine.join.to!(string);
writeln(text);
}
catch (Exception ex)
{
writeln(ex.msg);
}
}
Тут не нужно перехватывать исключения, ибо их поведение по умолчанию и так эквивалентно тому, что написано в го версии. Так что правильнее так:
void main(string[] args)
{
auto source = args.length > 1 ? File(args[1], "r") : stdin;
source.byLine.writeln;
}
void main(string[] args)
{
[1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}
Этот код можно ещё упростить:
void main(string[] args)
{
[1, 2, 3, 4, 5].reduce!q{ a + b }.writeln;
}
Не говоря уж о том, что в стандартной библиотеке уже есть нужный алгоритм работающий с любыми числовыми типами:
void main(string[] args)
{
[1, 2, 3, 4, 5].sum.writeln;
}
В нем нет новых идей, кроме поддержки параллелизма (который, кстати, прекрасен) и это обидно.Не так уж и прекрасен. Смотря с чем сравнивать )
Не планируется ли введение в рантайм каких то механизмов для идентификации процессов горутин с возможностью их принудительного завершения работы?
По поводу каналов — да, это типичное решение для обмена. Но мне ближе обмен сообщениями между процессами с почтовыми ящиками (заумно — модель акторов). Я не критикую каналы, просто CSP и Акторы — это разные вещи, со своими особенностями. Мне в каналах не нравится то, что канал — это дополнительная сущность; факт того, что отправляющий процесс блокируется, если на той стороне канала не читают, умерла горутина.
Да, я в курсе, что в Go это стараются решить. И я буду рад узнать о том, что решили.
Альтернативы всегда есть, но всегда можно найти причины, по которым эти альтернативы вам не подойдут.
вопрос в том что если горутина умерла навсегда, то рано или поздно все равно придется решать эту проблему.Как?
Оно так не работает)
Попробуйте набросать пример — будет любопытно посмотреть.
Попробуйте запустить на локальной машине и посмотреть итог (в песочнице должен быть deadlock поскольку там только один thread и он будет сразу заблокирован).
Context.Cancel может оповестить горутины о том, что пора `Done()`, но он не может прервать их выполнения. Такого механизма в go нет.
Из этого есть еще одно следствие — Golang неполноценно реализует CSP модель Хоара, поскольку в его модели над процессами для полноты модели определялся рад операций, в том числе и прекращение процесса. А golang этого не умеет и модель CSP реализует лишь частично.
Не совсем верно, до 1.5 вполне была возможность прерывать выполнение горутины. Да, через unsafe, но была, после ее убрали.
Время от времени проверять можно, если операцию можно разбить на отдельные части, между которыми делать проверки. Но как итог мы усложняем код на порядок.
Как правило остается только смириться с тем, что механизма для early stop и сохранения ресурсов нет и не будет.
Как правило остается только смириться с тем, что механизма для early stop и сохранения ресурсов нет и не будет.И слава богу. В C++ мире от pthread_cancel тоже, в общем, отказались.
Не окупает оно себя. Теоретическая красота модели не компенсирует сложности, требуемые для того, чтобы её реализовать — и на практике оказывается, что пользоваться этим всё равно нельзя, так как разработчики разных библиотек не разрабатывают их так, чтобы их можно было безболезненно останавливать.
Вопрос без шуток, любопытно, как в C++ с подобным живут.
Вообще же стоит задуматься над таким фактом: чуть ли не самая отказоустойчивая система всех времён и народов полностью построена вокруг кооперативной многозадачности — так же, как и «ужасное глюкало» Windows 3.x.
В чём разница? Да в том, что если вы используете нормально написанные программы (а тем «бац-бац-и-в-продакшн»), то все «ужасные» проблемы легко разруливаются аккуратным программированием.
Если же об архитектуре не думать от слова «совсем» — то и «модель Хоара» не спасёт.
Да нет в Coroutines TS никаких шедулеров… В каком потоке вызвали resume()
— в том и продолжилась работа.
не очень я понял при чем тут акторы. я говорил о транспорте данных между процессами.arild.github.io/csp-presentation
Слайды 10, 11, 12.
Как показывает опыт Elrang, с акторами то же бывают проблемы.
факт того, что отправляющий процесс блокируется
а в том же Eglang получаем всякие утечки и раздувание очередей, если кто-то много пишет, а другой не успевает вычитывать. Что не бери, все равно получается, что жизнь штука сложная.
Очень сильно устраивает простота языка и еще главное независимость от кучи библиотек. Скомпилировал 1 файл, раскидал по серверам и полетело, не надо кучу зависимостей тащить и потом отлавливать конфликты или баги обновлений.
Если не используются гошные плагины ;)
> Не очень выразительный
Я не знаю, какие еще конструкции имел в виду автор, но в пример он привел исключения. В Go нет исключений, в FAQ есть пункт почему, нет и соответствующих кострукций. Возвращается ошибка, ее надо обработать. В C хотя бы были макросы, чтобы не копипастить, но в Go их нет. Кроме того, в Go у интерфейса error нет даже метода, который вернет код, только строковое представление. Так что если хочешь среагировать на конкретную ошибку — найди ее реализацтию и проверь type cast'ом. Или сравни текст и надейся, что не будет ложного срабатывания на другие ошибки с похожим текстом. Конечно, внутри приложения обычно все-таки используются типизированные ошибки, а не интерфейс error.
В сравнении с исключениями, где тебе достаточно знать тип исключения, на который ты хочешь среагировать, выглядит уныло. С другой стороны, ты не обязан знать, что конкретно может пойти не так, и ловить все ошибки по типу, а реагировать на фейл конкретного метода.
> Ад копирования
В Go нет типообезопасного обобщенного программирования. Когда будет — неизвестно. Копипаста, боль, страдания.
> Простой обход системы типов
Увы, если нет обобщенного программирования на этапе компиляции, оно будет на этапе исполнения. Ничего удивительного.
> Горе управления зависимостями
> нельзя указать версию
В стандартном инструменте go get нельзя указать версию, в менеджерах зависимостей glide и govendor — можно. Скоро обещают ввести стандартный менеджер зависимостей. Зависимости выкачиваются в поддиректорию /vendor для каждого пакета. Тут как раз все удобно.
> Культурный багаж из Си
> нет новых идей, кроме поддержки параллелизма
Непонятно, новых по сравнению с C или со всеми другими языками. Утиная типизация в компилируемом языке? Cтатически слинкованная стандартная библиотека и GC без зависимостей на libc размером в ~1МБ? Трансляциия в язык ассемблера целевой платформы, благодаря чему кросс-компиляция встроена в стандартную поставку? Отличий от С еще больше.
> Простота для собственной выгоды
Мы тут горшки обжигаем. После кода на Go, приятно сесть и написать, например, немного обощенного кода на C++. Но потом, возможно, его перепишут другие люди, и не раз. Которые тоже горшки обжигают, и у них дедлайны, и голова болит, и дома надо быть в 8. И мне придется его отлаживать.
А разве в первом примерно когда идет считывание файла, не происходит ли там передача потока в другую goroutine? Сам go ещё не знаю, но насколько мне представляется схожесть с nodejs, во время считывания файла, и ожидания ответа от HDD, возможно фоновое выполнение другой подзадачи. И в таком случае, go сильно выигрывает у D и у C, т.к. передачу контекста там реализовывать сложнее чем в го.
Go с Javascript (и нодой) сравнивать по языковым конструкциям некорректно, поскольку в JS многопоточность не подразумевалась, и авторам пришлось совать в язык неявные async-костыли, чтобы не вешать нарисованный в том же потоке интерфейс. А у Go многопоточность самая обычная — ее нет, если явно в коде не попросить.
(Ну да, если придираться, то системных потоков там несколько, но у программиста к управлению ими доступа почти нет, и с точки зрения программы логический поток у нее один)
- Если молоко прокисло, значит надо его пить
- Если появились статьи о вреде курения, надо купить сигарет
- Если появились статьи почему Go плох, значит уже стоит обратить на него внимание
- Если девушка умерла, самое время сделать ей предложение
Справедливости ради, юзеры просят не многого, но очевидного, без чего mainstream язык обречен:
— Generics
— Управление зависимостями
— Более настойчивая система ошибок
Удручает, что движения в этих направлениях незаметно. Ну разве что dep пилят, но предварительное знакомство не обрадовало.
Что лично я наблюдал где-то месяц назад: медленный (https://github.com/golang/dep/blob/master/docs/FAQ.md#why-is-dep-slow), клонирует по новой зависимости, если в них есть обновления. Если добавят кэширование, то будет приличнее.
Второе — сырой, иногда валится без причины.
Прошло много лет, и миллионы обезьянок действительно прыгают и стараются — одни код пишут, другие код ломают, третьи делают инструментарий — красота!
Его просто читать и просто использовать.
Разве не это главное для синтаксиса?
Он крайне многословный, невыразительный и плох для умных программистов.
Кмк это всегда баланс между читаемостью и выразительностью.
С одной стороны я хочу как можно лучше выразить идею в коде, с другой — чтобы язык не позволял вливать в код все оттенки личного чувства прекрасного каждого программиста (иначе задолбаешься разбираться в чужом коде или кто-то — в твоем).
Этот баланс конечно тоже лично у каждого свой (если конечно о нем задумаешься), но в Go он уж слишком смещен в
Это прям как лакмусовая бумажка.
Те, кто с языком работал основательнее, резонно замечают, что есть только проблема с дженериками, остальное — сделано довольно хорошо.
Те, кто с языком работал основательнее, резонно замечают, что есть только проблема с дженериками, остальное — сделано довольно хорошо.
Лол. У него проблем выше крыши. Вот недавно в комментарии описывал, что в нем совершенно уродские теги/аннотации/декораторы, словно их придумывал человек с сильным отставанием в развитии. Это ведь не относится к Дженерикам? ;)
Интерфейсы в Go — вот главная инновация, я бы сказал козырь перед другими языками.
О том, что GNU C++ signatures (которые и явились прототипом интерфейсов в Go) «срисованы» с Haskell type classes — сами разработчики говорят. Но вот «abstract class в C++, interface в Java/Delphi/PHP/остальных ООП языках» — это совсем о другом.
Серьёзно? В каких из этих языков реализация интерфейса пишется независимо от самого интерфейса и, в принципе, может быть «залита» в VCS до того, как туда попадёт описание самого интерфейса?
Ну, вот с Вики список: Prolog, D, Perl, Smalltalk, Python, Objective-C, Ruby, JavaScript, TypeScript, Groovy, ColdFusion, Boo, Lua, Go.
И это, скорее всего, далеко не все. И компилируемые среди них таки есть.
Это называется утиная типизация и в этом тоже нет ничего нового.
Ну вот ни разу не было необходимости писать реализацию интерфейса раньше его самого…
Я бы этот момент рассматривал как небольшую странность а не как ключевую особенность.Если это не «ключевую особенность», а «небольшая странность», то почему вокруг добавления подобного подхода в C++ сломано столько копий?
Ну вот ни разу не было необходимости писать реализацию интерфейса раньше его самого…Вопрос не в написании реализации интерфейса раньше описания интерфейса, а во вполне эквивалетной этому возможности по реализации интерфейса, на описание которого вы, при написании вашего класса, вообще не смотрели. Какие-нибудь интерфейсы типа BasicLockable или Swappable, как правило, оказываются реализованы без явного намерения их реализовать.
lock
и unlock
связаны с тредами, а не совершенно другая логика класса Gate
?А как вы поймете, что lock и unlock связаны с тредами, а не совершенно другая логика класса Gate?Никак — и в этом весь смысл. Совершенно неважно: захватывает
lock
какой-нибудь mutex
или тыкву. Важно, что lock
— захватывает ресурс, а unlock
— его освобождает. Для класса, которому нужен BasicLocable — этого достаточно.lock
— захватывает, а не замыкает дверь? Ну в том плане, что у него бизнес-логика совершенно из другой области, никак не связанная с тредами. И unlock срабатывает только если у пользователя есть права доступа к двери.Речь же не идёт о том, чтобы писать программы случайным образом тасуя компоненты — это и на любом другом языке к добру не доведёт — а о том, чтобы писать программы с удобством.
Так вот описывать интерфейсы там, где они потребляются и не заставлять из описывать там, где они реализуются — просто удобно.
implements BasicLocable
и в этом ваше удобство?implements BasicLocable
— это фигня. Главное — что я при этом не вытаскиваю и не включаю в проект модуль, где этот BasicLocable
описан.То есть я могу поддержать все интерфейсы требуемые MySQL'ем, PostgreSQL'ем и, скажем, Oracle'ом одновременно — и не втягивая в проект библиотек MySQL'я, PostgreSQL'я и Oracle.
Причём для этого мне не нужно «городить огород» с генераторами фабрик, как в Java, а несоотвествие типов таки будет выявлено в момент сборки, а не в рантайме.
Там и тогда, где это можно использовать — там можно и протестировать.
Вы не поверите, но в природе существуют ещё программисты, способные написать код так, что его не требуется перетестировать по 100 раз после простейших изменений.
То что я не пишу implements BasicLocable — это фигня. Главное — что я при этом не вытаскиваю и не включаю в проект модуль, где этот BasicLocable описан.
Это скорее вопрос корректного разбиения на модули. Так-то ничего страшного во включении хоть сотни «заголовочных» модулей нет кмк.
Пример с разными СУБД — немного некорректен на мой взгляд — это все же иные интерфейсы, специфичные для каждой БД, а выше речь шла о неких общих, без специализации. Т.е. применимо к БД это будет некий интерфейс доступа к БД, на который будут опираться как ваша программа, так и коннекторы БД.
На практике, впрочем, с подобными проблемами (когда у вас не просто есть два разных интерфейса с одинаковыми сигнатурами, но и из ещё реально нужно различать в рантайме) приходится сталкиваться редко. А вот необходимость опционально поддержать разные вещи — встречается часто. Потому Go «заточен» под второе, а не под первое.
Модуль использующий интерфейс обязан про него знать (иначе, как бы, непонятно как его использовать). Модуль
предоставляющий интерфейс — не обязан (программисту про него знать, в общем, полезно — но тоже не всегда обязательно).
Но если у вас адекватный менеджер зависимостей в рамках вашего языка, то в чём проблема?Проблема в лицензиях. Может в вашей домашней «генточке» это и нормально, когда upgrade одного компонента вытягивает пяток других, которые ему нужны только, чтобы из них вынуть описание нужно им интерфейса.
Но в больших компаниях принято на каждый новый компонент полочать «добро» от лигала (и не только). То есть если очередная версия захочет вытащить клиента MS SQL только для того, чтобы реализовать описанный в этом клиенте интерфейс — то вам придётся получать добро на добавление в ваш репозиторий этого самого клиента MS SQL!
Что может растянуться на недели и месяцы.
С прямой все понятно — если нужно реализовать интерфейс для MS SQL — значит, надо добавлять зависимость от их клиента. Это нужно даже в go, потому что во всех случаях кроме самых тривиальных понадобится описание структур данных.
Что же до транзитивной — то тут вовсе не обязательно выкачивать все подобные зависимости. В тех же Java или C# если вы не пользуетесь теми классами которые реализуют интерфейс MS SQL — то и описание интерфейса тоже не нужно!
using C++20;
Чтобы порождался код совместимый со старыми обьектными модулями, но при этом на уровне исходного кода какие-то фичи бы выключались.
Тогда от них можно было бы отказываться постепенно…
А так — каждый новый стандарт делает вид, что он существует «в вакууме», старых программ «типа нет» — но при этом мы всё время о них думаем… Шизофрения какая-то…
Тем самым они не дают возможности постепенно убирать из него фичи: вначале делаем возможность фичу выключить, потом делаем возможность её включить, но выключаем по умолчанию, потом — отказываемся от неё совсем.
using C++17;
в начале файла.Хотя, справедливости ради, мне рыдать хочется что теперь реализации методов по-умолчанию привносят в интерфейсы C# :( в Java они уже давно имеются.
А оно надо? Я бы предпочёл, чтобы компилятор имел возможность проверить, всё ли я определил и тайпчекается ли оно, в точке определения реализации интерфейса.Ну значит вам больше понравятся другие языки. У обоих подходов есть плюсы и минусы.
А вообще это сурово пахнет концептами C++, а соответствующий пропозал появился до релиза Go, ЕМНИП.Я бы сказал, что Go'шный ООП очень сильно пахнет GNU C++ сигнатурами, которым, если бы они были людьми, уже можно было пить и курить — это ж почти четверь века назад было всё релизовано! Не исключу, что и раньше, чем в Haskell подобные вещи пробрались, но точно не скажу — это нужно целое расследование проводить…
И да — некая схожесть с концептами и type class'ами наблюдается, но в целом — это не совсем то.
В гошных тайпклассах есть, кстати, multiparam type classes? Fundeps?Вроде бы нет, но на 100% не уверен.
В случае Go сам тип T, реализующий интерфейсы, таблицы виртаульных методов не содержит никогда, поэтому когда мы не используем полиморфное поведение, не будет лишнего жира. Когда T передаётся как интерфейсный тип, вот там уже будет боксинг с аллокацией.
Насколько это хорошо или плохо — не хочу полемизировать, но подчеркнуть, что это не «Как в C++», всё-таки захотелось.
Чойта? -fdevirtualize
и -fdevirtualize-speculatively
в компиляторах C++
придумали не вчера.
Про спекулятивную девиртуализацию поищу.
Anyway, в Go можно явно сказать: «Тут мне полиморфный тип, а тут просто структру T».
В C++ же полиморфность является свойством самого типа T. Right?
Возможно мне действительно не хватит знаний продолжить диалог, но стало любопытно: а если член структуры является полиморфным типом, разве компилятор сможет в каких-то случаях избежать перерасхода памяти?Нет. Таблица виртуальных методов будет прописана всегда, конструкторы/деструкторы тоже будут вызываться всегда.
В любом случае тут как бы «небольшие накладные расходы всегда» vs «никаких накладных расходов если полиморфность не нужна, но весьма внушительные — если нужна».
Было бы интересно сравнить на реальных задачах, но на маленьких примерах всё очевидно, а большой проект для этого делать дважды вряд ли кто будет…
Anyway, в Go можно явно сказать: «Тут мне полиморфный тип, а тут просто структру T». В C++ же полиморфность является свойством самого типа T. Right?
Угу. -fdevirtualize
может вырезать лишний жир, если полиморфное поведение не используется. Но… это соооовсем не идеально.
Go использую с версии 1.8, не знаю что было раньше, но то что сейчас — хорошо работает.
Программы, в основном, получаются легко читаемые, а писать небольшие утилитки — в радость, а с горутинами — так вообще шик.
Порог вхождения не высок, но месяца за три — только начинаешь въезжать в идею создания Go, хотя первый микросервис удалось написать дня через два после первого `Hello world`
Вообще не понимаю этих обсираний, особенно от людей, толком не разбирающихся в обсираемом языке.
А что из описанного в статье поменялось?
Ну и но месяца за три — только начинаешь въезжать в идею создания Go,
— это что-то дофига, на уровне с erlang и haskell. Вроде же все наоборот утверждают, что Go очень простой.
Вроде же все наоборот утверждают, что Go очень простой.А тут другая проблема: он простой — но другой. Человек, не видевший ничего, кроме GW-BASIC'а его легко освоит. А людям, работающим на других языках, приходится переучиваться. Это занимает время.
Позвольте с вами не согласится. Если он другой и на него нужно переучиваться, значит он не простой.
Вот python простой, что бы начать писать на нем какой-то рабочий код достаточно вводной статьи и 15 минут времени. Да, качество кода будет так себе и все прочее, но в целом оно неплохо работает.
Я в течении этого времени только искал, как же нормально задать переменную окружения навсегда.
Если он другой и на него нужно переучиваться, значит он не простой.Нет. Так у вас все языки, кроме C++, сложными станут. Потому что с ним я работаю последние 10 лет и мне в нём всё понятно. А чтобы освоить даже Lua — потребуется время.
Простота/сложность языка определяется временем, которое требуется на его освоение человеком, который не знает ни одного языка программирования. С этой точки зрения — Go и JavaScript просты. А C++ и Haskell — сложны.
А вот если вы уже имеете опыт работы на другом языке программирования — то тут ситуация может немного другой оказаться.
Вот python простой, что бы начать писать на нем какой-то рабочий код достаточно вводной статьи и 15 минут времени. Да, качество кода будет так себе и все прочее, но в целом оно неплохо работает.Та же самая ситуация и с Go, как бы.
И в обоих случаях вам потребуется несколько месяцев, чтобы начать писать идеоматичный код. Поначалу вы будете писать код в стиле того языка, который использовали до того — и плеваться, когда будете упираться в разные «странности».
Я в течении этого времени только искал, как же нормально задать переменную окружения навсегда.Что значит «задать переменную окружения навсегда», как это сделать в Python'е и почему в Go это сделать сложнее?
Что значит «задать переменную окружения навсегда», как это сделать в Python'е и почему в Go это сделать сложнее?
Это я про GOPATH и GOROOT. Вот в ubuntu это все еще не делается из под коробки, а значит надо устанавливать самому. А я в то время не знал как.
А в python просто, pip install package
и погнали. Потом, конечно, больно, но все же можно)
А в python просто, pip install package и погнали.Серьёзно? А давайте я вам SunOS какой-нибудь постарше дам питона — и вы на ней
pip install package
без установки PYTHONPATH и PYTHONHOME погоните. А я посмеюсь.Или, если SunOS не нравится — могу дать MacOS и скрипт на Python3.
Это я про GOPATH и GOROOT. Вот в ubuntu это все еще не делается из под коробки, а значит надо устанавливать самому. А я в то время не знал как.И что — это делает язык сложным? Python точно так же требует установки переменных окружения. Просто в Ubuntu это уже сделали за вас, на этапе сборки, собственно, питона.
Почему так же не сделать для го то?
Go build и то, что близ него — это довольно низкоуровневые вещи.
Мне не очевидно, насколько github.com/constabulary/gb юзабелен, но скорее всего со временем появится хороший project-based тул, который станет тем самым pip для Go.
У меня отец физик, и ему хаскель (и интуитивный подход к вычислению программы как к редукции графа) будет сильно понятнее, чем Go или JS.Вы бы ещё про математиков вспомнили!
Да, есть люди, которые функциональный подход воспринимают легче, чем императивный. Но где-то для 90% программистов (и, боюсь, для 98%-99% людей вообще) иперативная «поваренная книга» воспринимается проще.
Даже несмотря на то, что в школе, вроде как, математике учат всех…
По моему, в статье автор не высказал никакой причины, чтобы считать язык отстоем.
Это скорее делается акцент на эмоции. Если GO является для него простым и для дураков, то наверно у него проблемы с усвоением синтаксиса какого-то сложного языка. Лично по моему С++ и Java также являются простыми и не сложными языками, это дело привычки и опыта.
От языка требуется чтобы он решал те или иные задачи, не важно как, с помощью дженериков как в С++ и Java, или с помощью интерфейсов как в GO.
Лично по моему С++ и Java также являются простыми и не сложными языками, это дело привычки и опыта.
Насчёт С++ есть просто отличное выступление Скотта Мейерса на конференции, посвящённой языку программирования D. Обязательно посмотрите, очень рекомендую. Джава по сравнению с С++ существенно проще, но по сравнению с Go в смысле количества сущностей — конечно сложнее.
Язык можно описать как Си с дополнительными колесиками(ориг.: training wheels).
Трёхколёсный велоСипед.
Вот, к примеру, решение той же задачи на D:Дочитал до этой строчки и всё стало ясно. Ох уж эти войны за влияние.
hackernoon.com/why-senior-devs-write-dumb-code-and-how-to-spot-a-junior-from-a-mile-away-27fa263b101a
Не всегда шаблоны — хорошо.
Во-первых, в результате использования шаблонов будет сгенерировано столько же кода, сколько и в результате использования копирования.
Во-вторых, при использовании копирования копии можно дорабатывать в индивидуальном порядке, что невозможно при использовании шаблонов.
В третьих, компиляция из шаблонов идет гораздо дольше, чем копий.
В четвертых, отладка копий выглядит проще.
- Автоматизация нужна, чтобы уменьшать человеческие ошибки, шаблоны — та же степь. Написали правильно — везде правильно, неправильно — везде неправильно
- Тогда в этом случае а) не нужны шаблоны б) обобщение на слишком большой кусок кода (e.g темплейт нужен не на метод, а его половину)
- Согласен, но впрочем шаблоны помощнее инструмент
- Выше веткой обсудили(-ают), если коротко: тоже самое
Во-вторых, при использовании копирования копии можно дорабатывать в индивидуальном порядке, что невозможно при использовании шаблонов.
Это не так. Можно написать generic-реализацию для всех типов и для конкретного типа отдельно.
Осваиваем запасную профессию, посоны. Пока не поздно. Не, я серьёзно. Эпоха элитарности программистов неумолимо приближается к закату.
Простота языка нужна не только для легкого обучения и передачи кода между программистами. Она еще и позволяет делать эффективную оптимизацию во время компиляции, не затрачивая на это время Когда я писал свой интерпретатор, на своей шкуре прочуствовал силу и мощь авторов Go в этом вопросе.
И кто теперь более читабельный? Я отдам свой голос D. Его код куда более читаемый, так как он более явно описывает действия.
Скажите, вы всерьез считаете, что тернарный однострочник
auto source = args.length > 1 ? File(args[1], "r") : stdin;
более читаем? По-моему, нет. Это — неструктурированная/плохо структурированная (с точки зрения визуального формализма) каша, следовательно, нечитаемый код.
auto text = source.byLine.join.to!(string);
А это и вовсе подтасовка — вы пользуетесь библиотечным вызовом, в то время как в примере на Go выписали чтение руками. Вы так же можете на Go спрятать это в другой модуль и вызывать одной строкой.
Это у вас подтасовка. В D используются абстрактные алгоритмы из стандартной библиотеки, которые можно применять к любым подходящим типам данных. А в Go вам придётся для каждой комбинации типов написать отдельную реализацию. И от того, что вы заметёте их под ковёр и будете вызывать одной строкой — суть не поменяется.
Это у вас подтасовка. В D используются абстрактные алгоритмы из стандартной библиотеки, которые можно применять к любым подходящим типам данных
Нет, вы перескакиваете на другую тему. Проблема типов — отдельно, сокрытие кода — отдельно. Здесь ставился вопрос о читаемости, а не простоте поддержания. Так что подтасовка у автора — для сравнения читаемости он должен запихнуть реализацию в библиотеку и вызывать ее одной строкой. То, что таких реализаций будет миллион — вопрос совсем из другой оперы.
Вы пытаетесь утвердить тезис о том, что «Go плох», а я лишь пишу о том, что аргумент автора о нечитаемости — дутый. Это не значит, что Go крут или более читаемый, чем D.
На любом языке можно написать идеально читаемую программу с вызовом всего одной библиотечной функции:
doEveryThingRight()
Значит ли это, что читаемость всех языков одинаковая?
Язык Go является хорошим выбором основного языка программирования в команде, где большинство разработчиков не хотят замарачиваться тонкостями языка, такого как, например, C++, а хотят просто валять код. В такую команду не сложно набрать людей, потому как Go можно выучить за пару недель, и он не требует семь пядей во лбу. Да, код, который напишут такие разработчики не будет блестать гениальностью, и в нем будет много примитивных багов, которых можно было бы избежать при использовании более выразительного языка. Зато разработчики будут взаимозаменяемые, и если кто-то уйдёт, на его замену можно взять двух других.
Почему дизайн Go плох для умных программистов