Language Design FAQ @ golang.org の適当訳

golang.org に掲載されている Language Design FAQ の非常に適当な翻訳です。 ところどころ、言い訳がましい(訳注)が挟まるように、内容は保証できませんが、原文を読む参考にどうぞ。 不勉強なので、専門用語の訳詞間違いなどが有ればごめんなさい。

ご意見や、訳の誤りなどがありましたら、ema <ameema@gmail.com> までお寄せください。

Language Design FAQ - 言語設計に関するFAQ

Origins - 起源

What is the history of the project?

このプロジェクトの歴史は?

Robert Griesemer, Rob Pike and Ken Thompson started sketching the goals for a new language on the white board on September 21, 2007. Within a few days the goals had settled into a plan to do something and a fair idea of what it would be. Design continued part-time in parallel with unrelated work. By January 2008, Ken had started work on a compiler with which to explore ideas; it generated C code as its output. By mid-year the language had become a full-time project and had settled enough to attempt a production compiler. In May 2008, Ian Taylor independently started on a GCC front end for Go using the draft specification. Russ Cox joined in late 2008 and helped move the language and libraries from prototype to reality.

2007年9月21日に、Robert Griesemer と Rob Pike と Ken Thompson は、新しい言語の目標をホワイトボードへとスケッチしはじめました。 (訳注:翻訳の自信なし)数日の内に目標は、すべき計画と、綺麗なアイデアとにまとめ上げられました。 設計は無関係な仕事と並行して、パートタイムで続けられました(訳注:いわゆる20%ルールの範囲内でという意味だと思われる)。 2008年1月に、Ken はアイデアを試すために、コンパイラを作り始めました。 そのコンパイラは出力として C のコードをはき出しました。 その年の中頃(mid-year)には、その言語はフルタイムの仕事となり、製品としてのコンパイラを実現するに十分なものとなりました。 2008年5月、Ian Taylor はドラフトの仕様書を元に、独自に Go の GCC フロントエンドを作成し始めました。 Russ Cox は 2008年の後半(late)に参加し、言語並びにライブラリをプロトタイプから現実のものへと昇華させる手助けを行いました。

Many others have contributed ideas, discussions, and code.

多くの方々がアイデア、議論、そしてコードへ貢献しています

Why are you 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 は、システムプログラミングに用いる、現存する言語や環境への不満から生まれました。 プログラミングがあまりにも難しくなり、それは部分的には言語言語における選択のせいでもあります。 ある言語ではコンパイル効率、実効効率、あるいはプログラミングのしやすさの中から一つを選ばねばなりませんでした。 現在主要な言語では一つとして、この全てを実現した言語はありません。 安全性や効率性よりもプログラミングしやすさを選択できるプログラマたちは、 C++ や (より狭い範囲で) Java よりも、Python や JavaScript のような動的型の言語へと流れていきました。

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.

Go はインタプリタや動的型言語のプログラミングしやすさ、ならびに、コンパイラや静的型言語の効率や安全性の双方を実現しています。 また、モダンであることを目指し、ネットワークやマルチコアコンピューティングをサポートしています。 つまるところ、「速さ」に主眼がおかれています。 巨大な実行ファイルのビルドですら、一台のコンピュータで数秒の内に終わるべきです。 これらの目標に合致するために、多数の言語に関する問題へと取り組む必要がありました。 表現が豊かでありながら、軽量の型システムである。 並行処理ができ、ガベージコレクションを備えている。 依存性の指定は厳格である、などなどです。 それらはライブラリやツールでは対処できず、新しい言語の出番となったのです。

What are Go's ancestors?

Go のご先祖様は何?

Go is mostly in the C family (basic syntax), with significant input from the Pascal/Modula/Oberon family (declarations, packages), plus some ideas from languages inspired by Tony Hoare's CSP, such as Newsqueak and Limbo (concurrency). However, it is a new language across the board. In every respect the language was designed by thinking about what programmers do and how to make programming, at least the kind of programming we do, more effective, which means more fun.

Go は、基本的な文法は C ファミリから、 宣言やパッケージなどの、重要な入力は Pascal/Modula/Oberon ファミリから、 加えて、並行処理に関するいくらかのアイデアを Tony Hoare の CSP から得ています (例えば、Newsqueck や Limbo)。 それでもなお、全く新しい言語なのである。 この言語は、少なくとも私たちが取り組むプログラミングにおいて、 より効率よく、より楽しくプログラムを作成するにはどうすればいいのか、 また、プログラマが実際にどのように振る舞うのかについて、 あらゆる観点から徹底的に考えて設計されたのだ。

