Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 1480] ファイルの概要

このコミットは、Go言語の標準ライブラリの一部である tabwriter パッケージにおける命名規則の変更を扱っています。具体的には、tabwriter パッケージ内の型や関数の識別子を、外部に公開される(エクスポートされる)ものから、パッケージ内部でのみ使用される(アンエクスポートされる)ものへと変更しています。これは、Go言語における識別子の可視性(visibility)に関する重要な慣習に則った変更です。

コミット

commit e28692f07d6b476ff9c684577cf11877fdb8991d
Author: Robert Griesemer <gri@golang.org>
Date:   Thu Jan 15 15:10:46 2009 -0800

    - converted tabwriter to new naming scheme
    
    R=r
    OCL=22870
    CL=22870

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/e28692f07d6b476ff9c684577cf11877fdb8991d

元コミット内容

このコミットの目的は、tabwriter パッケージ内の識別子を新しい命名スキームに変換することです。具体的には、ByteArray 型が byteArray に、AddLine 関数が addLine に、Write0 関数が write0 に、Newline 変数が newline に、WritePadding 関数が writePadding に、WriteLines 関数が writeLines に、Format 関数が format に、UnicodeLen 関数が unicodeLen に、Append 関数が append に、Buffer 型が buffer に、Init 関数が init に、Clear 関数が clear に、Write 関数が write に、String 関数が string に、Verify 関数が verify に、Check 関数が check にそれぞれ変更されています。

変更の背景

Go言語では、識別子(変数、関数、型など)の最初の文字が大文字であるか小文字であるかによって、その可視性(スコープ)が決定されます。

  • 大文字で始まる識別子: パッケージ外からアクセス可能(エクスポートされる)。
  • 小文字で始まる識別子: パッケージ内でのみアクセス可能(アンエクスポートされる)。

このコミットが行われた2009年1月は、Go言語がまだ初期開発段階にあり、言語仕様や標準ライブラリの設計が固まりつつある時期でした。tabwriter パッケージは、テキストを整形してタブ区切りの列を揃えるためのユーティリティを提供します。このコミット以前は、パッケージ内部でしか使われないはずの多くの型や関数が、誤って大文字で始まり、外部にエクスポートされている状態でした。

この変更の背景には、Go言語の設計思想である「シンプルさ」と「明示性」があります。パッケージの内部実装の詳細を外部に公開しないことで、APIの安定性を保ち、利用者が混乱するのを防ぎます。また、不必要なエクスポートを避けることで、コンパイル時の依存関係を減らし、コードの保守性を向上させる狙いもあります。

前提知識の解説

Go言語の命名規則と可視性

Go言語の命名規則は非常にシンプルで、識別子の最初の文字がその可視性を決定します。

  • エクスポートされた識別子 (Exported Identifiers): 識別子の最初の文字が大文字の場合、その識別子はパッケージの外部からアクセス可能です。これは、他のパッケージからインポートして使用できることを意味します。例えば、fmt.PrintlnPrintln は大文字で始まるため、fmt パッケージの外部から呼び出すことができます。
  • アンエクスポートされた識別子 (Unexported Identifiers): 識別子の最初の文字が小文字の場合、その識別子は宣言されたパッケージ内でのみアクセス可能です。これは、パッケージの内部実装の詳細であり、外部からは直接利用できないことを意味します。例えば、sync パッケージ内の多くの内部ヘルパー関数は小文字で始まります。

この規則は、Go言語のAPI設計において非常に重要です。外部に公開すべきものだけをエクスポートし、内部実装は隠蔽することで、モジュール性とカプセル化を促進します。

tabwriter パッケージの役割

text/tabwriter (コミット当時は src/lib/tabwriter) パッケージは、Go言語の標準ライブラリの一部で、テキストデータを整形し、タブ区切りの列を自動的に揃える機能を提供します。これは、コマンドラインツールやログ出力などで、整形された表形式のデータを表示する際に非常に便利です。tabwriter.Writer 型は io.Writer インターフェースを実装しており、任意の io.Writer にデータを書き込むことができます。内部的には、タブ文字 (\t) や改行文字 (\n) を解析し、各列の幅を計算して適切なパディング(空白や指定された文字)を挿入することで、列を揃えます。

