Статья написана, как ответ на опубликованную ранее статью-антипод.


image


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


Создан для слабых программистов?


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

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


Даже начинающие программисты начинают выдавать вполне приличный код спустя неделю-другую. Книга, по которой я изучал Go называется “Программирование на языке Go” (автор Марк Саммерфилд). Книга весьма хороша, в ней затрагиваются многие нюансы языка. После неоправданно усложненных языков таких, как Java, PHP, отсутствие магии действует освежающе. Но рано или поздно у многих ограниченных программистов возникает желание использовать старые методы на новом поприще. Действительно ли это так необходимо?


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


Так для чего же он был создан таким простым? Вот пара цитат Роба Пайка:


Ключевой момент здесь, что наши программисты не исследователи. Они, как правило, весьма молоды, идут к нам после учебы, возможно изучали Java, или C/C++, или Python. Они не в состоянии понять выдающийся язык, но в то же время мы хотим, чтобы они создавали хорошее ПО. Именно поэтому язык должен прост для понимания и изучения.

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

Мудрые слова, не правда ли?


Артефакты простоты


Простота — необходимое условие прекрасного. Лев Толстой.

Быть простым — это одно из важнейших стремлений в любом дизайне. Как известно, совершенный проект это не тот проект, куда нечего добавить, а тот – в из которого нечего удалить. Многие считают, что для того, чтобы решить (или даже выразить) сложные задачи, необходим сложный инструмент. Однако, это не так. Возьмем к примеру язык PERL. Идеологи языка считали, что программист должен иметь как минимум три разных пути для решения одной задачи. Идеологи языка Go пошли другим путем, они решили, что для достижения цели достаточно одного пути, но действительно хорошего. Такой подход имеет под собой серьезный фундамент: единственный путь легче учится и тяжелей забывается.


Многие мигранты жалуются, что язык не содержит элегантных абстракций. Да, это так, однако это и есть одно из главных достоинств языка. Язык содержит в своем составе минимум магии – поэтому не требуется глубоких знаний для чтения программы. Что же касается многословности кода, то это и вовсе не проблема. Хорошо написанная программа на языке Golang читается по вертикали, практически без структурирования. Кроме того, скорость чтения программы как минимум на порядок превосходит скорость ее написания. Если учесть, что весь код имеет единообразное форматирование (выполненное при помощи встроенной команды gofmt), то прочитать несколько лишних строк вообще не является проблемой.


Не очень выразительный


Искусство не терпит, когда стесняют его свободу. Точность не входит в его обязанности.

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


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


package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
)

func main() {

    flag.Parse()

    scanner := newScanner(flag.Args())

    var text string
    for scanner.Scan() {
        text += scanner.Text()
    }

    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }

    fmt.Println(text)
}

func newScanner(flags []string) *bufio.Scanner {
    if len(flags) == 0 {
        return bufio.NewScanner(os.Stdin)
    }

    file, err := os.Open(flags[0])

    if err != nil {
        log.Fatal(err)
    }

    return bufio.NewScanner(file)
}

Решение этой же задачи на языке D хотя и выглядит несколько короче, однако, читается ничуть не проще


import std.stdio, std.array, std.conv;

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);
    }
}

Ад копирования


Человек носит ад в самом себе. Мартин Лютер.

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


package main

import "fmt"