What are the guiding principles in the design?

設計において、ガイドとした原則にはどのようなものがあるの?

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?

今日のプログラミングは、あまりにも bookkeeping や繰り返しや、事務的な仕事を必要とする。 (訳注:bookkeeping は GC のところで出てくる用法を見るに、メモリマネージメントなどの「帳尻合わせ」とでも訳せばいいように思うが自信がない)。 Dick Gabriel 曰く、 「古きプログラムは、コンパイラとの論争ではなく、 上品な研究員とよく勉強した機械の同僚の間で交わされる静かな会話のように読まれた。 (よく分かりません)いったい誰が、洗練を推測し、そのようなノイズを購入したというのか?」。 その洗練は価値のあるものであります(誰も古い言語へと戻りたがらないでしょう)が、 よりひっそりと実現できないのでしょうか?

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.

Go は、二つの意味で typing を減らします。 私たちは、その設計のいたるところで、ノイズや複雑さを減らすよう腐心しました。 前方宣言やヘッダファイルは最早必要有りません。 全てはただ一度きり宣言されるのです。 初期化の表現は豊かであり、自動的であり、簡単に使用できます。 構文は明確で、予約語は軽量です。 どもり(foo.Foo* myFoo = new(foo.Foo))は := declare-and-initialize construct によるシンプルな型導出によって除去されます。 さらに、おそらく一番ラディカルなのは、型階層がないということです。 型は、それらの関係を喧騒することなく、ただそこにあるのです。 これらの単純化により、Go は良さや洗練を犠牲にすることなく、表現豊かにも関わらず理解しやすいものになっています。

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.

もう一つの重要な原則は、コンセプト同士を直交に保つことです。 メソッドはあらゆる型にむけて実装できる。 構造体はデータを表現し、インタフェースは抽象化を表現する、などです。 直交性によって、物事を組み合わせると、どのような事が起きるのか、を容易に理解することができます。

Changes from C - C からの変更点

Why is the syntax so different from C?

どうして、Cと構文がそんなに違うの?

Other than declaration syntax, the differences are not major and stem from two desires. First, the syntax should feel light, without too many mandatory keywords, repetition, or arcana. Second, the language has been designed to be easy to analyze and can be parsed without a symbol table. This makes it much easier to build tools such as debuggers, dependency analyzers, automated documentation extractors, IDE plug-ins, and so on. C and its descendants are notoriously difficult in this regard.

宣言構文を除いては、違いは些細であるか、二つの幹から来るものです。 第一に、構文を軽いと感じられるものであるべきです。 義務的な予約語や、繰り返し、あるいは奥義は必要有りません。 第二に、この言語は、解析が簡単で、シンボル表を用いずにパーズできるように設計されています。 そのため、デバッガや依存解析器、自動ドキュメント作成、IDE のプラグインなどといったビルドツールの作成は容易です。 Cやその子孫は、この観点において悪名高い。

Why are declarations backwards?

なぜ、型宣言を後置としたのか

They're only backwards if you're used to C. In C, the notion is that a variable is declared like an expression denoting its type, which is a nice idea, but the type and expression grammars don't mix very well and the results can be confusing; consider function pointers. Go mostly separates expression and type syntax and that simplifies things (using prefix * for pointers is an exception that proves the rule). In C, the declaration

あなたがもしCを使っていたとしたら、ここには後置しか有りません。 Cにおける発想は、「変数はその型を表す式のように宣言される」です。 これは良いアイデアですが、この型と式の文法はあまりよく適合せず、 その結果混乱を生み出します。関数ポインタのことを考えてみて下さい。 Go では、大部分において、式と型の構文は分割され、物事を単純にしています (ポインタに * というプリフィックスを用いることは、規則を証明する例外です)。 C における以下の宣言では、

	int* a, b;
	int* a, b;

declares a to be a pointer but not b; in Go

a はポインタとなりますが、b はなりません。Go では

var a, b *int;
var a, b *int;

declares both to be pointers. This is clearer and more regular. Also, the := short declaration form argues that a full variable declaration should present the same order as := so

