kouzdra (kouzdra) wrote,
kouzdra
kouzdra

Category:

Разгребание наслоений мусора

Посмотрел внимательно на язык Go.

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

Для начала вводная - Go - это статически компилируемый, причем без особенных изысков со стороны компилятора, язык. Раскладка проекта/пакетов по каталогам фиксирована и слизана примерно с Java (что очень правильно, бо ликвидирует совершенно ненужный творческий бардак, свойственный тому же С/C++). Есть понятие workspace etc.

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

Дропнули кучу считавшихся нужными языковых конструкций и заменили их набором простых хаков, которые их очень неплохо заменяют. В результате imho получилось что-то относящееся к прочим мэйнстримным языкам примерно как С/Pascal относились к PL/I и Algol-68. Причем с явным потенциалом для развития заложенных в него идей (я уже много думаю).

Основные отличия:

Возврат к указателям: у значений (и структур и даже таких тяжелых как массив), семантика присваивания - копирование. Если надо семантику указателей - их и используйте, либо юзайте "указателеподобные" proxy-типы - интерфейсы и вырезки (slices). Решает кучу проблем и с семантикой (тонкости сравнения типа Integer в плане == и equals, равно как и его смешение с == над int - известная песня).

И с эффективностью. Поскольку принцип "все составные объекты живут в куче" стоит дороговато.

Отказ от объектности и наследования: методы есть - но это просто специального вида функции получающие особым параметром значение (любого типа) или - указатель на него. Никаких VMT нет. Конструкторов тоже нет. Напишите функцию если надо.

И есть интерфейсы - которые именно "интерфейсы в прямом смысле слова" - то есть список сигнатур. Значение типа интерфейс это если грубо пара "значение + VMT" (я давно об этом мечтал). Близкий и видимо единственный аналог - классы типов в Haskell (но там есть явное наследование), тут есть возможность при описании интерфейса включить в него другой, сабтайпинг есть, но чисто структурный. Чтобы тип преобразовать в интерфейс требуется просто соответствие сигнатур.

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

Выкинуты исключения и try-catch (есть забавная и простая замена в виде конструкции defer и пары встроенных функций).

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

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

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

Что (более или менее) нового: встроенная языковая поддержка light-weight тредов - они там называются goroutines, пишется так:
go вызов функции

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

Мутексы есть, но основное средство - встроенный тип "chan" и операторы чтения/записи и селект. Пример всего этого:
c := make(chan int)  // Allocate a channel.
// Start the sort in a goroutine; when it completes, signal on the channel.
go func() {
    list.Sort()
    c <- 1  // Send a signal; value does not matter.
}()
doSomethingForAWhile()
<-c   // Wait for sort to finish; discard sent value.


Оператор отложенного вызова defer - фича довольно важная, своего рода динамическое задание "деструктора" - defer'ы выполняются при выходе из функции после вычисления значения операции return. Фича странная, но полезная и заменяющая довольно много "традиционных" вещей.

Возможность switch'a по конкретным типам интерфейсов (ближайший аналог - inspect в Simula-67) - это вместо tagged unions, dynamic-casts или instanceof.

Странный, но полезный, хак в виде возможности для функции вернуть несколько значений:
func nextInt(b []byte, i int) (int, int) {
    for ; i < len(b) && !isDigit(b[i]); i++ {
    }
    x := 0
    for ; i < len(b) && isDigit(b[i]); i++ {
        x = x*10 + int(b[i])-'0'
    }
    return x, i
}
...
for i := 0; i << len(b); {
        x, i = nextInt(b, i)
        fmt.Println(x)
    }


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


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

При этом с точки зрения дизайна ЯП он очень ценен imho как возможная отправная точка, в которой не давят многие привычные уже до одури решения, которые мы обычно полагаем "сверхнеобходимыми".
Tags: go, Компутерщина, Языки программирования
Subscribe
  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 15 comments