技術的詳細

このコミットの技術的な変更は、主にGo言語の識別子のリネームに集約されます。具体的には、tabwriter.gotabwriter_test.go の両ファイルにおいて、以下のパターンでリネームが行われています。

  1. 型名の変更:

    • ByteArray -> byteArray
    • Buffer -> buffer これらの型は、tabwriter パッケージの内部実装で使用される補助的なデータ構造であり、外部に公開する必要がないため、アンエクスポートされました。
  2. メソッド名の変更:

    • (*ByteArray).Init -> (*byteArray).Init (ただし、Initinit に変更されていない点に注意。これは InitWriter の初期化に使われるため、外部から呼び出される可能性があるためか、あるいは初期のGoの慣習がまだ固まっていなかったためかもしれない)
    • (*ByteArray).Len -> (*byteArray).Len (同上)
    • (*ByteArray).Clear -> (*byteArray).clear
    • (*ByteArray).Slice -> (*byteArray).slice
    • (*ByteArray).Append -> (*byteArray).append
    • (*Writer).AddLine -> (*Writer).addLine
    • (*Writer).Line -> (*Writer).line
    • (*Writer).Dump -> (*Writer).dump
    • (*Writer).Write0 -> (*Writer).write0
    • (*Writer).WritePadding -> (*Writer).writePadding
    • (*Writer).WriteLines -> (*Writer).writeLines
    • (*Writer).Format -> (*Writer).format
    • (*Writer).Append -> (*Writer).append これらのメソッドは、tabwriter.WriterbyteArray の内部的な処理を担うものであり、パッケージの外部から直接呼び出されることを意図していません。そのため、小文字で始まる名前に変更され、内部実装の詳細として隠蔽されました。
  3. グローバル変数/関数名の変更:

    • Newline -> newline
    • UnicodeLen -> unicodeLen
    • Write (テストヘルパー関数) -> write
    • Verify (テストヘルパー関数) -> verify
    • Check (テストヘルパー関数) -> check Newline は内部で使用されるバイトスライス定数であり、UnicodeLen は内部的な文字幅計算に使用されるヘルパー関数です。これらも外部に公開する必要がないため、アンエクスポートされました。テストファイル内のヘルパー関数も同様に、テストスイートの外部から呼び出されることを意図していないため、アンエクスポートされています。

この変更により、tabwriter パッケージの公開APIはより明確になり、パッケージの利用者は tabwriter.Writer 型とその Init および Flush メソッド、そして io.Writer インターフェースの実装にのみ焦点を当てればよくなりました。内部的な byteArrayaddLine といった詳細は隠蔽され、パッケージの内部構造が変更されても、外部のコードに影響を与えにくくなりました。

コアとなるコードの変更箇所

src/lib/tabwriter/tabwriter.go

  • ByteArray 型が byteArray に変更。
  • ByteArray 型のメソッド Init, Len, Clear, Slice, Append が、byteArray 型のメソッドとして、clear, slice, append に変更(InitLen は大文字のまま)。
  • Writer 型のフィールド buf の型が ByteArray から byteArray に変更。
  • Writer 型のメソッド AddLine, Line, Dump, Write0, WritePadding, WriteLines, Format, Append が、それぞれ addLine, line, dump, write0, writePadding, writeLines, format, append に変更。
  • グローバル変数 Newlinenewline に変更。
  • 関数 UnicodeLenunicodeLen に変更。
  • Flush メソッド内で呼び出される b.Formatb.format に、b.buf.Clearb.buf.clear に、b.AddLineb.addLine に変更。
  • Append メソッド内で呼び出される b.Appendb.append に、UnicodeLenunicodeLen に、b.buf.Sliceb.buf.slice に、b.Lineb.line に、b.AddLineb.addLine に変更。