双方がポインタとなります。より明確で、より規則的です。 (正確に訳せませんが、意味としては以下で外していないつもりです) := による短い宣言形式によって、 := と同順による表現で、完全な変数宣言を行うことができます。

var a uint64 = 1;
var a uint64 = 1;

has the same effect as

は、以下と同様の効果を与えます。

a := uint64(1);
a := uint64(1);

Parsing is also simplified by having a distinct grammar for types that is not just the expression grammar; keywords such as func and chan keep things clear.

明確に、式の文法ではなく、型と区別できる文法を持つことでパーズもまた単純化されています。 予約語funcおよびchanが、物事を明確にしています。

Why is there no pointer arithmetic?

どうして、ポインタの算術演算は存在しないのですか?

Safety. Without pointer arithmetic it's possible to create a language that can never derive an illegal address that succeeds incorrectly. Compiler and hardware technology have advanced to the point where a loop using array indices can be as efficient as a loop using pointer arithmetic. Also, the lack of pointer arithmetic can simplify the implementation of the garbage collector.

安全性のためです。ポインタへの算術演算を取り除くことで、 誤って不正なアドレスを導き出してしまうことがないことを保証するように、言語を作ることができます。 コンパイラおよびハードウェアの技術は、ループ中の位置を指し示すのに、配列のインデックスを用いる方が、 ポインタの算術演算を用いるより効率的になるように進歩しました。 さらに。ポインタの算術演算を持たないことで、ガベージコレクタの実装を単純にできます。

Why are ++ and -- statements and not expressions? And why postfix, not prefix?

どうして、++-- 文は式ではないの?そして、どうして、後置になったの、前置じゃないはなぜ?

Without pointer arithmetic, the convenience value of pre- and postfix increment operators drops. By removing them from the expression hierarchy altogether, expression syntax is simplified and the messy issues around order of evaluation of ++ and -- (consider f(i++) and p[i] = q[++i]) are eliminated as well. The simplification is significant. As for postfix vs. prefix, either would work fine but the postfix version is more traditional; insistence on prefix arose with the STL, a library for a language whose name contains, ironically, a postfix increment.

ポインタの算術演算がなければ、前置・後置双方のインクリメント演算子の利便性は無くなります。 それらを式階層からまるっきり取っ払うことで、式構文は単純になり、 評価順序にまつわるやっかいな問題は、すっかりと取り除かれます (f(i++)p[i] = q[++i] について考えてみて下さい)。

Why do garbage collection? Won't it be too expensive?

なぜガベージコレクションするの?コストが大きすぎるのでは?

One of the biggest sources of bookkeeping in systems programs is memory management. We feel it's critical to eliminate that programmer overhead, and advances in garbage collection technology in the last few years give us confidence that we can implement it with low enough overhead and no significant latency. (The current implementation is a plain mark-and-sweep collector but a replacement is in the works.)

システムプログラムにおける、もっとも巨大な bookkeeping 源の一つはメモリ管理である。 私たちはそれを、プログラマにとって、取り除くべき深刻なオーバヘッドだと感じている。 そして、ここ数年の実装を通じて、十分に小さなオーバヘッドで、深刻なレイテンシは起きないと確信している。 (現在の実装はプレーンなマーク・アンド・スイープを用いているが、置き換え作業中である)

Another point is that a large part of the difficulty of concurrent and multi-threaded programming is memory management; as objects get passed among threads it becomes cumbersome to guarantee they become freed safely. Automatic garbage collection makes concurrent code far easier to write. Of course, implementing garbage collection in a concurrent environment is itself a challenge, but meeting it once rather than in every program helps everyone.

別な観点として、並行処理やマルチスレッドプログラミングにおける、 難しさの大部分はメモリ管理である。 例えば、スレッドをまたいで受け渡されたオブジェクトを 安全に解放することはやっかいな問題である。 自動ガベージコレクションは並行処理のコード作成を劇的に書きやすくする。 もちろん、並行処理環境における、ガベージコレクタの実装はそれ自身がチャレンジである。 (意訳できず自信無し)しかし、一度上手く適合させてしまえば、プログラム毎にやるよりは、皆を助けるだろう。

Finally, concurrency aside, garbage collection makes interfaces simpler because they don't need to specify how memory is managed across them.

閑話休題。結局、ガベージコレクションはインタフェースをシンプルにします。 というのも、インタフェースは、メモリをどのように管理するかについて明記する必要がないからです。 (訳注:interfaces が何を指すのかが分かりませんでした)

