LINUX.ORG.RU

Опубликован почти окончательный драфт генериков в Go

 


0

10

За подробностями в Go-блог (blog.golang.org/why-generics), там есть ссылка на собственно драфт.

Генерики семантически будут наподобие шаблонов C++, т.е. не boxed (как в Java), а value: компилятор будет генерировать копии с конкретными типами.

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

В релизе появится всё это не скоро, в Go 2, срок выхода которого неизвестен. Go 1.13 появится на днях, 1.14 — в ноябре, к десятилетию первого публичного бета-релиза.

★★★★

Ответ на: комментарий от annulen

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

abcq ★★
()
Ответ на: комментарий от vertexua

Увы плохое отношение, хоть у С, хоть у С++, дорогобохато опаснорисково

abcq ★★
()
Ответ на: комментарий от Joe_Bishop

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

Ну да. Дело же в исключениях. Не в байт-коде, не в jit-е, не в особенностях GC (и отсутствия навыков/желания его тюнить), не в жирных java-вских структурах данных, не в boxing/unboxing, не в чрезмерном увлечении run-time рефлексией… А в обработке ошибок.

eao197 ★★★★★
()
Ответ на: комментарий от abcq

Есть устойчивое ощущение, что на C++ вы не программируете. Ни на Си с классами, ни на современном.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

не в особенностях GC (и отсутствия навыков/желания его тюнить)

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

не в жирных java-вских структурах данных, не в boxing/unboxing, не в чрезмерном увлечении run-time рефлексией… А в обработке ошибок.

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

Joe_Bishop
()
Ответ на: комментарий от Joe_Bishop

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

Самое смешное, что GC в Go именно так и работает: оптимизируем продолжительность пауз ценой всего остального. Подробности: https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e

Zenom ★★★
()
Ответ на: комментарий от Joe_Bishop

неправда

file := os.Open(fileName) or err {
    return nil, errors.Wrap(err, "open config file")
}

Похоже на это предложение: https://github.com/golang/go/issues/32848

Его зарубили за неестественный, «non-Goish» синтаксис, от чего страдает читаемость. Не всегда более краткий код читабельнее.

hbee ★★★★
() автор топика
Ответ на: комментарий от Zenom

Самое смешное, что GC в Go именно так и работает: оптимизируем продолжительность пауз ценой всего остального. Подробности: https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e

Такая, %%ядь, проблема )

У тех, у которых такое является проблемой, Жаба умудряется обгонять в тестах C++.

Joe_Bishop
()
Ответ на: комментарий от abcq

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

Что, сам Безос жрёт этот кактус и плачет или разрабы поддерживают весь хлам на постгресе? Бабки то платят неплохие, наверное под 500К USD на брата в год?

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

foror ★★★★★
()
Ответ на: комментарий от Joe_Bishop

Как раз это – Goish
file := os.Open(fileName) or err

что будет в file в случае ошибки ? И конструкция весьма сложночитаема, например не получается моментально определить, в чем синтаксический смысл строки, в присваивании или условии. Более того, получается что часть переменных находятся в разных областях видимости, при этом создаются в одной строке кода. Существующий синтаксис все же лучше(который if err:=f(x); err != nil{}). Позволят точно дать понять, что это проверка и что создаваемые переменные не используются дальше по коду.

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

Dred ★★★★★
()
Ответ на: комментарий от Dred

что будет в file в случае ошибки ?

обязательный выход из скоупа в котором был вызов os.Open либо возврат переменной типа *of.File (которая не равна nil, если что) из обработчика c помощью yield os.Stdin

идея развита из https://vlang.io/docs#option

в общем и целом конструкция

file := os.Open(fileName) or err {
    return errors.Wrapf(err, "open config file")
}
A(file)

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

match File::open(filename) {
    Ok(file) => {
         A(file)
    }
    Err(err) => {
        return ...
    }
}

При этом позволяет избежать елочки

Joe_Bishop
()
Ответ на: комментарий от Joe_Bishop

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

раст - не го

идея развита из

это тоже не го, более того, то что оно там - не значит что оно хорошо

обязательный выход из скоупа

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

либо

в этом проблема, «либо» заставляет дополнительно проверять, что убивает всю идею

обработчика c помощью yield os.Stdin

либо пример не показательный, либо оно не универсально. Как оно должно работать для мап, например ? Или для курсоров ?

которая не равна nil, если что

но может быть, ссылка вполне может быть nil, более того, это тоже удобно и показательно.

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

Dred ★★★★★
()
Последнее исправление: Dred (всего исправлений: 1)

Я думаю это не аналог шаблонов из С++, а аналог auto из С++. Что имеет смысл, потому что вывод типов в Го уже в каком-то виде и так уже есть. Вот этот пример:

