LINUX.ORG.RU

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

 


0

10

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

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

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

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

★★★★

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

Каким боком операторы относятся к ООП?

Таким, что для разных классов один и тот же оператор имеет разный смысл. Например сложение строк и сложение векторов(не std::vector, а векторов из математики).

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

когда иксперты походя называют Go «примитивным»

Так он и есть примитивный. Привет из прошлого века.

anonymous
()

перегрузки тоже завезут?

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

В целом мне нравится. Нет этих мерзких угловых скобок :).

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

anonymous
()

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

Шёл 2019 год~

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

А разве не всегда можно определить на этапе компиляции что тип реализует нужный интерфейс? С фактическими параметрами функций оно же работает.
Еще мне не понятно зачем при вызове параметризированной функции указывать явно тип. Или это все ради того чтобы не усложнять компилятор, линтеры и вот это все?

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

Надеюсь, несколько лет всё же продержимся. А потом есть план Б.

Переход на Оберон?

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

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

Для этого ООП не нужен, перегрузка операторов есть и в haskell и в OCaml (не затрагивая объекты) и в rust.

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

И, конечно, самим интересно, можно ли так расширить язык, не разрушив его (как произошло с C++)

Как бы шаблоны создали С++, а не разурушили.

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

Тем не менее в рамках ООП перегрузка операторов удобная и полезная возможность.

rumgot ★★★★★
()

в Го вообще не нужны дженерики. Зачем они там, писать всякие обобщенные алгоритмы? Так для алгоритмов уже есть C++, раст и прочие с мощными системами типов, зеро кост и прочими векторизациями.

А во всех остальных случаях - объявить тип как interface{} и сконвертировать его в рантайме во что надо ну вообще не проблема.

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

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

А разве не всегда можно определить на этапе компиляции что тип реализует нужный интерфейс?

Нет. Интерфейсы предназначены для рантайма. Скажем, io.Writer во время компиляции не знает, какой конкретный объект ему передадут.

Еще мне не понятно зачем при вызове параметризированной функции указывать явно тип

Это как раз опционально. Можно указать, можно не указывать (компилятор выведет типы). Всё как в C++.

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

Как бы шаблоны создали С++, а не разрушили.

Если бы они не оказались тьюринг-полным языком сами по себе, это было бы ещё полбеды. С открытиями Александреску в C++ стало возможным творить невообразимые вещи. А если что-то в языке возможно сделать — это непременно будет делаться. И это придётся сопровождать.

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

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

Очень верно. Тем не менее развиваться и меняться языку нужно, как и всему живому в нашем мире.

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

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

Да вроде всё хорошо, просто к типу ресивера добавился в скобках шаблонный параметр. Остально как было.

func (t *Tree(E)) Contains(v E) bool {
    return *t.find(e) != nil
}
hbee ★★★★
() автор топика
Ответ на: комментарий от hbee

С открытиями Александреску в C++ стало возможным творить невообразимые вещи

И это позволило решать на С++ задачи, которые в «си с классами» были немыслимы

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

И это позволило решать на С++ задачи, которые в «си с классами» были немыслимы

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

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

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

Тут как раз без проблем. Рефлексия в рантайме, она имеет дело с уже инстанцированными типами. Единственно, reflect.Type.String() от шаблонного типа вернёт что-то вроде «Tree(float64)».

hbee ★★★★
() автор топика

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

RedPossum ★★★★★
()
Последнее исправление: RedPossum (всего исправлений: 1)
Ответ на: комментарий от hbee

нечеловеческий нечитаемый код

Полегче с городскими легендами.

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

Tree - generic тип с параметром E?

Т.е. в нормальном синтаксисе что-то вроде:

fun Contains<E>(t: Tree<E>, v: E): bool

anonymous
()
Ответ на: комментарий от hbee
func (t *Tree(E)) Contains(v E) bool {
    return *t.find(e) != nil
}

Почему это говно на 50% состоит из синтаксического мусора даже в таком примитивном примере?

func (t *Tree(E))

Зачем нужен этот мусор. Что это за нахрен? Зачем оно? Что это за нелепое t - это что? Название функции? Аргумент?

Contains(v E)

Это что?

*t.find(e) != nil

Это что? Нахрена тут звёзды? nil? Что за херня?

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

перегрузка операторов есть и в haskell и в OCaml (не затрагивая объекты) и в rust.

Адепт врёт. Ничего там нету.

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

Нет этих мерзких угловых скобок

из-за дженериков код всегда превращается в нечитаемое говно