Absent features - 欠けている機能について

Why does Go not have generic types?

どうして、Go には generic types がないの?

Generics may well be added at some point. We don't feel an urgency for them, although we understand some programmers do.

ジェネリックスはいくらかの観点で良いでしょう。 私たちはジェネリックスについて緊急性を感じていません。 もちろん、一部のプログラマがほしがることは承知しています。

Generics are convenient but they come at a cost in complexity in the type system and run-time. We haven't yet found a design that gives value proportionate to the complexity, although we continue to think about it. Meanwhile, Go's built-in maps and slices, plus the ability to use the empty interface to construct containers (with explicit unboxing) mean in many cases it is possible to write code that does what generics would enable, if less smoothly.

ジェネリックスは便利ですが、型システムとランタイムに複雑さを持ち込みます。 私たちはまだ、複雑さのバランスのとれた設計を見いだすことができていませんが、 そのことについて考え続けています。 (訳注:以下、訳者の能力が不足しており理解できない。 しかし、コンテナについては、なにかしら代替案が用意されているっぽい。 言語仕様を読んでからなら意味を汲めるのかもしれないが・・・) それまでのあいだ、Go の 組み込み maps および slices は、 (明示的な unboxing とともに)コンテナを生成するための空のインタフェースを用いる能力を加えます。 これにより、ほとんどのケースではジェネリックスが有るかのように、コードを記述できます。 スムーズさは欠くかもしれませんが。

This remains an open issue.

このことは、今現在ある問題の一つです。

Why does Go not have exceptions?

どうして、Go には例外がないの?

Exceptions are a similar story. A number of designs for exceptions have been proposed but each adds significant complexity to the language and run-time. By their very nature, exceptions span functions and perhaps even goroutines; they have wide-ranging implications. There is also concern about the effect they would have on the libraries. They are, by definition, exceptional yet experience with other languages that support them show they have profound effect on library and interface specification. It would be nice to find a design that allows them to be truly exceptional without encouraging common errors to turn into special control flow that requires every programmer to compensate.

例外についても似たようなストーリがあります。 例外に関する多数の提案がなされましたが、そのいずれも言語やランタイムに深刻な複雑性をもたらします。 自然な形で、例外は関数間や恐らくgoroutines間をまたがります。 すなわち、例外は幅広い範囲への影響があるわけです。 ライブラリへの影響についても懸念事項があります。 例外というのは、定義においてすら例外的です。 例外をサポートする他の言語での経験によると、 例外はライブラリやインタフェースの仕様に影響を与えます。 (訳注:訳が分かりません) 標準的なエラーを、プログラマによる補償が必要な特別な制御フローへと、 置き換えるよう促すこと無しに、 真の例外的なものとなる設計を見いだせれば良いのですが。

Like generics, exceptions remain an open issue.

ジェネリックスのように、例外も今現在ある問題として残っています。

Why does Go not have assertions?

なぜ Go にはアサーションがないの?

This is answered in the general FAQ.

FAQにおいて回答しています。

Types

Why is there no type inheritance?

なぜ型の継承がないの?

Object-oriented programming, at least in the best-known languages, involves too much discussion of the relationships between types, relationships that often could be derived automatically. Go takes a different approach.

少なくとも最もよく知られた言語では、 オブジェクト指向プログラミングは型同士の関係に対するあまりにも多くの議論を引き起こしました。 関係はしばしば自動的に派生します。 Go は異なるアプローチをとりました。

Rather than requiring the programmer to declare ahead of time that two types are related, in Go a type automatically satisfies any interface that specifies a subset of its methods. Besides reducing the bookkeeping, this approach has real advantages. Types can satisfy many interfaces at once, without the complexities of traditional multiple inheritance. Interfaces can be very lightweight—having one or even zero methods in an interface can express useful concepts. Interfaces can be added after the fact if a new idea comes along or for testing—without annotating the original types. Because there are no explicit relationships between types and interfaces, there is no type hierarchy to manage or discuss.

プログラマに前もって2つの型の関係を宣言してもらうよりも、 Go においては、ある型はインタフェースのメソッドのサブセットを満たすことで、自動的にそのインタフェースを満たします。 bookkeeping の削減の傍らに、このアプローチの本当のアドバンテージがあります。 型は一度に多数のインタフェースを満たすことができるのです。 それも、古典的な多数の継承の複雑さとは無縁にです。 インタフェースは、元の型への注釈は不要であり、非常に軽量なものになるでしょう (ひとつや、ゼロ個のメソッドを持つインタフェースでさえ、役に立つコンセプトを表現できます。 インタフェースは、もし新しいアイデアを思いついたり、テストのために後からでも追加できるのです)。

It's possible to use these ideas to construct something analogous to type-safe Unix pipes. For instance, see how fmt.Fprintf enables formatted printing to any output, not just a file, or how the bufio package can be completely separate from file I/O, or how the crypto packages stitch together block and stream ciphers. All these ideas stem from a single interface (io.Writer) representing a single method (Write). And that's only scratching the surface.

このアイデアは、型安全な Unix パイプに類似したものを作ることに使用できます。 例えば、fmt.Fprintf が、どのようにフォーマットされたプリントを、 ファイルに限らない、任意の出力へと実現しているかを見て下さい。 あるいは、bufio パッケージが完全にファイルI/Oから分離されているでしょう。 またあるいは、cryptoパッケージがどのようにブロック暗号とストリーム暗号を綴じ込んでいるかを見て下さい。 これら全てのアイデアは、一つのメソッド(Write)を表現する、一つのインタフェース(io.Writer)に起因します。 さらに、これは表層をなぞっているにすぎないのです。

It takes some getting used to but this implicit style of type dependency is one of the most exciting things about Go.

なじむまでには少々時間が必要かもしれませんが、 この暗黙的な型依存のスタイルは、Go に関する最もエキサイティングな事柄の一つです。

Why is len a function and not a method?

なぜ len は関数であってメソッドじゃないの?

We debated this issue but decided implementing len and friends as functions was fine in practice and didn't complicate questions about the interface (in the Go type sense) of basic types.

私たちはこのことについて議論を行いましたが、 lenとその仲間は、実践的には関数が適しており、 基本型の(Go の型の意味における)インタフェースについて、論点を複雑にしません。

Why does Go not support overloading of methods and operators?

なぜ Go はメソッドや演算子のオーバロードをサポートしないの?

Method dispatch is simplified if it doesn't need to do type matching as well. Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.

型マッチが不要であれば、メソッドディスパッチが単純になります。 他の言語における経験で、私たちは同じ名前を持つがシグネチャの異なるメソッドのバリエーションは、 時折便利だということを知っています。 (訳注:シグネチャについて訳語が分かりませんが、ぴんと来ない人は Method signature - Wikipedia を参照して下さい)。 しかし、それは実践的には、混乱の元であったり、危ういものであったりします。 名前でのみ一致し、型において無矛盾であることは、Go の型システムにおける、単純化のための重要な決断です。

Regarding operator overloading, it seems more a convenience than an absolute requirement. Again, things are simpler without it.

(訳注:訳の自信なし) 演算子オーバロードについては、絶対的な必要要件というよりは、ただ便利だというものであるように思える。 重ねて言うが、それ抜きに、物事をよりシンプルにしよう。

Values - 値

Why does Go not provide implicit numeric conversions?

なぜ Go には暗黙的な数値変換がないの?

The convenience of automatic conversion between numeric types in C is outweighed by the confusion it causes. When is an expression unsigned? How big is the value? Does it overflow? Is the result portable, independent of the machine on which it executes? It also complicates the compiler; “the usual arithmetic conversions” are not easy to implement and inconsistent across architectures. For reasons of portability, we decided to make things clear and straightforward at the cost of some explicit conversions in the code. The definition of constants in Go—arbitrary precision values free of signedness and size annotations—ameliorates matters considerably, though.

Cの数値型における自動型変換の利便性は度が過ぎていて、混乱元となっています。 いつその式が符号無しなのでしょうか? いったい値はどれぐらい大きいのでしょうか? オーバーフローするのでしょうか? 演算結果は、移植可能で、マシン非依存なのでしょうか? このことは、コンパイラをも複雑にします。 というのも、「よくある算術変換」は実装が容易ではなく、 アーキテクチャをまたいで整合性をとることができません。 移植性のために、私たちは、明示的な型変換によるコストについて、明確でわかりやすくすることを決めました。 (訳注:訳ミス?最後のthough がよく分かりません) Goにおける定数の定義(自由精度の値は符号やサイズの注釈から解放されています)は問題を大幅に改善していますけれども。

