Gaperton (gaperton) wrote,
Gaperton
gaperton

Category:

Язык программирования Google Go.

Не так давно Google сделал анонс нового языка собственной разработки. Обсуждения в сети в основном показывают, что люди не поняли, что этой хреновиной хотел сказать Google и зачем вообще они сделали новый язык. Хотя об этом недвусмысленно заявлено в двух абзацах language design FAQ. Кто б его еще читал, правда? :) На такие глупости просто нет времени, ибо не секрет, что публика в форумах и блогах предпочитает писать. Причем, не контент. А "комменты", которые "рулят".

Да, о чем это я? О предназначении языка Go. :) Так давайте начнем с того, что почитаем, что же нам хотят об этом сказать его авторы:

http://golang.org/doc/go_lang_faq.html#creating_a_new_language
Go was born out of frustration with existing languages and environments for systems programming. Programming had become too difficult and the choice of languages was partly to blame. One had to choose either efficient compilation, efficient execution, or ease of programming; all three were not available in the same mainstream language. Programmers who could were choosing ease over safety and efficiency by moving to dynamically typed languages such as Python and JavaScript rather than C++ or, to a lesser extent, Java.

Go is an attempt to combine the ease of programming of an interpreted, dynamically typed language with the efficiency and safety of a statically typed, compiled language. It also aims to be modern, with support for networked and multicore computing. Finally, it is intended to be fast: it should take at most a few seconds to build a large executable on a single computer. To meet these goals required addressing a number of linguistic issues: an expressive but lightweight type system; concurrency and garbage collection; rigid dependency specification; and so on. These cannot be addressed well by libraries or tools; a new language was called for.

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

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

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

Программы компилируются долго? Я отлично понимаю, о чем парни говорят. Полная сборка клиента CQG, где я работал, занимала в начале 2000-х около 9 часов. Это кошмар, радикально понижающий продуктивность, поскольку удлинняет цикл экспериментов.

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

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

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

Ознакомившись с мотивацией разрабочиков, я решил, что Go определенно стоит того, чтобы с ним разобраться. Почему? Потому, что практика показывает, что люди давно разучились делать простые вещи. И разучились их ценить. А ведь простые вещи делать гораздо сложнее, чем сложные. Cреди авторов Go есть такие, как Кен Томпсон, и кому, как ни ему, одному из отцов UNIX, понимать толк в простоте.

Хорошо, ну, и какие же у них были основные принципы при разработке?

Programming today involves too much bookkeeping, repetition, and clerical work. As Dick Gabriel says, “Old programs read like quiet conversations between a well-spoken research worker and a well-studied mechanical colleague, not as a debate with a compiler. Who'd have guessed sophistication bought such noise?” The sophistication is worthwhile—no one wants to go back to the old languages—but can it be more quietly achieved?

Go attempts to reduce the amount of typing in both senses of the word. Throughout its design, we have tried to reduce clutter and complexity. There are no forward declarations and no header files; everything is declared exactly once. Initialization is expressive, automatic, and easy to use. Syntax is clean and light on keywords. Stuttering (foo.Foo* myFoo = new(foo.Foo)) is reduced by simple type derivation using the := declare-and-initialize construct. And perhaps most radically, there is no type hierarchy: types just are, they don't have to announce their relationships. These simplifications allow Go to be expressive yet comprehensible without sacrificing, well, sophistication.

Another important principle is to keep the concepts orthogonal. Methods can be implemented for any type; structures represent data while interfaces represent abstraction; and so on. Orthogonality makes it easier to understand what happens when things combine.

Сейчас я попробую проиллюстрировать эти три абзаца. Все сразу, и одним примером. Я покажу, как они обошлись с объектной системой. Она основана на двух принципах - duck typing, и упомянутой ими "ортогональности".

"Ортогональность" проявляется в том, что вы можете объявить метод для почти любого типа языка. Просто пишете что-то вроде:

func ( x int ) sqrt() int { ... }

И все, можно писать x.sqrt(), и если x это целое, система вас поймет. А можете сделать так:

type SecsFrom1900 int
type Minutes int
type Seconds int
func ( x SecsFrom1900 ) take_min_sec() ( min Minutes, sec Seconds ) { ... }

И тогда

min, sec = some_time.take_min_sec()

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

Но как же у нас с ООП? Ах, да. Забыл.

type TimeOfDay struct {
min Minutes
sec Seconds
hour Hours
}

func ( x TimeOfDay ) to_secs_from_1900() SecsFrom1900 { ... }

На самом деле, имея возможность возвращать несколько значений из функции, и "ортогональность", во многих случаях вы не захотите плодить структур, и будете делать это ровно тогда, когда нужно. Это просто не нужно. Объектом, как вы понимаете, в некотором смысле, является все. В довольно необычном смысле, на этот раз. Не так, как в Smalltalk.

Ну какие же у нас объекты без полиморфизма, скажете вы. И будете правы.

type Second_i interface {
secs() Seconds
}

type Minutes_i interface {
mins() Minutes
}

type MinSecs_i interface{
Second_i
Minute_i
}

Объявили мы такие интерфейсы. Для того, чтобы какой-либо тип ми соответствовал, нам не надо делать никаких дополнительных объявлений. Им соответствует любой тип, к которому мы объявили достаточное количество нужных "методов". Как вы понимаете, пустому интерфейсу interface{} естественным образом соответствует вообще любой тип. Все есть Object? Нет, все есть interface{}.

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

Да, а наследование-то, наследование?

type TimeOfYear struct {
TimeOfDay
day Day
}

Получите, распишитесь :). Если вы опустите имя поля в объявлении структуры, то к ней перейдут все методы, объявленные для типа. Таким образом, изобразить "множественное наследование" для простого случая не представляет собой какой-либо проблемы. Более того, при "множественном наследовании" не возникает парадоксов, как в С++, и следующего из этого заворота мозгов - здесь "наследование" однозначно понимается как специальный случай аггрегации, и никакой динамической диспетчеризации при этом не происходит. Динамика - это интерфейсы.

Все, уважаемые коллеги. Это вся объектная система.

The last but not least, в Go есть настоящие замыкания - функция является таким же значением, как и все остальные.

И совсем даже не least - это великолепная встроенная поддержка параллельного программирования.

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

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

И это чертовски хорошо. В наше время - большая редкость. Если заинтересовались, я настоятельно рекомендую ознакомиться с его спецификацией.
http://golang.org/

Будем следить за развитием этого проекта.

PS: Да, мои примеры кода могут содержать ошибки. Компилятора Go у меня нет. И не будет, пока не появится порт под Windows или MacOS на Power (последнее - никогда). Так что если вы поправите ошибки, буду признателен.
Tags: go, go language, golang, google, google go
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 114 comments