V

Так вот кто лулзы для /r/pcj генерит.

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

Плюсую этого оратора. Сам в Go с первых стабильных версий. Но вот эта вот реализация дженериков - это обосрамс какой-то. Если пилят вторую версию, нужно, наверное, делать нормально и волноваться больше о consistency, а не backward compatibility (который всё равно ломают).

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

Как будто бы с угловыми скобками он становится читаемым. Больше, меньше. Вот, например, генерик-фигерик

Т<ВоюМать>
Т(ВоюМать)

Первое похоже на сравнение. Второе на вызов функции. Оба варианта так себе. Есть нормальны, поцанский, вариант

Тэ из рода Серых Псов.

Вот тут сразу всё видно и понятно.

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

Когда в Rust завезут нормальный синтаксис?

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

Вот тут сразу всё видно и понятно.

А покажи определение функции примерно с таким синтаксисом. Наверняка будет многословное жиденькое.

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

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

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

Это стукач-тред, братан, здесь бесполезно что-то писать.

anonymous
()

будут наподобие шаблонов C++

Всё, приплыли! Теперь и в голанге начнётся «ехал шаблон, через шаблон в шаблон». Коготок увяз — всей птичке пропасть!

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

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

eao197 ★★★★★
()

Чёт не душевные какие-то черновичёчки. Страшно смотреть. Может всё-таки не надо.

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

Вот что за манера, из двух миров брать худшее.

Шаблоны могут частичную специализацию, но ломаются на рекурсии, упираясь в бесконечное развёртывание. Дженерики могут рекурсию, но не могут частичную специализацию. А тут — ни нашим, ни вашим. Раста обкурились?

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

В какую рекурсию ты там собрался мочь? Показывай. Для генериков.

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

Вообще-то специализация/частичная специализация — это крутые фичи. Как и переопределение операторов.
Если всего этого не будет. Голанг опять будет неидеален и критикуем.
Ну зато может будет повод разрабам пилить бюджет гугла и выпускать версии 3.0, 4.0 и т.д. где постепенно будут эти фичи вводить.

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

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

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

Generic с использованием шаблонов ...?
Излюбленная тема программистов, находящихся в третьей палате психдиспансера г.Дураковка.

Владимир

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

Годнота или как обычно?

В сочетании с CPUQuota

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

А разве не всегда можно определить на этапе компиляции что тип реализует нужный интерфейс?


Нет. Интерфейсы предназначены для рантайма. Скажем, io.Writer во время компиляции не знает, какой конкретный объект ему передадут.

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

func foo(type T io.Writer)(t T, b []byte) (int, error) {
    return t.Write(b)
}

foo(os.Stdout, []byte("Hello, World.")) // ok
var a int
foo(a, []byte("Hello, World.")) // compilation error: variable of int type does not satisfy io.Writer interface

Не подскажешь где этот вопрос раскрыт авторами? В draft'е есть? Я его пока не осилил.

Это как раз опционально. Можно указать, можно не указывать (компилятор выведет типы). Всё как в C++.

Ну тогда нормально.

urxvt ★★★★★
()
Последнее исправление: urxvt (всего исправлений: 1)
Ответ на: комментарий от anonymous

пока что исследование проводится

«Исследование», ЛМАО. С 1970го недостаточно «исследований» провели, либо это были неправильные «исследования». А с 2009го недостаточно реализаций применимо к Go наобсуждали. Такими темпами нужно ещё 50 лет на «исследования» и 10 на обсуждения.

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

func (t *Tree(E))

Это ресивер, делает обычную функцию «методом». Это как self/this, только в явном виде и с именем t

Contains(v E)

Название метода

*t.find(e) != nil

Это звезда - операция разыменования. Очевидно что кто-то сделал метод find у которого value receiver, а возвращает этот метод указатель на году, или nil, если нет такого значения.

Тут вообще ничего от дженериков по большому счету нет, а ты похоже на гонке ни строчки не написал и кудахтаешь

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

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

Потому что нет встроенного механизма, позволяющего назначить операторы +, -, * и т.д. для произвольных типов. Соответственно невозможно определить интерфейс для какого-нибудь int, uint и пр., они так и остаются builtin special cases. Отсюда (в драфте) костыль с контрактом и простынёй из int, int32, int8, int16, uint, uint32, uint8, uint16… Если навесить это на интерфейсы, тогда непонятно как те должны себя вести в ряде случаев (например, когда простыня контрактная, а интерфейс рантаймный).

anonymous
()

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

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