func Reverse (type Element Sequence) (s []Element) {

в С++20 должен выглядеть как-то так:

void Reverse(Sequence auto s) {

Без учёта всяких ссылок и константности, но идея примерно такая. Только то, что в Го называется «контракты» в С++ называется «концепты».

Это правильный подход, С++ движется в этом же направление. Рад видеть, что Го не стал повторять ошибки С++ и пропустил стадию SFINAE, надеюсь, что из С++ SFINAE тоже когда-нибудь выкинут.

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

Нормальная тема. Было бы ещё круто впилить это прямо в Го 1 без ломания совместимости. Разговоры про Го 2 и несовместимые изменения - нет, не привлекательно совсем, ровно наоборот, будет та же история, что и с питоном 3. Как-то это всё не очень это интересно, к тому времени как в Го сломают совместимость, это всё уже будет в С++ вероятно с обратной совместимостью. Очень надеюсь, что и питоновские ошибки тоже будут учтены.

aleksey_tulinov
()
Ответ на: комментарий от aleksey_tulinov

Разговоры про Го 2 и несовместимые изменения - нет, не привлекательно совсем, ровно наоборот, будет та же история, что и с питоном 3.

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

Joe_Bishop
()
Ответ на: комментарий от Joe_Bishop

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

Примеры фстудию

ya-betmen ★★★★★
()
Ответ на: комментарий от Dred

либо пример не показательный, либо оно не универсально. Как оно должно работать для мап, например ? Или для курсоров ?

yield make(map[string]string)

? Так сложно понять?

выход куда ?

return? break? continue? panic?

но на деле крайне нечитабильно и более того, дебажать это сложнее.

чем это нечитабельнее того же if err := ....; err != nil {?

дебажать это сложнее.

почему?

Joe_Bishop
()
Ответ на: комментарий от Joe_Bishop

статическая типизация с возможностью автоматического преобразования

Нет, всё равно не интересно. Возможный более-менее приемлемый вариант: если компилятор Го 2 будет бесшовно компилировать Го 1 с каким-нибудь флагом типа -std=golang1 как компилятор С++ компилирует и С++98 и С++2а. В идеале существовало бы какое-то общее подмножество Го 2 и Го 1 которое компилировалось бы и с -std=golang1, и с -std=golang2.

Любые разговоры про ломание совместимости и EOL - это спасибо, оставьте себе.

aleksey_tulinov
()
Ответ на: комментарий от Joe_Bishop

почему?

нет явной последовательности

return? break? continue? panic?

и что с ними, с переменной, которая глобальнее, что будет ?

чем это нечитабельнее того же

я писал выше, прочти внимательно.

Так сложно понять?

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

Dred ★★★★★
()
Ответ на: комментарий от RazrFalcon

Есть же ?.

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

Joe_Bishop
()
Ответ на: комментарий от RazrFalcon

Есть же ?.

Такие пропозалы в Go-сообществе сбиваются на взлёте самонаводящейся ракетой Cryptic :).

hbee ★★★★
() автор топика
Ответ на: комментарий от Joe_Bishop

Как образом теряется контекст? Это просто сахар на лапшой.

RazrFalcon ★★★★★
()
Ответ на: комментарий от Joe_Bishop

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

А вы могли бы на примерах кода проиллюстрировать свою мысль? Мол, вот так хорошо, а вот так с ? – уже плохо.

eao197 ★★★★★
()
Ответ на: комментарий от Dred

yield нет в Go. Про какую реалиацию ты сейчас говоришь ?

Нет, это совпадение. Он возвращает значение наружу из шкоупа. Желателен для избегания nilable-значений и для возвращения значений по-умолчанию при обработках нештатных ситуаций. Можно использовать что-то другое, например continue with <value> или with <value>.

Например

file := os.Open(fileName) or err {
    log.Warning().Err(err).Msgf("failed to open input file, using stdin instead")
    yield os.Stdin
}

попытается открыть файл с названием fileName и сохранить в переменной file. Если не получилось, сообщит об этом в логе и использует в качестве значения file os.Stdin. Чуть сложно, но гарантирует типобезопасность. Что немаловажно, имеет императивный дух, и не требует адских нечитаемых ёлочек.

Joe_Bishop
()
Ответ на: комментарий от eao197

А вы могли бы на примерах кода проиллюстрировать свою мысль? Мол, вот так хорошо, а вот так с ? – уже плохо.

Лениво. На пальцах так: есть какая-то абстракция Transport с методом Transport, есть её реализации. Метод может зваться в разных местах. Если он будет давать ошибку, то пропуская его с помощью ? мы будем знать, что в какой-то из реализаций произошла ошибка без указания того, какой вызов метод вызвал ошибку – это если мы аннотировали её там. А если не аннотировали, то вообще может показываться какая-то сетевая/дисковая/… низкоуровневая ошибка. Это самый простой случай. В реальности в обработке ошибки могут, кроме аннотаций, случаться всякие восстановления целостности данных, запуски асинхронных задач и т.п.

Joe_Bishop
()
Ответ на: комментарий от Joe_Bishop

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

eao197 ★★★★★
()
Ответ на: комментарий от Joe_Bishop

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

не требует адских нечитаемых ёлочек

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

Dred ★★★★★
()
Ответ на: комментарий от Dred

А если разные ошибки (EOF, ItemNotFound и тд)

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

type ReadResult oneof {
    Length int64
    EOF    int64
    Error  error
}

type Reader interface {
    Read(p []byte) ReadResult
}

// …

for {
    switch v := f.Read(p) {
    case io.Length:
        buf.Write(p[:int(v)]) or err {
            return nil, errors.Wrap(err, "copying from %s into a memory buffer", f.Name())
        }
    case io.EOF:
        buf.Write(p[:int(v)]) or err {
            return nil, errors.Wrap(err, "copying from %s into a memory buffer", f.Name())
        }
        return buf.Bytes(), nil
    case io.Error:
        return nil, errors.Wrapf(err, "reading %s", f.Name())
    }
}

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

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

Joe_Bishop
()
Ответ на: комментарий от hbee

ресурс ускорения Go: улучшить т.н. escape analysis, увеличить долю размещения значений на стеке, а не в куче

И вот в новом 1.13 (вышел пока только RC1):

The compiler has a new implementation of escape analysis that is more precise. For most Go code should be an improvement (in other words, more Go variables and expressions allocated on the stack instead of heap).

https://tip.golang.org/doc/go1.13

Процесс идёт.

hbee ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.