A related detail is that, unlike in C, int and int64 are distinct types even if int is a 64-bit type. The int type is generic; if you care about how many bits an integer holds, Go encourages you to be explicit.

これに関連して、C とは異なり、 intint64 は int が仮に64bitだったとしても、明確に区別されます。 int型はジェネリックであるため、 整数で保持するビット数をケアしたいのならば、 Go ではそれを明示するようにして下さい。

Why are maps built in?

なぜ maps は組み込みなの?

The same reason strings are: they are such a powerful and important data structure that providing one excellent implementation with syntactic support makes programming more pleasant. We believe that Go's implementation of maps is strong enough that it will serve for the vast majority of uses. If a specific application can benefit from a custom implementation, it's possible to write one but it will not be as convenient syntactically; this seems a reasonable tradeoff.

これにはいくつかの理由があります。 まず、それらはとても強力で重要なデータ構造です。 構文によるサポートをともなった、非常に優れた実装は、よりプログラミングを快適にします。 私たちはGoのmapsの実装は膨大な重要な用途において十分に強力だと確信しています。 特定用途に適した独自実装は可能ですが、それは恐らく構文的な便利さは持たないでしょう。 どうも、妥当なトレードオフであるようです。

Why don't maps allow structs and arrays as keys?

なぜ maps は構造体や配列をキーにできないの?

Map lookup requires an equality operator, which structs and arrays do not implement. They don't implement equality because equality is not well defined on such types; there are multiple considerations involving shallow vs. deep comparison, pointer vs. value comparison, how to deal with recursive structures, and so on. We may revisit this issue—and implementing equality for structs and arrays will not invalidate any existing programs—but without a clear idea of what equality of structs and arrays should mean, it was simpler to leave it out for now.

Map の辞書引きは、構造体や配列には実装されていない、等価演算子を必要とします。 それらが実装されていない理由は、それらの型において、良い定義というものが無いからです。 例えば、「shallowかdeepか」、「ポインタか値か」、「再帰している構造体の扱い」などといった複数の比較を考えることができます。 「構造体や配列に対する等価性の実装は、既存のプログラムの全てに妥当であることはできない」という問題を再考すべきでしょう。 しかし、構造体や配列の等価性が何を意味すべきかについて、明確なアイデアがでてくるまでは、 いまのところ、それを忘れておく方が単純です。

Why are maps, slices, and channels references while arrays are values?

なぜ配列は値なのに、maps や slices や channels は参照なの?

There's a lot of history on that topic. Early on, maps and channels were syntactically pointers and it was impossible to declare or use a non-pointer instance. Also, we struggled with how arrays should work. Eventually we decided that the strict separation of pointers and values made the language harder to use. Introducing reference types, including slices to handle the reference form of arrays, resolved these issues. Reference types add some regrettable complexity to the language but they have a large effect on usability: Go became a more productive, comfortable language when they were introduced.

このことについては、多数の議論がなされました。 初期には、maps や channels は構文的にはポインタであり、 非ポインタとして宣言したり使用することはできませんでした。 そして、配列がどう振る舞うべきかについて葛藤していました。 最終的に、私たちは、ポインタと値を厳密に分離すると、言語を使うことが難しくなると判断しました。 配列を参照の形で取り扱う slice を含む、参照型を導入することで、これらの問題を解決しました。 参照型によって、痛ましい複雑さを追加することとなりましたが、 使いやすさは大きく改善しました。 Goは参照型の導入によって、より生産的で快適な言語となったのです。

Concurrency - 平行処理

Why build concurrency on the ideas of CSP?

なぜ並行処理は CPS のアイデアを元にしたの?

Concurrency and multi-threaded programming have a reputation for difficulty. We believe the problem is due partly to complex designs such as pthreads and partly to overemphasis on low-level details such as mutexes, condition variables, and even memory barriers. Higher-level interfaces enable much simpler code, even if there are still mutexes and such under the covers.

並列処理やマルチスレッドのプログラミングは難しいと言われています。 私たちはその問題は pthread などの複雑な設計や、mutex、condition variable、 メモリバリアといった低レベルの詳細が過度に強調されていることに依ると考えています。 高レベルのインタフェースはコードをとても単純にします。 もちろん、その下には mutex などが横たわっているのですけれども。

