[インデックス 10187] ファイルの概要
このコミットは、Go言語の実験的なEBNFパーサー (exp/ebnf
) における手動での修正を記録しています。特に、エラー処理に関するAPIの変更に対応するためのものです。
コミット
- コミットハッシュ:
c93b6a1756be708ba2d6c8c91c4dabdbbd653cbe
- Author: Russ Cox rsc@golang.org
- Date: Tue Nov 1 21:49:33 2011 -0400
- 変更ファイル:
src/pkg/exp/ebnf/parser.go
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c93b6a1756be708ba2d6c8c91c4dabdbbd653cbe
元コミット内容
exp/ebnf: manual fixup for error
(The definition of ErrorList is in another file, so gofix
has no hope of getting this right.)
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/5330043
変更の背景
このコミットの背景には、Go言語の進化におけるエラーハンドリングAPIの変更と、gofix
ツールの限界があります。
Go言語の初期バージョンでは、エラーを表すためにos.Error
という型が使われていました。しかし、Go 1.0のリリースに向けて、より汎用的なerror
インターフェースが導入され、エラーハンドリングの仕組みが大きく変更されました。これに伴い、os.Error
を使用していた既存のコードはerror
インターフェースに準拠するように修正する必要がありました。
gofix
は、このようなGo言語のAPI変更や慣習の進化に合わせて、古いコードを新しい形式に自動的に変換するためのツールです。しかし、このコミットメッセージにあるように、ErrorList
の定義が別のファイルにある場合、gofix
は依存関係を完全に解決できず、自動的に正しい修正を適用することができませんでした。
したがって、このコミットは、gofix
が自動修正できなかった部分を、開発者であるRuss Cox氏が手動で修正したことを示しています。これは、Go言語の進化の過程で、自動化ツールだけでは対応しきれない複雑なケースが存在したことを物語っています。
前提知識の解説
EBNF (Extended Backus-Naur Form)
EBNF(拡張バッカス・ナウア記法)は、プログラミング言語やデータ形式の構文を記述するためのメタ言語です。BNF(バッカス・ナウア記法)を拡張したもので、より簡潔で読みやすい構文定義を可能にします。EBNFは、以下のような特徴を持ちます。
- 繰り返し:
*
(0回以上)、+
(1回以上) - 選択:
|
(いずれか) - オプション:
[]
(0回または1回) - グループ化:
()
- 終端記号と非終端記号: 終端記号はそれ以上分解できない要素(例: キーワード、識別子)、非終端記号は他の規則によって定義される要素(例: 式、文)
Go言語のexp/ebnf
パッケージは、このEBNF形式で記述された構文定義を解析するための実験的なパーサーを提供していたと考えられます。
Go言語のエラーハンドリング (os.Error
からerror
インターフェースへ)
Go言語のエラーハンドリングは、他の多くの言語に見られるような例外処理(try-catch)とは異なり、関数の戻り値としてエラーを返すという特徴的なアプローチを取ります。
-
os.Error
(Go言語初期): Go言語の非常に初期の段階では、エラーを表すためにos.Error
という具体的な型が使われていました。これは、エラーメッセージを保持するシンプルなインターフェースのようなものでした。 -
error
インターフェース (Go 1.0以降): Go 1.0のリリースに伴い、エラーハンドリングの標準的な方法としてerror
インターフェースが導入されました。このインターフェースは非常にシンプルで、Error() string
という単一のメソッドを定義しています。type error interface { Error() string }
これにより、任意の型が
Error()
メソッドを実装することでerror
インターフェースを満たすことができ、より柔軟なエラー表現が可能になりました。例えば、fmt.Errorf
関数は、このerror
インターフェースを返すことで、カスタムエラーメッセージを生成します。
このコミットが行われた2011年11月は、Go 1.0のリリース(2012年3月)に先立つ時期であり、Go言語のAPIが活発に開発・変更されていた過渡期にあたります。os.Error
からerror
インターフェースへの移行は、Go言語の安定化と標準化に向けた重要な変更の一つでした。
gofix
ツール
gofix
は、Go言語のソースコードを自動的に修正し、新しいAPIや慣習に適合させるためのコマンドラインツールです。Go言語の進化の過程で、APIの変更や言語仕様の微調整が行われることがありましたが、gofix
は開発者が手動で大量のコードを修正する手間を省くために開発されました。
例えば、Go言語の初期にはmake
関数がスライス、マップ、チャネルの作成に使われていましたが、後にスライスにはnew
関数が推奨されるようになりました。gofix
はこのような変更を検出し、自動的にコードを修正することができます。
しかし、このコミットのケースのように、型定義が別のファイルにあり、gofix
がその依存関係を完全に追跡できない場合など、一部の複雑なシナリオでは手動での修正が必要となることがありました。
技術的詳細
変更の核心は、p.errors.Error()
からp.errors.Err()
への呼び出しの変更です。
Go言語のerror
インターフェースにはError()
というメソッドが定義されていますが、これは通常、エラーオブジェクト自体がエラーメッセージを文字列として返すために使用されます。
一方、Err()
というメソッドは、Go言語の標準ライブラリや特定のパッケージで、エラーのリストや複数のエラーを管理する構造体(この場合はErrorList
と推測される)が、それらのエラーをまとめて単一のerror
インターフェースとして返すために使用されることがあります。
この変更は、p.errors
がErrorList
のような型であり、その型がError()
メソッドではなくErr()
メソッドを通じて、集約されたエラー情報をerror
インターフェースとして提供するようにAPIが変更されたことを示唆しています。
具体的には、ErrorList
のようなエラーの集合を扱う型が、Go 1.0のエラーハンドリングの慣習に合わせて、以下のような変更を受けた可能性があります。
- 旧API:
ErrorList
型が直接Error() string
メソッドを実装しており、エラーメッセージの文字列を返していた。 - 新API:
ErrorList
型がErr() error
メソッドを実装し、内部のエラーリストから単一のerror
インターフェース(例えば、最初のエラーや、複数のエラーを結合したカスタムエラー型)を返すようになった。これにより、ErrorList
自体がerror
インターフェースを直接実装するのではなく、Err()
を通じてerror
インターフェースを「提供」する形になったと考えられます。
この変更は、Go言語のエラーハンドリングがより洗練され、エラーの集約や伝播のパターンが標準化されていく過程の一部と見ることができます。
コアとなるコードの変更箇所
--- a/src/pkg/exp/ebnf/parser.go
+++ b/src/pkg/exp/ebnf/parser.go
@@ -187,5 +187,5 @@ func (p *parser) parse(filename string, src io.Reader) Grammar {
func Parse(filename string, src io.Reader) (Grammar, os.Error) {
var p parser
grammar := p.parse(filename, src)
- return grammar, p.errors.Error()
+ return grammar, p.errors.Err()
}
コアとなるコードの解説
変更が行われたのは、src/pkg/exp/ebnf/parser.go
ファイル内のParse
関数です。
func Parse(filename string, src io.Reader) (Grammar, os.Error) {
var p parser
grammar := p.parse(filename, src)
return grammar, p.errors.Err() // 変更箇所
}
func Parse(filename string, src io.Reader) (Grammar, os.Error)
: この関数は、指定されたファイル名とio.Reader
からEBNF構文を解析し、Grammar
(解析された構文ツリーまたは表現)とos.Error
(エラー情報)を返します。Go 1.0以前のos.Error
が戻り値の型として使われている点に注目してください。var p parser
:parser
型の変数を宣言しています。これはEBNF解析のロジックをカプセル化する構造体であると推測されます。grammar := p.parse(filename, src)
:parser
のparse
メソッドを呼び出して、実際の解析処理を実行し、結果としてGrammar
オブジェクトを取得しています。return grammar, p.errors.Err()
: ここが変更点です。- 変更前:
p.errors.Error()
- 変更後:
p.errors.Err()
- 変更前:
p.errors
は、解析中に発生したエラーを収集するErrorList
のような型であると推測されます。このErrorList
が、Go言語のエラーハンドリングAPIの変更に伴い、エラー情報を取得するためのメソッドがError()
からErr()
に変わったため、それに合わせて呼び出し側も修正されたということです。
この修正により、Parse
関数は、ErrorList
が提供する新しいAPIを通じて、適切にエラー情報をos.Error
(最終的にはerror
インターフェース)として返すことができるようになりました。
関連リンク
- Go CL 5330043: https://golang.org/cl/5330043
参考にした情報源リンク
- Go言語のエラーハンドリングに関する一般的な情報:
gofix
ツールに関する情報:- EBNFに関する一般的な情報:
- Go言語の歴史的な変更に関する情報(
os.Error
からerror
への移行など)は、Goの公式ブログやメーリングリストのアーカイブに散見されますが、特定の記事を直接参照したわけではありません。一般的なGo言語の知識として記述しました。