func int64Sum(list []int64) (uint64) {
    var result int64 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int32Sum(list []int32) (uint64) {
    var result int32 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func main() {

    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(int32Sum(list32))
    fmt.Println(int64Sum(list64))
}

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


package main

import "fmt"

func Eval32(list []int32, fn func(a, b int32)int32) int32 {
    var res int32
    for _, val := range list {
        res = fn(res, val)
    }
    return res
}

func int32Add(a, b int32) int32 {
    return a + b
}

func int32Sub(a, b int32) int32 {
    return a - b
}

func Eval64(list []int64, fn func(a, b int64)int64) int64 {
    var res int64
    for _, val := range list {
        res = fn(res, val)
    }
    return res
}

func int64Add(a, b int64) int64 {
    return a + b
}

func int64Sub(a, b int64) int64 {
    return a - b
}

func main() {

    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(Eval32(list32, int32Add))
    fmt.Println(Eval64(list64, int64Add))
    fmt.Println(Eval64(list64, int64Sub))
}

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


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


import std.stdio;
import std.algorithm;

void main(string[] args)
{
    [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}

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


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


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


Обобщенное программирование в ряде случаев дает нам неоспоримую выгоду. Это наглядно иллюстрирует нам пакет sort. Так, для сортировки любого списка нам достаточно реализовать интерфейс sort.Interface.


import "sort"

type Names []string

func (ns Names) Len() int {
    return len(ns)
}

func (ns Names) Less(i, j int) bool {
    return ns[i] < ns[j]
}

func (ns Names) Swap(i, j int) {
    ns[i], ns[j] = ns[j], ns[i]
}

func main() {
    names := Names{"London", "Berlin", "Rim"}
    sort.Sort(names)
}

Если Вы возьмете любой open source проект и выполните команду grep "interface{}" -R, то увидите, как часто используются путые интерфейсы. Недалекие товарищи сразу же скажут, что все это из-за отсутствия дженериков. Однако, это далеко не всегда так. Возьмем к примеру язык DELPHI. Несмотря на наличие у него этих самых дженериков, он содержит специальный тип VARIANT для операций с произвольными типами данных. Аналогично поступает и язык Go.


Из пушки по воробьям


И смирительная рубашка должна соответствовать размеру безумия. Станислав Лец.

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


Роб Пайк предупреждает нас:


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

Википедия говорит нам следующее:


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

Однако, как известно, за все необходимо платить. В данном случае это:


  • сложность написания программ
  • скорость исполнения программ

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


Культурный багаж из Си? Нет, из ряда языков!


Вместе с состоянием наследникам оставляют и долги.

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


Синтаксис


Прежде всего, синтаксис грамматических конструкций основывается на синтаксисе языка Си. Однако, существенное влияние оказал и язык DELPHI. Так, мы видим, что полностью убраны избыточные скобки, так сильно снижающие читаемость программы. Также язык содержит оператор ":=", присущий языку DELPHI. Понятие пакетов заимствовано из языков, подобных ADA. Декларация неиспользуемых сущностей заимствована из языка PROLOG.


Семантика


За основу пакетов была взята семантика языка DELPHI. Каждый пакет инкапсулирует данные и код и содержит приватные и публичные сущности. Это позволяет сокращать интерфейс пакета до минимума.


Операция реализации методом делегирования была заимствована из языка DELPHI.


Компиляция


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


Высокоуровневые конструкции


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


  • Строки
  • Хэш таблицы
  • Слайсы
  • Утиная типизация позаимствована из языков, подобных RUBY (которую, к сожалению, многие не понимают и не используют на полную мощь).

Управление памятью


Управление памятью вообще заслуживает отдельной статьи. Если в языках типа C++, управление полностью отдано на откуп разработчика, то в более поздних языках типа DELPHI, была использована модель подсчета ссылок. При таком подходе не допускалось циклических ссылок, поскольку образовывались потерянные кластера, то в Go встроено детектирование таких кластеров (как в C#). Кроме того, по эффектвности garbage collector превосходит большинство известных на текущий момент реализаций и уже может быть использован для многих real time задач. Язык сам распознает ситуации, когда значение для хранения переменной может быть выделено в стеке. Это уменьшает нагрузку на менеджер памяти и повышает скорость работы программы.


Параллельность и конкурентность


Параллельность и конкурентность языка выше всяких похвал. Ни один низкоуровневый язык не может даже отдаленно конкурировать с языком Go. Справедливости ради, стоит отметить, что модель не была изобретена авторами языка, а просто заимствована из старого доброго языка ADA. Язык способен обрабатывать миллионы параллельных соединений задействуя все CPU, имея при этом на порядок реже типичные для многопоточного кода сложные проблемы с дедлоками и race conditions.


Дополнительные выгоды


Если это будет выгодно — бескорыстными станут все.

Язык также предоставляет нам также ряд несомненных выгод:


  • Единственный исполнимый файл после сборки проекта существенно упрощает deploy приложения.
  • Статическая типизация и вывод типов позволяют существенно сократить число ошибок в коде даже без написания тестов. Я знаю некоторых программистов, которые вообще обходятся без написания тестов и при этом качество их кода существенно не страдает.
  • Очень простая кросс-компиляция и отличная портабельность стандартной библиотеки, что сильно упрощает разработку кросс-платформенных приложений.
  • Регулярные выражения RE2 потокобезопасные и с предсказуемым временем выполнения.
  • Мощная стандартная библиотека, что позволяет в большинстве проектов обходиться без сторонних фреймворков.
  • Язык достаточно мощный, чтобы концентрироваться на задаче, а не на методах ее решения и в то же время достаточно низкоуровневый, чтобы задачу можно было решить эффективно.
  • Эко система Go содержит уже из коробки развитый инструментарий на все случаи жизни: тесты, документация, управление пакетами, мощные линтеры, кодогенерация, детектор race conditions и т. д.
  • У Go версии 1.11 появилась встроенное семантическое управления зависимостями, построенное поверх популярных хостингов VCS. Все инструменты, входящие в состав экосистемы Go используют эти сервисы, чтобы скачивать, собирать и устанавливать из них код одним махом. И это здорово. С приходом версии 1.11 также полностью разрешилась проблема с версированием пакетов.
  • Поскольку основной идеей языка является уменьшение магии, язык стимулирует разработчиков выполнять обработку ошибок явно. И это правильно, поскольку в противном случае, он просто будет забывать вообще про обработку ошибок. Другое дело, что большинство разработчиков сознательно игнорирую обработку ошибок, предпочитая вместо их обработки, просто пробрасывать ошибку вверх.
  • Язык не реализует классической методологии ООП, поскольку в чистом виде в Go нет виртуальности. Однако, это не является проблемой при использовании интерфейсов. Отсутствие ООП существенно снижает входной барьер для новичков.

Простота для выгоды сообщества


Усложнять просто, упрощать сложно.

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


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


Заключение


Большой размер мозга еще не сделал ни одного слона лауреатом Нобелевской премии.

Для тех программистов, у которых личное эго превалирует над командным духом, а также теоретиков, которые любят академические задачи и бесконечное "самосовершенствование", язык действительно плох, поскольку это ремесленнический язык общего назначения, не позволяющий получить эстетического удовольствия от результата своей работы и показать себя профессионалом перед коллегами (при условии, что мы измеряем ум именно этими критериями, а не коэффициентом IQ). Как и все в жизни — это вопрос личных приоритетов. Как и все стоящие новшества, язык уже проделал достаточный путь от всеобщего отрицания к массовому признанию. Язык гениален по своей простоте, а, как известно, все гениальное — просто!


Резюме


Среди всей резкой критики, направленной на Go, особо выделяются следующие утверждения:


  • Нет дженериков. Если мы взглянем на статистику самых востребованных языков то заметим, что половину языков из верхней десятки не имеют дженериков. Преимущественно дженерики нужны только в контейнерах. Поэтому выигрыш от них не слишком большой.
  • Другие языки типа Rust много лучше (по крайней по номинациям сайта XXX). Опять же, если мы взглянем на статистику самых востребованных языков, то мы вообще не обнаружим язык Rust в списке или же он будет где-то внизу рейтинга. Лично мне, Rust нравится, но я выбрал Go.
  • У языка XXX есть вот такая плюшка. Это обратная сторона медали простоты. Недостаток это или нет решать каждому. Однако, разработчики проекта отдали свои предпочтения в пользу простоты.
  • Вот выпустят Go 2.0, тогда и посмотрим. Такую позицию занимают наблюдатели, а не практики.
  • Не достаточно выразительный. Согласен, на некоторых участах выразительность хромает, однако в целом это простой и непротиворечивый язык. Кроме того, из-за бедности языка, мы вынуждены большее внимание уделять архитектуре разрабатываемого приложения, что позитивно сказыввается на его гибкости.

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


Эксперимент


Не верь словам — ни своим, ни чужим, а верь делам – и своим и чужим.

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


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


  • Действительно, гипотеза моих знакомых подтвердилась, однако, среди хабражителей еще встречаются адекватные люди, хотя процент их стремительно падает. Юрий Быков называет таких людей “дураками”, на которых держится вся страна. По его версии, их процент невелик (около 2%). Я не так пессиместичен и считаю, что их значительно больше.
  • Закон СМИ. Деструктивная информация вызывает значительно больший интерес, чем конструктивная.
  • Психология толпы. Это ужасная вещь, она даже из адекватного человека делает жестокого барана. Человек в толпе – это уже не человек. Ни о какой объективности не может быть и речи. Никакие логические доводы, никакие авторитетные источники или прецеденты на него уже не действуют.
  • Ответсвенность и безнаказанность. Люди с удовольствием готовы унизить другого, чтобы возвеличить себя (хотя бы в собственных глазах). Особенно, если за это не придется отвечать (что может быть проще — нажал минус и даже не требуется писать комментарий). Между словами и делами остается столько же общего, как между каналом и канализацией.
  • Тщеславие. Большинство снобов готовы выделиться любым способом. Никакие моральные преграды им не страшны.
  • Пессимизм. В отличие от западных стран (и тем более Америки), в стране превалируют пессимистические настроения. Как известно, оптимист ищет возможности среди сложностей, а пессимист — сложности среди возможностей. У нас в стране, практически никто, не обращает внимание на положительные качества чего бы то ни было.
  • Профессионализм и круг мировоззрения. Большинство людей выбирает инструменты, как самоцель, а не как средство достижения поставленной цели. Люди разучились работать с информацией. Люди не видят за деревьями леса. Из массива информации они не в состоянии выделять главные мысли. Никто не хочет взглянуть с другой, не стандартной для себя, точки зрения. Инакомыслие подавляется. Здесь так не принято.
  • Дружность и уважение. Хваленые дружные коллективы существуют только на словах. Ценности Agile разработки — только на бумаге.
  • Лицемерие. Об этом вообще можно написать отдельную статью.
  • Принципиальность. Есть люди, которые задаются правильным вопросом: “Что я вообще нахрен делаю?”, однако не все понимают, что из-за отстутствия приципиальности для нас сиюминутный шкурный интерес важней, чем все наши принципы вместе взятые. Легче всего свалить все на обстоятельства и сказать, что от нас ничего не зависит.

С глубоким уважением и сочуствием ко всем конструктивно мыслящим оптимистам.


Adverax.

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


  1. roman_truschev
    22.04.2019 09:21

    Накопировали что функции int64Add и Sub получились одинаковыми так же и для 32


  1. vlreshet
    22.04.2019 09:27
    +1

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


    1. adverax Автор
      22.04.2019 09:43

      Вообще в статье идет не о достоинствах языка D, а об отсутствии преимуществ у альтернативных языков перед Go. Все зависит от точки зрения и расстоновки приоритетов.
      Тернарным условием сейчас никого не удивишь, поскольку она пришло из C++. В данном контексте куда интереснее восклицательный знак. Человек, не знающий языка, просто не сможет правильно прочесть это предложение.


      1. vlreshet
        22.04.2019 10:22
        +2

        Человек, не знающий языка, просто не сможет правильно прочесть это предложение.
        А зачем человек не знающий языка — пытается его прочесть? ИМХО, менеджерам и прочим — можно показывать псевдокод, отлично зайдёт. А делать язык который будет понятным даже без изучения… Представьте если бы проводку в машинах делали не тугими косами с цветовой кодировкой, а большой лапшой где каждый провод отдельно подписан. Мол «ну да, места больше занимает, зато если на СТО водитель захочет разобраться чё там как — механик ему легче объяснит». Абсурд же.


        1. adverax Автор
          22.04.2019 10:37

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


          1. vlreshet
            22.04.2019 11:43

            DRY — это к написанию кода реального продукта. Накидать псевдокод для презентации клиенту/менеджеру/аналитику — к этому не относится.


            1. adverax Автор
              22.04.2019 12:29

              Википедия говорит:

              Don’t repeat yourself, DRY (рус. не повторяйся) — это принцип разработки программного обеспечения, нацеленный на снижение повторения информации различного рода, особенно в системах со множеством слоёв абстрагирования. Принцип DRY формулируется как: «Каждая часть знания должна иметь единственное, непротиворечивое и авторитетное представление в рамках системы»

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

              Если же приходится выдавать справки в виде псевдокода, мы получаем следующие минусы:
              * Дополнительная работа для программиста, которая отрывает его от основной работы.
              * Устаревание информации. Через некоторый интервал времени сведения устаревают, после чего требуется псевдокод писать заново.
              * Отсутствие цельной картины. Тот кто работал с аналитикой, поймет, что выдавая псевдокод, мы формируем срез по решению конкретной проблемы. Эти отрывочные данные не позволяют увидеть всю многомерную картину.


          1. deepone
            22.04.2019 13:33

            ага, а go dry соответствует =)


      1. Chaos_Optima
        22.04.2019 15:07
        +1

        а об отсутствии преимуществ у альтернативных языков перед Go.

        Но ведь это не правда, у других языков полно преимуществ по сравнению с GO просто эти преимущества усложняют понимание кода (хотя это тоже спорное утверждение, читать код на D для меня было проще). Про простоту чтения тоже сомнительное утверждение, да может читать код в go проще например 50 против 20 в другом языке, но насколько я вижу многие вещи в го выражаются куда более многословнее, и получается что в го нужно прочитать 15 строк против 2 в другом языке. Такое себе ускорение.
        И ещё
        Однако, только короче, но не правильней, поскольку в реализации на D полностью игнорируется проблема обработки ошибок.

        Но в ведь в коде GO тоже нет никакой обработки ошибок.


      1. Optik
        22.04.2019 23:55

        Показал боссу непрограммисту — он всё равно выбрал как предпочтительный вариант на D.


    1. dendron
      23.04.2019 00:05

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


  1. TonyLorencio
    22.04.2019 09:28

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

    Это все прекрасно до тех пор, пока не нужно передавать, например, слайс интерфейсов. Слайс переменных []T, где T — некоторый тип, не удовлетворяет []iface, где iface — некоторый интерфейс.


    Варианты:


    1. Передавать interface{} и сношаться с рефлексией (как вариант: свести использование до какой-то функции из библиотеки, в том числе стандартной, где сношаются с рефлексей за вас)
    2. Накопипастить / нагенерировать нужные функции
    3. Каждый раз создавать новый []iface из []T (либо в явном виде, либо через unsafe-магию)
    4. Жрать кактус Ждать дженериков, а пока использовать 1, 2 или 3


    1. adverax Автор
      22.04.2019 09:52

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


      1. TonyLorencio
        22.04.2019 09:56

        Именно поэтому разработчики Go не стали реализовывать серебрянную пулю.

        Они уже в процессе, на самом деле, но сроков пока нет https://go.googlesource.com/proposal/+/master/design/go2draft-generics-overview.md


        1. adverax Автор
          22.04.2019 10:07

          Все дело в том, что Go консервативный язык, поэтому недостаточно проработанную модель никто внедрять не торопится. Аналогично в процессе и расширенная обработка ошибок habr.com/ru/post/422049, но сроков выхода релиза Go 2.0 никто не знает. Сравните, к примеру, реализацию объектной модели в PHP версии 4.0 и 5.1. На мой взгляд консервативный подход правильней, поскольку попросту экономит человеческие ресурсы.


    1. farcaller
      22.04.2019 11:04

      Я тут недавно yaml с гибкой спецификацией парсил, было весело:


      d := map[string]map[string]interface{}{}


      1. 0xd34df00d
        22.04.2019 16:53

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


        1. TonyLorencio
          22.04.2019 17:02

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


          mValue, ok := value.(map[string]interface{})
          // далее - проверка ok и возможное использование mValue как map[string]interface{}

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


        1. farcaller
          22.04.2019 17:25

          именно так. ПО хорошему надо было бы в именованные типы вынести, но оно не очень помогает из-за вороха дальнейших кастов (как верно подметил TonyLorencio выше).


    1. Pr0Ger
      22.04.2019 20:02

      Дело не в дженериках, а в том что у []T и []iface разные представления в памяти и для такой передачи надо было бы неявно создать копию исходного слайса за O(n), про это даже в FAQ упомянуто
      Но да, будь в языке дженерики можно было бы сделать у слайса метод который создает такую копию с нужным типом


      1. TonyLorencio
        23.04.2019 10:32

        Мне казалось, что коварианты можно на уровне компилятора реализовать более эффективно, чем неявно копировать слайс за O(n).


  1. tangro
    22.04.2019 10:21
    +2

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

    Объясните теперь зачем по 8+ часов в день заниматься тем, что не даёт получить эстетическое удовольствие даже теоретически?


    1. adverax Автор
      22.04.2019 10:32
      -2

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

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

      Если же программист желает получать эстетическое удовольствие — добро пожаловать в Haskell.


      1. tangro
        22.04.2019 11:28

        Ну то есть нужно страдать?


        1. adverax Автор
          22.04.2019 11:43

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

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


          1. tangro
            22.04.2019 18:32
            +7

            Вы человек вообще?


      1. 0xd34df00d
        22.04.2019 16:55
        +1

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

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


        Если же программист желает получать эстетическое удовольствие — добро пожаловать в Haskell.

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


        1. vassabi
          23.04.2019 04:25

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


          1. 0xd34df00d
            23.04.2019 04:31

            Да, довольны, иногда даже параллельно!


            Ну, если дописать, то как-то уже несерьёзно будет :]


      1. Fortop
        23.04.2019 19:04

        Не-не-не.
        Какой индустриальный стандарт?

        Вы же сами процитировали Пайка

        Ключевой момент здесь, что наши программисты не исследователи. Они, как правило, весьма молоды, идут к нам после учебы, возможно изучали Java, или C/C++, или Python. Они не в состоянии понять выдающийся язык, но в то же время мы хотим, чтобы они создавали хорошее ПО. Именно поэтому язык должен прост для понимания и изучения.


        Читаем буквально.
        Ключевой момент здесь, что наши программисты не исследователи"люди с высоким интеллектом и особым складом ума". Они, как правило, весьма молоды, идут к нам после учебы, возможно изучали Java, или C/C++, или Python"ограничены в опыте". Они не в состоянии понять выдающийся язык"туповаты", но в то же время мы хотим, чтобы они создавали хорошее ПО. Именно поэтому язык должен быть прост для понимания и изучения.

        Ну что же… Все логично. Я полностью солидарен с Пайком.

        Только вот вывод из цитаты получается строго противоположный заголовку статьи…


        1. vassabi
          23.04.2019 20:45

          хмм… то есть Пайк пытался, но не смог?


  1. jaiprakash
    22.04.2019 11:10

    Delphi пишется не заглавными буквами, и это IDE, язык же называется object pascal.


    1. gltrinix
      22.04.2019 11:31

      Язык тоже называется Delphi


  1. sandworm
    22.04.2019 11:32

    А вот интересно, почему 98% статей про го — рассказ о том, что он нереально, фантастически хорош?
    Почему нет таких развернутых апологий для котлина? дарта? тайпскрипта? Ведь все они тоже новые модные языки с кучей крутых гитик!


    1. deepone
      22.04.2019 13:37

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


      1. evocatus
        22.04.2019 21:15

        По-моему евангелисты Rust уже везде.


        1. PsyHaSTe
          22.04.2019 21:28

          Нет, просто язык не первый год в топе опросов на stackoverflow.

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


    1. Optik
      22.04.2019 23:57

      У котлина вроде фанатиков за глаза, куда больше.


    1. nikbond
      23.04.2019 00:16

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


    1. SirEdvin
      24.04.2019 09:18

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


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


      1. TonyLorencio
        24.04.2019 10:07

        кучу абстракций которых они не понимают

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


  1. vitvakatu
    22.04.2019 11:39

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

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


    1. adverax Автор
      22.04.2019 11:56
      -1

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

      Что касается длины программы, то отвечу цитатой про читаемость на языке PERL:

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


      1. 0xd34df00d
        22.04.2019 17:14

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


      1. PsyHaSTe
        22.04.2019 17:51

        То есть вы такие сходу меняете условия и БАЦ, программист неправ? Типа «как бы вы реализовали сложение чисел», а потом «А если мы вдруг ДЕЛИМ тот тут будет ошибка, айяйяй».

        Ну так если мы не делим, то никакой обработки ошибок не надо. Вот когда появится необходимость делить, тогда и добавим. YAGNI во всей красе. И да, в хорошем ЯП отрефакторить код чтобы он начал прокидывать ошибки совершенно несложно.


    1. 0xd34df00d
      22.04.2019 17:15

      ни вообще необходимость какой бы то не было обработки ошибок во время сложения и вычитания чисел

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


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


  1. zim32
    22.04.2019 12:16

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


  1. PsyHaSTe
    22.04.2019 12:21
    +3

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


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

    Это неправда, потому что строго говоря на ГО сложных программ вообще не пишут. Несмотря на то, что формально Кубернитес написан на Go, фактически там реализована своя система типов, "класс" Object, реализованы правила именования, идентификации и реестр типов (type registry), соответствие типов проверяется в рантайме (в случае чего выдаётся “no kind is registered for the type …”). Подробнее можно почитать здесь. Интересно, зачем они это сделали?


    Роб Пайк (главный идеолог языка) создавал язык Go, как индустриальный язык, который легок в восприятии, эффективен в использовании.

    Язык прост в написании кода, но он непрост в выражении предметной области. Например, вопрос, что делает этот цикл:


    for i := 1; i <= 10; i++ {
       item := a[i]
       ...
    }

    ...


    Не догадались?


    А вот аналог на каком-нибудь функциональном языке


    let result = a.map(|item| ... )

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


    Мудрые слова, не правда ли?

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


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

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


    Может, простота это не единственный критерий?


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

    Свобода это рабство, мир это война. Отсутствие элегантных абстракций это достоинство.


    Решение этой же задачи на языке D хотя и выглядит несколько короче, однако, читается ничуть не проще

    Я не знаю D, однако программу на нем я понял сразу. В го я зарылся в то, что такое Scanner. И хотя со второго взгляда все стало очевидным, мне понадобилось совершить когнитивное усилие чтобы восстановить алгоритм. В D написано практически по-английски ЧТО нужно получить, в Go написано императивно КАК это сделать. А нас, как разработчиков, обычно больше волнует цель кода, а не то, как он работает. В одном случае мы эту информацию можем получить прямо из исходного кода, в другом случае нужно самостоятельно дедуктивно это определить. ИМХО просто прочитать это из исходника проще.


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

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


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

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


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

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


    fn main() {
        do_job(&["1", "2", "3"]);
        do_job(&["1", "Not a number", "3"]);
    }
    
    fn do_job(input: &[&str]) {
        let ints = input.iter().map(|x| {
            println!("Trying to parse: {}", x);
            x.parse::<i32>()
        });
        let result: Result<Vec<i32>, _> = ints.collect();
        println!("{:?}", result);
    }

    https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7a17522cf5808edf11be13159b31a37e


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


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


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

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


    Обобщенное программирование в ряде случаев дает нам неоспоримую выгоду. Это наглядно иллюстрирует нам пакет sort. Так, для сортировки любого списка нам достаточно реализовать интерфейс sort.Interface.

    Честно говоря, не вижу в программе ничего про "реализую sort.Interface", только набор несвязных объявленных функций. Чтобы про них узнать, видимо, нужно читать документацию. Как догадаться, какие функции объявлять и с какими сигнатурами не имею представления.


    Если Вы возьмете любой open source проект и выполните команду grep "interface{}" -R, то увидите, как часто используются путые интерфейсы.

    Пустые интерфейсы это аналог dynamic в C# или другими словами отключение системы типов. Зачем тогда го вообще? Используйте Python. Он, конечно, не поможет на этапе компиляции отловить ошибку "вы пишете в переменную String число", но зато он позволит истинно обобщенное программирование, без рефлексии.


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

    Хотел давно задать вопрос, а почему мы сравниваем Го с языком 33 летней давности? Неужели с тех пор ничего полезного не изобрели? И да, этот VARIANT остается тем, чем я сказал, признанием в бессилии системы типов и переходом в динамику.


    И да, генерики в го есть, но они не для всех. Можно ведь создать []string или []T, с любым T. Видимо, деление на граждан первого сорта (разработчикам языка, которым можно генерики) и всех остальных (которым нельзя) тоже очень важно в го. Вот уж где много магии, когда нельзя скопировать код стандартной библиотеки так, чтобы они скомпилировались.


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

    Citation needed


    Параллельность и конкурентность языка выше всяких похвал. Ни один низкоуровневый язык не может даже отдаленно конкурировать с языком Go.

    Citation needed


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

    Но ведь у нас нет системы типов :) Мы постоянно пишем interface {} и отказываемся от них. Из системы типов у нас одни только примитивы, по сути. Да и с типами ничего сделать нельзя, потому что они раскрываются вкупе с обобщенным программированием (которое Generic), а его и нет. А с interface {} никакие типы не нужны, можно было бы как в питоне писать и все бы работало.


    Мощная стандартная библиотека, что позволяет в большинстве проектов обходиться без сторонних фреймворков.

    Стандартная библиотека не мощная. В нее напихано куча всякой фигни вроде работы с HTTP, но зато до сих пор нет метода удаления элемента из массива. На дворе 2019 год, а люди до сих пор пишут a = append(a[:i], a[i+1:]...).


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

    Пример выше показывает, что приходится концентрироваться на "как выразить этот очевидный однострочник этими скудными АПИшками". Причем как правило проще нагуглить результат на stackoverflow, где у этого ответа 245 лайков. Сколько сотен тысяч раз был скопирован этот код из-за того, что в стандартной библиотеке его не оказалось? Не берусь считать.


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

    Попробуйте забыть обработку ошибки на примере раста, пожалуйста. Explicit != verbose.


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

    И тут БАХ, и всех несогласных объявили "эгоистами-диванными-теортиками с низким IQ". Это, конечно, очень способствует позитивному восприятию статьи.




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

    У меня нет возражений по всем пунктам, которые явно не выделил в цитатах, но этот хотел отметить отдельно. Я абсолютно полностью с ним согласен. Го действительно получился очень простым. И он действительно написан для умных программистов. Я вообще всегда считал, что чем ближе язык к динамическим, тем умнее надо быть чтобы на нем программировать. На языке с генериками, типами и ограничениями не получится использовать несуществующее поле, изменить неизменяемое значение, записать строку в число, не нужно пользоваться рефлексией чтобы написать обобщенный код, а достаточно сделать генерик-плейсхолдер Т… В динамическом языке нужно держать всё это в голове, знать все поля всех объектов в программе (при том, что типы явно не объявлены, и нужно помнить все инстансы!). Го определенно ближе именно ко второй границе.


    Статье поставил плюс. Спасибо за интересное чтение.


    1. vlreshet
      22.04.2019 13:34
      +2

      Тот случай, когда комментарий тянет на пост.


    1. PsyHaSTe
      22.04.2019 13:49

      Автор ответил чуть ниже, если интересно продолжение обсуждения ищите там :)


    1. 0xd34df00d
      22.04.2019 17:33

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

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


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

      [тянет руку] Ой, а можно я? Если я правильно понимаю, что делает println! у вас там, то


      ?> parseAll ws = show $ sequence (readEither <$> ws :: [Either String Int])
      ?> :t parseAll
      parseAll :: [String] -> String

      Или, если вы не боитесь значков и расширений языка:


      ?> :set -XTypeApplications
      ?> parseAll ws = show $ sequence (readEither @Int <$> ws)
      ?> :t parseAll
      parseAll :: (Show (t Int), Traversable t) => t String -> String

      Заодно получили чуть более обобщённый тип. Кроме того, теперь можно увидеть, что у нас тут по факту map + sequence, что по определению равно mapM для монад (либо можно было бы сразу вспомнить, что Either — монада), и написать итоговое


      ?> parseAll ws = show $ mapM (readEither @Int) ws
      ?> :t parseAll
      parseAll :: (Show (t Int), Traversable t) => t String -> String
      ?> putStrLn $ parseAll ["1", "2", "3"]
      Right [1,2,3]
      ?> putStrLn $ parseAll ["1", "2", "foo", "3"]
      Left "Prelude.read: no parse"

      За счёт ленивости тоже всё получится хорошо и эффективно.


      И можно, наверное, в pointfree переписать, но пора уже остановиться.


      PS. Ппц, случайно после идриса набрал :doc sequence вместо :info sequence, чтобы убедиться, что там легаси Monad-констрейнт, а не Applicative, а оно мне справку распечатало:


      ?> :doc sequence
       Evaluate each monadic action in the structure from left to
       right, and collect the results. For a version that ignores the
       results see 'Data.Foldable.sequence_'.

      Что-то я забыл про эту новинку.


      1. PsyHaSTe
        22.04.2019 17:54

        ?> parseAll ws = show $ sequence (readEither <$> ws :: [Either String Int])
        ?> :t parseAll
        parseAll :: [String] -> String

        Ну по сути тут в одну строчку то же самое записано, что у меня.
        Только я не совсем понял, в каком моменте мы от Seq<Either<_, _>> перешли к Either<Seq<_>, _>


        Или, если вы не боитесь значков и расширений языка:

        Боюсь :)


        mapM (readEither Int) ws

        Оно нам вернет Either? Потому что я хотел набить данными структуру, а не тупо распечатать :)


        1. 0xd34df00d
          22.04.2019 18:00

          Ну по сути тут в одну строчку то же самое записано, что у меня.

          Ну, да, идея там ровно та же, просто не нужны никакие iter(), ну и всякие $ и <$> помогают композабельности.


          Только я не совсем понял, в каком моменте мы от Seq<Either<_, _>> перешли к Either<Seq<_>, _>

          В sequence:


          ?> :t sequence
          sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

          Подставим сюда t = [], m = Either String:


          ?> :t sequence @[] @(Either String)
          sequence @[] @(Either String)
            :: [Either String a] -> Either String [a]

          Оно нам вернет Either? Потому что я хотел набить данными структуру, а не тупо распечатать :)

          Да, mapM f = sequence . map f почти по определению. Ну и


          ?> :t mapM (readEither @Int)
          mapM (readEither @Int)
            :: Traversable t => t String -> Either String (t Int)


          1. PsyHaSTe
            22.04.2019 18:06

            Ну, да, идея там ровно та же, просто не нужны никакие iter(), ну и всякие $ и <$> помогают композабельности.

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




            Ну а в целом все понятно, да. Большое спасибо. Закончу читать красную книгу, обязательно вернусь в learnyouhaskell :)


            1. 0xd34df00d
              22.04.2019 18:12
              +1

              Я в скалку не смог. Она, наверное, хороша, если вам нужно спарк ковырять, или что-то такое, у чего в скалу API торчит, но брать её либо для просто проектов, которым это не нужно, либо, тем более, для какого-то самообразования я бы не стал. На мой взгляд, это действительно попытка совместить ООП и ML-style-функциональщину, и получилась какая-то костыльная ерунда.


              Ну и читать невозможно. На мои каверзные вопросы по всяким околохаскелям на SO отвечает в основном один и тот же чувак, я посмотрел из интереса, какие вопросы он сам задаёт, а там на меня сходу прыгнуло Why can't the compiler figure out (_ >: T) => (_ <: V[_ <: U]) <: T => V[U] for V[+_]?, ну камон.


              1. PsyHaSTe
                22.04.2019 18:36

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

                Я лично не пробовал, но настрой примерно такой. Хотя жвм и все остальное расстраивают, равно как и угробищный синтаксис.

                Что касается ссылки то вроде все не так уж страшно. По сути у нас есть баунды, и вопрос звучит как «почему функа принимающий ковариантный параметр T и возвращающая контрвариантный генерик V контрвариантного типа U не является подтипом T => V[U]»


                1. 0xd34df00d
                  22.04.2019 18:43

                  На Eta их зовите вместо скалы, лул. Хотя, «We will probably not support the TypeInType extension in the near future because dependent kinds can be a bit difficult to learn and teach.», хм :(


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


                  1. sshikov
                    22.04.2019 20:06

                    А чем Эта лучше пары предыдущих попыток затащить хаскел в среду JVM? Как-то они обе (полу)дохлые…


                    1. 0xd34df00d
                      22.04.2019 20:27

                      Ну, она пока ещё вроде как менее дохлая. И больше расширений из ghc поддерживает.


                  1. PsyHaSTe
                    22.04.2019 21:30

                    Ну кмк на скалу все же проще затащить. Но это так.

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


                    1. newpavlov
                      22.04.2019 22:23

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


                      1. PsyHaSTe
                        22.04.2019 23:57

                        Ну как-то костыльно очень выглядит. Сначала с ?, потом с async/await, теперь вон с Pin/Unpin. Каждый маркерный трейт, от которого еще надо явно отказываться и учить как с ним работать это очередное подтверждение фигового планирования. Да, работает, но какой ценой?


                        1. newpavlov
                          23.04.2019 02:04

                          Я как понимаю, вам хотелось бы увидеть полноценные do-нотацию и монады? :) Мне кажется, что разработчики решили не расходовать и без того опустошённый strangeness budget (особенно на такие меметичные вещи как монады) и пойти по пути меньшего сопротивления добавив костыли которые покроют львиную долю юзкейсов встречаемых на практике, вместо поиска какого-то более обобщённого решения. Т.е. рассказывать людям приходящим с JS/Питона/etc. об async/await и ? значительно проще и это будет вызывает меньше отторжения по сравнению с монадами. Хотя, конечно, вместо Pin/Unpin я бы тоже предпочёл иметь более общее решение для ссылающихся на самих себя структур.


                          1. 0xd34df00d
                            23.04.2019 04:35

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


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


                            1. newpavlov
                              23.04.2019 11:46

                              Разница подхода в том, что Раст стремится стать «успешным», т.е. в каком-то смысле противоположно «avoid success at all costs». Насчёт «потери для сообщества» сложно сказать, но думаю количество тех кто после шарпов и питонов посмотрит на раст и увидит вместо более-менее сразу понятных механизмов обработки ошибок и асинхронщины, высокоуровневые абстракции и HKT, и решит «да ну нафиг этот Раст, слишком заумно» будет весьма заметно, что учитывая сетевые эффекты, может стать заметной потерей. (напоминаю, что значительное кол-во людей приходит в Раст из динамических языков)

                              Другим моментом является сколько времени понадобится на выработку дизайна и стабилизацию данной функциональности, что бы оно ещё и компилировалось в эффективные бинарники за разумное время? Сколько уже мурыжат весьма урезанные по функциональности const generics? Боюсь на do-нотацию и обобщённую систему эффектов ушло бы существенно больше времени и всё это время мы бы жили без удобств которые дают `?` и `async`/`await`, что, опять же, сказалось бы достаточно негативно на популярности языка.

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


                              1. PsyHaSTe
                                23.04.2019 12:15

                                Ничего страшного в do не было бы. Люди каким-то образом привыкли к ?, щас вон делают try-блоки. А это и есть do-блок, только прибитый к Try трейту, а не более общему.

                                У общих решений есть плюс, что ими можно пользоваться порционно. Например, можно было бы сделать do и единственной монадой был бы Either и Option. Как сейчас оно и есть с ?, просто был бы другой синтаксис. Потом добавили бы await. Потом еще что-нибудь. Это ведь просто вопрос удобства и переиспользования.

                                Другим моментом является сколько времени понадобится на выработку дизайна и стабилизацию данной функциональности, что бы оно ещё и компилировалось в эффективные бинарники за разумное время? Сколько уже мурыжат весьма урезанные по функциональности const generics?

                                Нисколько, потому что их не делают вообще. Они заблокированы chalk'ом, которого нет.

                                Разница подхода в том, что Раст стремится стать «успешным», т.е. в каком-то смысле противоположно «avoid success at all costs».

                                Эта фраза немного другое означает, и в оригинальной формулировке я даже с ней согласен.


                                1. 0xd34df00d
                                  23.04.2019 17:53

                                  Эта фраза немного другое означает, и в оригинальной формулировке я даже с ней согласен.

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


                                  1. PsyHaSTe
                                    23.04.2019 18:30

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


                              1. 0xd34df00d
                                23.04.2019 17:52

                                Я по плюсовому коммьюнити сужу, и тут уже давно никто не боится слов, что optional — монада, или что корутины — монада, или ещё что такое.


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


                                1. vassabi
                                  23.04.2019 18:35

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


                    1. 0xd34df00d
                      23.04.2019 04:33

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


                      Но это таки тоже так.


                      1. PsyHaSTe
                        23.04.2019 12:16

                        Ну под тырпрайзом я скорее подразумеваю прикладную разработку. Так-то для себя я понял что самые комфортные места работы в небольших компаниях на 30-100 человек.


                        1. 0xd34df00d
                          23.04.2019 17:54

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


                          1. sshikov
                            25.04.2019 22:52

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


  1. niklisto
    22.04.2019 12:54

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

    ЕМНИП дженерики в делфи завезли в версии 2009 года. При этом вариантами пользовались чуть ли не с первой версии… Так себе аналогия получается


  1. adverax Автор
    22.04.2019 13:17

    Спасибо за развернутое мнение по статье.
    Вкратце пройдусь по некоторым пунктам Вашего комментария.



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

    У каждой медали две стороны. Вы заняли пессимистическую позицию. Представьте ситуацию: токарь 30 лет работал, вытачивал одну и ту же деталь. Причем вытачивал в совершенстве. В один прекрасный момент пришел инженер изменил конструкцию так, что эта деталь стала не нужна. Вопрос: что от этого потерял мир? Так может лучше остановить технический прогресс вообще?



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

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



    Свобода это рабство, мир это война. Отсутствие элегантных абстракций это достоинство.

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



    Но ведь у нас нет системы типов :) Мы постоянно пишем interface {} и отказываемся от них. Из системы типов у нас одни только примитивы, по сути. Да и с типами ничего сделать нельзя, потому что они раскрываются вкупе с обобщенным программированием (которое Generic), а его и нет. А с interface {} никакие типы не нужны, можно было бы как в питоне писать и все бы работало.

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



    Хотел давно задать вопрос, а почему мы сравниваем Го с языком 33 летней давности? Неужели с тех пор ничего полезного не изобрели? И да, этот VARIANT остается тем, чем я сказал, признанием в бессилии системы типов и переходом в динамику.

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



    Попробуйте забыть обработку ошибки на примере раста.

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



    И тут БАХ, и всех несогласных объявили «эгоистами-диванными-теортиками с низким IQ».

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


    1. PsyHaSTe
      22.04.2019 13:48
      +1

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


      У каждой медали две стороны. Вы заняли пессимистическую позицию. Представьте ситуацию: токарь 30 лет работал, вытачивал одну и ту же деталь. Причем вытачивал в совершенстве. В один прекрасный момент пришел инженер изменил конструкцию так, что эта деталь стала не нужна. Вопрос: что от этого потерял мир? Так может лучше остановить технический прогресс вообще?

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


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

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


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

      Programming Defeatism: No technique will remove all bugs, so let's go with what worked in the 70s.


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

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


      protected static async Task<TransactionReceipt> WrapTransactionAsync(
          Func<Task<TransactionReceipt>> operation,
          params (Func<Task<bool>> isBusinessRuleFailed, Func<Exception> businessExceptionFunc)[] checks)
      {
          try
          {
              return await operation();
          }
          catch (TransactionFailedException)
          {
              foreach (var (isBusinessRuleFailedAsync, businessExceptionFunc) in checks)
              {
                  if (await isBusinessRuleFailedAsync())
                  {
                      throw businessExceptionFunc();
                  }
              }
              throw;
          }
      }

      Потому что после этого их очень легко переиспользовать:


      public Task<TransactionReceipt> ValidateTransactionAsync(string transactionHash, RequestStatusUpdate requestStatusUpdate)
      {
          return WrapTransactionAsync(
              () => Web3.Client.GetTransactionReceiptAsync(transactionHash),
              (
                  () => IsNewRequestAsync(requestStatusUpdate.ServiceNumber),
                  () => new RequestNotFoundException(requestStatusUpdate.ServiceNumber)
              ),
              (
                  async () => !await IsNewStatusAsync(requestStatusUpdate),
                  () => new StatusAlreadyExistsException(requestStatusUpdate)
              ));
      }

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


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

      Ну давайте сравним с Rust, благо он появился примерно в то же время. Давайте с C#/Kotlin, которые не менее "тырпрайзные" и приземленные, не в угоду ленивым теоретикам с низким IQ.


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

      Но ведь это не повод делать в го неудобно.


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

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


      1. adverax Автор
        22.04.2019 14:58
        -2

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

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

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

        Статистику привести не могу, поскольку не занимался этой проблемой, однако, можете сами посмотреть на github проекты и посмотреть составляющий их процент копипаста. Например, вы можете посмотреть мою ветку проекта Echo(http://github.com/adverax/echo). Да, там есть копипаст, однако процент его не так уж и велик. Существует множество языков без дженериков и все отлично обходятся без них. Однако, когда заходит речь о Go, почему-то 90% народа считают их краеугольным камнем.



        как завуалированное сомнение

        Сомнения — это домыслы каждого. Каждый судит в меру своей распущенности.



        Ну давайте сравним с Rust, благо он появился примерно в то же время. Давайте с C#/Kotlin, которые не менее «тырпрайзные» и приземленные, не в угоду ленивым теоретикам с низким IQ.

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


        1. PsyHaSTe
          22.04.2019 15:30
          +1

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

          Так где прецедент-то? В чем он заключался? Давайте факты.


          Существует множество языков без дженериков и все отлично обходятся без них. Однако, когда заходит речь о Go, почему-то 90% народа считают их краеугольным камнем.

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


          Сомнения — это домыслы каждого. Каждый судит в меру своей распущенности.

          Ну давайте проясним тогда, что имелось ввиду? Мне очень интересно.


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

          А не надо быть без недостатков, достаточно быть лучше, причем только в какой-то одной сфере, а в других просто быть не хуже. Это парето-оптимальность еще называется. Так вот ИМХО аргументы этой статьи не очень убедительны. Есть C# в котором ничуть не сложнее получить один исполняемый файл и иметь хорошую многопоточность и асинхронность. Есть котлин с теми же плюшками. Тонна других языков.


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


          1. adverax Автор
            22.04.2019 15:59
            -1

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

            Вот я и привел вам аналогию с токарем. Если человек в совершенстве изучил одну операцию — это еще не повод монетизировать ее всю жизнь.



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

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



            Ну давайте проясним тогда, что имелось ввиду? Мне очень интересно.

            Ранее вы писали:
            Лично я цитату «они умные, но при условии, что мы измеряем ум именно этими критериями, а не коэффициентом IQ» как раз-таки как завуалированное сомнение в этих-самых способностях, иначе зачем эта часть в статье я вообще затрудняюсь сказать. Уверен, у большинства читающих сложилось то же впечатление.




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

            Вот Go и хорош на 80%, причем на вопрос нужно смотреть шире: язык не только сам по себе достаточно хорош (в свое время я остановился на Rust), но его инфраструктура и выгоды для командной работы на текущий момент одни из лучших. Даже IDE для него от JetBrains одна из лучших.



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

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


          1. evocatus
            22.04.2019 21:26
            +1

            Бартош Милевски давно всё объяснил: «либо у вас динамическая типизация, либо generics, а если у вас их ещё нет, то скоро будут»


        1. a1ien_n3t
          22.04.2019 15:48
          +1

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

          А можно узнать, что нетак с экосистемой раста. Просто чтобы понимать.


          1. adverax Автор
            22.04.2019 16:18
            -1

            Пару лет назад (насколько я помню) у него:
            * не было полнокачественной среды (только плагины).
            * не было race detector.
            * было ручное форматирование и документирование кода.
            * было весьма немногочисленное комьюнити с относительно небольшим количеством библиотек.

            Несмотря на то, что язык хорош, ему трудно состязаться с такими монстрами, как Google.


            1. Lodin
              22.04.2019 16:31
              +3

              А сейчас у него есть Intellij Rust на платформе Intellij Idea, rustfmt для форматирования, rustdoc для документации (и вроде бы всегда был, кстати), а ещё он — ТОП-1 в рейтинге Stack Overflow как most loved language.


              1. PsyHaSTe
                22.04.2019 16:50

                К слову, описанные пару лет назад и они были. Проблемы с IDE у раста закончились через год после релиза в 2016 где-то. rustfmt/rustdoc же там с версий 0.х еще были.


            1. a1ien_n3t
              22.04.2019 16:35
              +1

              В расте нет проблем с race condition в общем смысле. Да в расте можно словить дедлок, но получить повреждение памяти без usafe кода нельзя.
              Тут подробнее.


    1. SirEdvin
      24.04.2019 09:24

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

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


      Мне интересно, откуда вы вообще берете какие-либо данные про читаемость языка? Вы проводили исследования, опросы?


  1. vassabi
    22.04.2019 13:27
    +1

    Вообщето «Почему язык ЯЯЯ плох для НЕумных программистов» — можно написать о ЛЮБОМ языке программирования, от перла до хаскеля с эрлангом и от фортрана до джавскрипта.


  1. unclechu
    22.04.2019 13:44
    +1

    Даже начинающие программисты начинают выдавать вполне приличный код спустя неделю-другую.


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

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


    1. unclechu
      22.04.2019 13:53
      +1

      Но рано или поздно у многих ограниченных программистов возникает использовать старые методы на новом поприще. Действительно ли это так необходимо?

      возникает использовать

      «Ограниченных» программистов? Т.е. «ограниченность» — это когда тебе чего-то не хватает в технологии? С каждым новым абзацем сомневаюсь в компетентности автора всё больше и больше.

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

      «Начинающие» программисты жалуются, что «есть многие фичи, которых им недостаёт»? Они точно начинающие, раз уже вообще знают о существовании целого множества фич, которых им вдруг стало не хватать, словно раньше они ими постоянно пользовались? Или вы просто клеймите всех «ограниченными» и «начинающими», кто не согласен что Govno — это якобы хороший ЯП?


      1. adverax Автор
        22.04.2019 14:27
        -2

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


        1. 0xd34df00d
          22.04.2019 17:38
          +1

          Я, конечно, дико извиняюсь, но гугл не топчик в части PLT.


          Ну и такой явный спердоб — это так себе.


        1. PsyHaSTe
          22.04.2019 17:59
          +1

          Кумоводство и спервадобейся в одном предложении. Неплохо.


  1. mjr27
    22.04.2019 14:16
    +1

    Я правильно понял, что он плох и для умных и для неумных?


  1. sv_kozlov
    22.04.2019 14:28
    +1

    Прежде всего, синтаксис грамматических конструкций основывается на синтаксисе языка Си. Однако, существенное влияние оказал и язык DELPHI. Так, мы видим, что полностью убраны избыточные скобки, так сильно снижающие читаемость программы. Также язык содержит оператор ":=", присущий языку DELPHI.

    На мой взгляд, значительно повлиял Oberon, хотя об этом говорят сильно меньше.
    Структуры и методы, привязанные через ресиверы — это из Оберона.
    Вообще, вся группа языков Н.Вирта оказала сильное влияние на Go. Впрочем, так же как и на Java, и на C#. Правда, джависты не признаются, за что Н.Вирт на них обижался. Он об этом говорил на своей лекции в Политехническом музее, когда приезжал в Москву.


  1. eandr_67
    22.04.2019 14:32

    существенное влияние оказал и язык DELPHI
    язык содержит оператор ":=", присущий языку DELPHI
    За основу пакетов была взята семантика языка DELPHI

    Если бы вы были знакомы с языком Oberon или хотя бы заглянули в учебник Go Донавана & Кернигана (в котором на первых же страницах показана «генеалогия» Go), то поняли бы полную ошибочность вышеперечисленных предположений. Авторы Go ориентировались на куда белее совершенные, чем распухший и бесформенный Delphi, языки.

    И семантика пакетов, и синтаксис методов однозначно указывают, что одним из первоисточников Go был именно Oberon.

    И, кстати, Ada также никакого отношения к Go не имеет. Хотя и в Ada, и в Go реализован механизм рандеву (называемый в Go каналами), но в Ada он основан на предварительной версии «Взаимодействующих последовательных процессов» Хоара, принципиально отличающейся от финальной редакции книги. И именно на финальный вариант — с безымянными отправителями/получателями и именованными каналами — опирается модель параллельности в Go.


  1. Kemet
    22.04.2019 14:39

    Как только вышла сия одиозная статья понизил карму автору за мусорность, сейчас захожу — жив курилка, ладно верну карму за стойкость )))


  1. Neftedollar
    22.04.2019 15:24

    >Eval64
    >Eval32
    

    ну очень обобщенно
    вот что такое обобщенное программирование
    REPL
    Microsoft (R) F# Interactive version 10.2.3 for F# 4.5
    > let inline add a b = a + b;;
    val inline add :
    a: ^a -> b: ^b -> ^c
    when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
    > add 2 3;;
    val it : int = 5
    > add System.Numerics.BigInteger.One System.Numerics.BigInteger.MinusOne;;
    val it : System.Numerics.BigInteger = 0 {IsEven = true;
    IsOne = false;
    IsPowerOfTwo = false;
    IsZero = true;
    Sign = 0;}
    > add "wat!!!?" "man";;
    val it : string = "wat!!!?man"


    1. adverax Автор
      22.04.2019 15:29
      -1

      Википедия об обобщенном программировании говорит:

      парадигма программирования, заключающаяся в таком описании данных и алгоритмов, которое можно применять к различным типам данных, не меняя само это описание. В том или ином виде поддерживается разными языками программирования. Возможности обобщённого программирования впервые появились в виде дженериков (обобщённых функций) в 1970-х годах в языках Клу и Ада, затем в виде параметрического полиморфизма в ML и его потомках, а затем во многих объектно-ориентированных языках, таких как C++, Java, Object Pascal[1], D, Eiffel, языках для платформы .NET и других.

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


      1. PsyHaSTe
        22.04.2019 15:34

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


  1. Zalechi
    22.04.2019 15:27

    Предположим я менеджер, но я не понял ничего. Вижу какие то функции, условия, но что они делают честно не вкурил.

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

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


    1. adverax Автор
      22.04.2019 15:36

      В таком случае, Вам могут подойти языки типа Lua, а, лучше, Python (имеет большую практическую ценность), как самые легкие в изучении. Следом за ними идет Go.


      1. Zalechi
        22.04.2019 15:55

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

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

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

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

        {пройдись по таблице из этого файла:(имя файла);
        {выведи на экран сумму (таких-то элементов);
        }
        }


        Что-то такое, а не все эти сложные математические конструкции.


        1. adverax Автор
          22.04.2019 16:05

          Если Вам нужна всего лишь обработка данных, возможно Вам вообще не нужно программирование на императивных языках. Эта отрасль называется DataSince и для нее используют языки типа (R, Python), однако существует ряд визуальных сред где такая обработка может быть проведена с минимальными трудозатратами.


          1. Zalechi
            22.04.2019 16:15

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

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


          1. Chaos_Optima
            22.04.2019 16:24

            Вы верно хотели сказать Data Science


            1. adverax Автор
              22.04.2019 16:27

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


          1. Zalechi
            22.04.2019 16:36

            Пожалуй такой пример был бы круче:
            {Программа, прочитай, затем занеси данные из такого-то <файла> в оперативную память;
            Процессор, перемножь все числовые данные и сохрани результат(р) в память;
            Графический процессор выведи (р) на экран;
            }


  1. mjr27
    22.04.2019 17:01

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


    После go осталось только одно послевкусие: "статический бинарник на выходе это офигенно". И это явно не заслуга самого языка.


  1. fogone
    22.04.2019 22:33
    +1

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


    1. vassabi
      23.04.2019 10:50

      возможно, что в этом и был смысл создания го: «больше хайпа богу хайпа» (с)ВХ40к


  1. prospero78su
    23.04.2019 08:03

    Спасибо за статью. В закладки)


  1. adverax Автор
    23.04.2019 16:04
    -1

    Для всех конструктивно мыслящих оптимистов была написана финальная часть статьи ЭКСПЕРИМЕНТ.


    1. Zalechi
      23.04.2019 16:19

      ограниченное видение и мышление, — это как у лошади, которая видит только прямо.


    1. PsyHaSTe
      23.04.2019 18:35
      +1

      Очень похоже на то, как всех людей которым не понравились новые «Охотники за привидениями» заклеймили женоненавистниками и нетолерантными личностями. Кстати, этим грешат как раз в штатах, так что в этом плане они не передовая страна, а самая что ни на есть отсталая. И я не про Россию говорю, а в сравнении хотя бы с Нидерландами или Зеландией.

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

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


  1. adverax Автор
    24.04.2019 13:21
    -1

    Для ответа на резкую критику читателей, в статью добавлен раздел РЕЗЮМЕ.


    1. TicSo
      24.04.2019 17:02

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

      Мне, например, тема интересна, хотелось бы и «продолжения»… с конкретными примерами, проблемами. Также интересно ваше мнение, — возможно ли использование языка для построения сайта-продаж, приложения уровня выше среднего, т.е. чтобы и web_server и работа с базой данных (например, postgresql) и бизнес-логика… аля_авито_розетка_возможна? Есть четкая грань, чего на go делать точно не разумно? Спасибо.



      1. adverax Автор
        24.04.2019 18:26
        -1

        В начале статьи я писал, что я пишу на Go уже свыше двух с половиной лет. Из них более двух лет я посвятил разработке масштабируемого высоконагруженного проекта, написанного полностью на Go. Почему так долго? Потому, что я полностью писал его сам, параллельно изучая тонкости языка. В добавок к этому выступал еще и в роли аналитика. Это позволяет мне судить о достоинствах и недостатках языка. До этого работал с разными языками PHP, C++, Delphi, Prolog. Поэтому с уверенностью могу сказать, что Go НЕ предназначен для низкоуровневых операций. В нем нет указательной арифметики. На нем не совсем удобно обрабатывать даже простые строки в юникоде. Например, на нем много тяжелее даются парсеры, чем в том же Delphi или C++. Для таких сложных низкоуровневых операций я бы предпочел выбрать другой язык. Однако, Go, при необходимости, может подключать внешние плагины, да и к тому же у него есть CGo (хотя надобность в нем все уменьшается).

        Что касается сайта продаж, то такие проекты (а также микросервисы) в основном и реализуются на Go. Причем реализуются весьма просто и элегантно. Многие используют для этого фреймворки, хотя best practics и не рекомендует это делать.

        Что же касается продолжения статьи, то его скорей всего на Хабре не будет, поскольку в Recovery Mode я публиковать свои статьи не собираюсь (карма не позволяет). Возможно, продолжение просто выйдет на каком-нибудь другом сайте.


    1. Chaos_Optima
      24.04.2019 17:33

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

      Ох ну давайте взглянем на этот список.
      JS — Динамический язык (я думаю нет смысла обяснять почему в нём нет дженериков)
      SQL — Не назвал бы его языком программирования
      1С — Сомневаюсь что они там в принципе нужны
      PHP — Есть
      Java — Есть
      Python — Динамический
      С# — Есть
      С++ — Есть
      PL\Sql — Тоже что и SQL
      Go — Нет

      Если брать языки только общего назначения (JS, PHP, Java, Python, С#, С++, Go) то только у го нет дженериков
      Другие языки типа Rust много лучше (по крайней по номинациям сайта XXX). Опять же, если мы взглянем на статистику самых востребованных языков, то мы вообще не обнаружим язык Rust в списке или же он будет где-то внизу рейтинга. Лично мне, Rust нравится, но я выбрал Go


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

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

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

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


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


      1. adverax Автор
        24.04.2019 18:31
        -1

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


        1. Chaos_Optima
          24.04.2019 23:54

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


      1. eandr_67
        24.04.2019 22:40

        PHP — Есть
        В PHP нет механизмов обобщённого программирования. Для уменьшения дублирования кода в PHP есть типажи (trait). Но использовать их для эмуляции generic — это сознательно уменьшать надёжность кода: придётся отказаться от автоматической проверки типов параметров.


        1. Chaos_Optima
          24.04.2019 23:57

          То есть вот тут вот не дженерики? wiki.php.net/rfc/generics
          Я просто PHP уже лет 8 как не видел, но всё равно интересно узнать.


          1. eandr_67
            25.04.2019 09:50

            RFC — это не актуальное состояние, а предложения по внесению изменений. Указанная вами заявка более 3 лет висит в статусе «черновик» — не то, что до голосования, а даже до стадии обсуждения не дошла.


            1. Chaos_Optima
              25.04.2019 11:13

              А понял, спасибо что разъяснили


  1. WayMax
    26.04.2019 08:57

    Не вижу логики:
    — мы уберем "{" чтобы меньше надо было печатать, но добавим ":" к каждому знаку "="
    — мы придумали язык который удобно читать, но одна строчка на другом языке равно полотну текста на языке Go

    Лично для меня Go не читаем абсолютно и я не понимаю почему Go должен быть понятнее для человека который никогда не программировал чем какой-нибудь C#.