One of the most successful models for providing high-level linguistic support for concurrency comes from Hoare's Communicating Sequential Processes, or CSP. Occam and Erlang are two well known languages that stem from CSP. Go's concurrency primitives derive from a different part of the family tree whose main contribution is the powerful notion of channels as first class objects.

高レベルで言語として並行処理をサポートした、もっとも成功したモデルの1つが、 Hoare の Communicating Sequential Processes (CSP) です。 Occam や Erlang は CSP に基づいているよく知られた言語です。 Go の並行処理プリミティブはその系譜とは異なる部分から導かれています。 主要な提案は、チャネルをファーストクラスオブジェクトだとする強力な発想です。 (訳注:ラスト2文自信なし)

Why goroutines instead of threads?

なぜスレッドの代わりに gotoutines なの?

Goroutines are part of making concurrency easy to use. The idea, which has been around for a while, is to multiplex independently executing functions—coroutines, really—onto a set of threads. When a coroutine blocks, such as by calling a blocking system call, the run-time automatically moves other coroutines on the same operating system thread to a different, runnable thread so they won't be blocked. The programmer sees none of this, which is the point. The result, which we call goroutines, can be very cheap: unless they spend a lot of time in long-running system calls, they cost little more than the memory for the stack.

(訳注:koba さんより訳をご提供いただきました) Goroutines は並行処理をより作りやすくするためのものです。 アイデア自体はしばらく前からありましたが、それは、 独立した複数の実行関数(coroutines)をスレッドの集合に多重化するというものです。 coroutineがブロックされるとき、例えばブロッキングするシステムコールを呼んだときなどですが、 ランタイムは自動的にそのcoroutineと同じスレッドの上に乗っている他のcoroutineを別の実行可能なスレッドに移動させ、 まきぞえになってブロックされてしまうことを防ぎます。 このことはとても重要なのですが、プログラマはこれを全く意識することはありません。 その結果、goroutineと呼ばれるものは、とてもコストの安いものになっています。 (それらが大部分を長時間かかるシステムコールばかりに費やすものではない限りにおいてですが)。 goroutineのコストはスタックに必要なメモリにほんの少しを加えたくらいのものです。

To make the stacks small, Go's run-time uses segmented stacks. A newly minted goroutine is given a few kilobytes, which is almost always enough. When it isn't, the run-time allocates (and frees) extension segments automatically. The overhead averages about three cheap instructions per function call. It is practical to create hundreds of thousands of goroutines in the same address space. If goroutines were just threads, system resources would run out at a much smaller number.

スタックを小さくするために、Go のランタイムは segmented stack を用います。 より新しい minted goroutine は数キロバイトで与えられ、それは大方において十分なものです。 もし、不足すると、ランタイムは自動的にセグメントを割り当て・解放します。 その平均オーバヘッドは関数呼び出しごとに軽量の3命令となっています。 このことは、数十万の goroutine を同一アドレス空間に作成した経験に基づいています。 もし goroutine がスレッドにすぎないなら、システムリソースをより小さな数で使い果たしてしまったでしょう。

Why are map operations not defined to be atomic?

なぜ map 命令はアトミックとして宣言されていないの?

After long discussion it was decided that the typical use of maps did not require safe access from multiple threads, and in those cases where it did, the map was probably part of some larger data structure or computation that was already synchronized. Therefore requiring that all map operations grab a mutex would slow down most programs and add safety to few. This was not an easy decision, however, since it means uncontrolled map access can crash the program.

長い議論の後に、典型的な map の使用においては、スレッドセーフである不要だという結論になりました。 そのような場合、map はより大きなデータ構造や計算の一部であり、すでに同期されていることが多かったのです。 したがって、ほとんどのプログラマにとって map が mutex をとらえることは、 ほとんどのプログラムで速度の低下を招きますが、あまり安全性が増えることはありません。 簡単に結論のでることではありませんでした。 それゆえに、きちんと制御されていない map アクセスはプログラムをクラッシュさせます。

The language does not preclude atomic map updates. When required, such as when hosting an untrusted program, the implementation could interlock map access.

言語的には、アトミックな map のアップデートを除外することはありません。 それが、信頼できないプログラムのホストなどで、必要なら、実装で map アクセスをインタロックします。

備考

Language Design FAQ を元に作成しました。

Except as noted, this content is licensed under Creative Commons Attribution 3.0.