src/lib/tabwriter/tabwriter_test.go

  • Buffer 型が buffer に変更。
  • Buffer 型のメソッド Init, Clear が、buffer 型のメソッドとして init, clear に変更。
  • Write 関数が write に変更。
  • Verify 関数が verify に変更。
  • Check 関数が check に変更。
  • テストケース内で呼び出される Checkcheck に変更。
  • テストヘルパー関数内で呼び出される b.Clearb.clear に、Writewrite に、Verifyverify に変更。

コアとなるコードの解説

このコミットの核心は、Go言語の識別子の可視性ルールを tabwriter パッケージに適用したことです。

例えば、src/lib/tabwriter/tabwriter.go の以下の変更を見てみましょう。

--- a/src/lib/tabwriter/tabwriter.go
+++ b/src/lib/tabwriter/tabwriter.go
@@ -13,34 +13,34 @@ import (


 // ----------------------------------------------------------------------------
-// Basic ByteArray support
+// Basic byteArray support

-type ByteArray struct {
+type byteArray struct {
 	a []byte;
 }


-func (b *ByteArray) Init(initial_size int) {
+func (b *byteArray) Init(initial_size int) {
 	b.a = make([]byte, initial_size)[0 : 0];
 }


-func (b *ByteArray) Len() int {
+func (b *byteArray) Len() int {
 	return len(b.a);
 }


-func (b *ByteArray) Clear() {
+func (b *byteArray) clear() {
 	b.a = b.a[0 : 0];
 }


-func (b *ByteArray) Slice(i, j int) []byte {
+func (b *byteArray) slice(i, j int) []byte {
 	return b.a[i : j];  // BUG should really be &b.a[i : j]
 }


-func (b *ByteArray) Append(s []byte) {
+func (b *byteArray) append(s []byte) {
 	a := b.a;
 	n := len(a);
 	m := n + len(s);

ここでは、ByteArray 型が byteArray にリネームされ、それに伴いそのメソッドの一部(Clear, Slice, Append)も小文字で始まる名前に変更されています。InitLen は大文字のままですが、これは tabwriter.Writer の内部でこれらのメソッドが呼び出されるため、Goの初期段階では内部的な型であっても一部のメソッドはエクスポートされたままにする慣習があったか、あるいは特定のインターフェースを満たすためにエクスポートが必要だった可能性が考えられます。しかし、Clear, Slice, Append は明らかに内部的なヘルパーメソッドであり、外部から直接アクセスされるべきではないため、アンエクスポートされています。

同様に、Writer 型の多くの内部ヘルパーメソッドもアンエクスポートされています。

--- a/src/lib/tabwriter/tabwriter.go
+++ b/src/lib/tabwriter/tabwriter.go
@@ -138,7 +138,7 @@ export type Writer struct {
 // buf                start of incomplete cell  pos


-func (b *Writer) AddLine() {
+func (b *Writer) addLine() {
 	b.lines_size.Push(array.NewIntArray(0));
 	b.lines_width.Push(array.NewIntArray(0));
 }

AddLineaddLine に変更されたことで、このメソッドは tabwriter パッケージの内部でのみ使用されるようになります。これにより、パッケージの外部から tabwriter.Writer オブジェクトの addLine メソッドを呼び出すことはできなくなり、APIの利用者は tabwriter の内部実装の詳細に触れることなく、より高レベルな WriteFlush メソッドを通じて機能を利用するようになります。

この変更は、Go言語の標準ライブラリ全体で一貫したAPI設計原則を確立する上で重要なステップでした。パッケージの内部構造と外部に公開されるAPIを明確に区別することで、ライブラリの安定性、保守性、そして使いやすさが向上します。

関連リンク

参考にした情報源リンク

  • Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
  • Go言語の初期のコミット履歴 (このコミットが含まれる): https://github.com/golang/go/commits/master?after=e28692f07d6b476ff9c684577cf11877fdb8991d+1
  • Go言語の設計に関する議論 (Go Mailing Listなど、当時の情報源)
    • Go言語の初期の設計に関する議論は、主にGoのメーリングリストや初期のGoブログで行われていました。具体的なリンクを特定するのは困難ですが、Goの設計原則に関する情報は、Effective GoやGoの公式ブログ記事に集約されています。