Skip to content

Instantly share code, notes, and snippets.

@vabka
Last active November 6, 2019 17:31
Show Gist options
  • Save vabka/ceef6cc0e68cbddb502160c36f19a12a to your computer and use it in GitHub Desktop.
Save vabka/ceef6cc0e68cbddb502160c36f19a12a to your computer and use it in GitHub Desktop.

Как сейчас

  1. сегодня женерики в го - это только шаблоны через кодогенерацию и шаблоны
  2. допустим, что '!' в начале коммента - инструкция для кодогенератора
  3. '!placeholder' - значит, что тип будет использоваться в качестве "дырки" в шаблоне
  4. '!template' - значит, что тип или функция - это шаблоны
//!placeholder
type T = interface{}

//!template
type Option struct {
  value T
  hasValue bool
}

func (this *Option) SetValue(value T) {
  this.Value = value
  this.hasValue = true
}

func (this *Option) SetNone() {
  this.Value = nil
  this.hasValue = false
}

func (this *Option) Value() T {
  if this.hasValue {
    return this.Value
  } else {
    panic("option has no value!")
  }
}

func (this *Option) HasValue() bool {
  return this.hasValue
}  

Плюсы:

  • Реализуется крайне просто
  • В рантайме не будет разницы, по сравнению с рукописным кодом
  • Экономит время разработчика, по сравнению с рукописным кодом
  • Не нужно вносить изменений в компилятор, стандартную библиотеку, и рантайм

Минусы:

  • Перед компиляцией нужно генерировать новый код, анализировать все использования структуры => тратить время компилятора
  • IDE не может нормально подсказать, какой возвращаемый тип будет у Value()
  • Все минусы, которые применимы к шаблонам в C++ применимы и здесь - пока не дойдёт до компиляции, об ошибках известно не будет
  • Волшебные комментарии
  • Компилятор должен будет N раз прочитать один и тот же текст с незначительными изменениями
  • Никакого полиморфизма
  • Непонятно, как объявить женерик от женерика
  • Непонятно, куда улучшать

Альтернативный вариант

Пока только в виде техже шаблонов

//далее псевдого

//<T> => на место T можно вставить любой тип
type Option<T> struct {
  value T
  hasValue bool
}

func (this *Option<T>) SetValue(value T) {
  this.Value = value
  this.hasValue = true
}

func (this *Option<T>) SetNone() {
  this.Value = nil
  this.hasValue = false
}

func (this *Option<T>) Value() T {
  if this.hasValue {
    return this.Value
  } else {
    panic("option has no value!")
  }
}

func (this *Option<T>) HasValue() bool {
  return this.hasValue
}  

Плюсы

  • Встроено в синтаксис => IDE знает, как с этим работать
  • Компилятору надо меньше читать с диска
  • Нет кодогенерации => меньше скрытой записи на диск перед компиляцией
  • Проще отладка, тк исходники не меняются
  • Типы известны до компиляции

Минусы

  • В идеале, надо менять встроенные типы - slice, map, chan, func, tuple
  • В идеале, надо менять встроенные функции i.e. make(type, args..) -> make<[]T | map[T1] T2>(...args)
  • Нужно расширять компилятор - это дорого
  • Не понятно, как через женерики выразить кортежи в го
  • Нужно больше писать, из-за того, какой синтаксис в го используется для объявления методов
  • Не понятно, можно ли писать "специальные" реализации методов для конкретных типов (такой синтаксис намекает, что можно). Например:
funс (this *Option<int32>) HasValue() bool {
  return true
}
  • Некоторым может быть непонятно, что нельзя вставить вместо T переменную, которая хранит метаданные о типе
  • Изменение стандартной библиотеки - это серьёзный breaking changes
  • Треугольные скобки - это плохо, тк это не парный символ
  • Не понятно, можно ли сделать женерик от конкретного значения (например от нуля, единицы, или пустой строки)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment