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

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

このコミットは、Go言語の初期開発段階におけるコードベースの変更であり、特にusr/gri/prettyディレクトリ内のファイル群に対して、Goの命名規則(特にエクスポートされる識別子とエクスポートされない識別子に関する規則)を適用したものです。

コミット

commit 2527bba993fcb324183b88aebafa2c2fe5c8b424
Author: Robert Griesemer <gri@golang.org>
Date:   Thu Jan 15 17:16:41 2009 -0800

    casify pretty
    
    R=r
    OCL=22899
    CL=22899

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

https://github.com/golang/go/commit/2527bba993fcb324183b88aebafa2c2fe5c8b424

元コミット内容

casify pretty

このコミットメッセージは簡潔ですが、Go言語の文脈においては非常に意味深いです。「casify」は「ケース(大文字・小文字)を調整する」という意味で、「pretty」は対象となるパッケージ名(usr/gri/pretty)を指しています。つまり、prettyパッケージ内のコードの識別子(変数名、関数名、構造体フィールド名など)の命名規則を、Goの標準的な慣習に合わせて変更したことを示唆しています。

変更の背景

Go言語は、識別子(変数、関数、型、メソッドなど)の可視性(エクスポートされるか否か)を、その識別子の最初の文字が大文字か小文字かによって決定するという独特のルールを持っています。

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

このコミットが行われた2009年1月は、Go言語がまだ一般に公開される前の初期開発段階でした。この時期には、言語仕様や慣習が固まりつつあり、コードベース全体で一貫したスタイルを適用する作業が頻繁に行われていました。この「casify pretty」コミットは、prettyパッケージがGoの命名規則に準拠するように修正されたことを示しています。これにより、コードの可読性と保守性が向上し、他のパッケージからの利用方法が明確になります。

前提知識の解説

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

Go言語の命名規則は、そのシンプルさと厳格さで知られています。特に重要なのが、識別子の最初の文字による可視性の制御です。

  1. エクスポートされる識別子 (Exported Identifiers):

    • 識別子の最初の文字が大文字である場合、その識別子はパッケージ外からアクセス可能です。これは、他のプログラミング言語におけるpublicexportに相当します。
    • 例: Name, CalculateSum, MyStruct
    • 構造体のフィールドやメソッドもこの規則に従います。フィールド名が大文字で始まると、そのフィールドは構造体の外部からアクセス可能になります。
  2. エクスポートされない識別子 (Unexported Identifiers):

    • 識別子の最初の文字が小文字である場合、その識別子は宣言されたパッケージ内でのみアクセス可能です。これは、他のプログラミング言語におけるprivateinternalに相当します。
    • 例: name, calculateSum, myStruct
    • パッケージ内部の実装詳細を隠蔽し、APIの安定性を保つために使用されます。

この規則は、Goの設計哲学である「明示的なものが良い (explicit is better than implicit)」を反映しており、コードを読むだけでその識別子が外部に公開されているかどうかが一目でわかるようになっています。

抽象構文木 (AST)

抽象構文木(Abstract Syntax Tree, AST)は、ソースコードの抽象的な構文構造を木構造で表現したものです。コンパイラやインタプリタがソースコードを解析する際に中間表現として生成します。ASTは、プログラムの構造を階層的に表現し、各ノードがソースコードの要素(式、文、宣言など)に対応します。

このコミットで変更されているファイルにはast.goが含まれており、これはGoプログラムのASTを定義する構造体や関数を含んでいると考えられます。例えば、ObjectNodeExprTypeStatDeclProgramといった構造体は、Goのコード要素を表現するためのASTノードである可能性が高いです。

字句解析器 (Scanner) と構文解析器 (Parser)

  • 字句解析器 (Scanner/Lexer): ソースコードを読み込み、意味のある最小単位(トークン)に分割する役割を担います。例えば、if, else, +, 変数名, 数値などがトークンです。
  • 構文解析器 (Parser): 字句解析器が生成したトークンのストリームを受け取り、それらが言語の文法規則に合致しているかを検証し、通常はASTを構築します。

このコミットで変更されているファイルにはscanner.goparser.goが含まれており、これらはGoのソースコードを解析するためのコンポーネントであると推測されます。

技術的詳細

このコミットの主要な変更は、usr/gri/prettyパッケージ内のGoコードにおける識別子の命名規則の統一です。具体的には、以下のパターンで変更が行われています。

  1. 構造体フィールド名の変更:

    • ast.goファイルにおいて、ObjectNodeExprTypeStatDeclCommentProgramなどの構造体のフィールド名が、小文字から大文字に変更されています(例: id -> Id, pos -> Pos, kind -> Kind, ident -> Ident)。
    • これは、これらのフィールドがパッケージ外からアクセスされることを意図しているため、Goのエクスポート規則に従って大文字で始まるように修正されたことを意味します。
  2. パッケージ内部関数の変更:

    • compilation.gopretty.goprinter.goplatform.goなどのファイルにおいて、パッケージ内部でのみ使用される関数名が、大文字から小文字に変更されています(例: ErrorHandler -> errorHandler, FileExists -> fileExists, AddDeps -> addDeps, Usage -> usage, HtmlEscape -> htmlEscape, Untabify -> untabify)。
    • これは、これらの関数がパッケージの外部に公開されるべきではないため、Goのエクスポートされない規則に従って小文字で始まるように修正されたことを意味します。
  3. 変数名の変更:

    • ast.goにおいて、ObjectIdobjectIdに、TypeIdtypeIdに変更されています。これらはパッケージ内部で管理されるIDカウンターであるため、エクスポートされない変数として小文字に修正されています。

これらの変更は、Go言語の可視性ルールを厳密に適用し、コードの意図を明確にするためのものです。これにより、どの要素がパッケージの公開APIの一部であり、どの要素が内部実装の詳細であるかが、命名規則によって明確に区別されるようになります。

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

このコミットは、複数のファイルにわたる広範な変更を含んでいますが、その性質は一貫しています。以下に、各ファイルにおける変更の代表的な例を挙げます。

usr/gri/pretty/ast.go

構造体フィールド名の変更が顕著です。

--- a/usr/gri/pretty/ast.go
+++ b/usr/gri/pretty/ast.go
@@ -54,23 +54,23 @@ export func KindStr(kind int) string {


 export type Object struct {
-	id int;  // unique id
-
-	pos int;  // source position (< 0 if unknown position)
-	kind int;  // object kind
-	ident string;
-	typ *Type;  // nil for packages
-	pnolev int;  // >= 0: package no., <= 0: function nesting level, 0: global level
+	Id int;  // unique id
+
+	Pos int;  // source position (< 0 if unknown position)
+	Kind int;  // object kind
+	Ident string;
+	Typ *Type;  // nil for packages
+	Pnolev int;  // >= 0: package no., <= 0: function nesting level, 0: global level
 	
 	// attached values
-	block *array.Array; end int;  // stats for function literals; end of block pos
+	Block *array.Array; End int;  // stats for function literals; end of block pos
 }


 func (obj *Object) IsExported() bool {
-	switch obj.kind {
+	switch obj.Kind {
 	case NONE /* FUNC for now */, CONST, TYPE, VAR, FUNC:
-		ch, size := utf8.DecodeRuneInString(obj.ident,  0);
+		ch, size := utf8.DecodeRuneInString(obj.Ident,  0);
 		return unicode.IsUpper(ch);
 	}
 	return false;
@@ -78,18 +78,18 @@ func (obj *Object) IsExported() bool {


 export var Universe_void_typ *Type  // initialized by Universe to Universe.void_typ
-var ObjectId int;
+var objectId int;

 export func NewObject(pos, kind int, ident string) *Object {
 	obj := new(Object);
-	obj.id = ObjectId;
-	ObjectId++;
+	obj.Id = objectId;
+	objectId++;
 	
-	obj.pos = pos;
-	obj.kind = kind;
-	obj.ident = ident;
-	obj.typ = Universe_void_typ;
-	obj.pnolev = 0;
+	obj.Pos = pos;
+	obj.Kind = kind;
+	obj.Ident = ident;
+	obj.Typ = Universe_void_typ;
+	obj.Pnolev = 0;

 	return obj;
 }

usr/gri/pretty/compilation.go

型名や関数名の変更が見られます。

--- a/usr/gri/pretty/compilation.go
+++ b/usr/gri/pretty/compilation.go
@@ -34,7 +34,7 @@ export type Flags struct {
 }
 
 
-type ErrorHandler struct {
+type errorHandler struct {
 	filename string;
 	src string;
 	nerrors int;
@@ -44,7 +44,7 @@ type ErrorHandler struct {
 }
 
 
-func (h *ErrorHandler) Init(filename, src string, columns bool) {
+func (h *errorHandler) Init(filename, src string, columns bool) {
 	h.filename = filename;
 	h.src = src;
 	h.nerrors = 0;
@@ -55,7 +55,7 @@ func (h *ErrorHandler) Init(filename, src string, columns bool) {
 
 
 // Compute (line, column) information for a given source position.
-func (h *ErrorHandler) LineCol(pos int) (line, col int) {
+func (h *errorHandler) LineCol(pos int) (line, col int) {
 	line = 1;
 	lpos := 0;
 
@@ -75,7 +75,7 @@ func (h *ErrorHandler) LineCol(pos int) (line, col int) {
 }
 
 
-func (h *ErrorHandler) ErrorMsg(pos int, msg string) {
+func (h *errorHandler) ErrorMsg(pos int, msg string) {
 	print(h.filename, ":");
 	if pos >= 0 {
 		// print position
@@ -97,7 +97,7 @@ func (h *ErrorHandler) ErrorMsg(pos int, msg string) {
 }
 
 
-func (h *ErrorHandler) Error(pos int, msg string) {
+func (h *errorHandler) Error(pos int, msg string) {
 	// only report errors that are sufficiently far away from the previous error
 	// in the hope to avoid most follow-up errors
 	const errdist = 20;
@@ -112,7 +112,7 @@ func (h *ErrorHandler) Error(pos int, msg string) {
 }
 
 
-func (h *ErrorHandler) Warning(pos int, msg string) {
+func (h *errorHandler) Warning(pos int, msg string) {
 	panic("UNIMPLEMENTED");
 }
 
@@ -124,7 +124,7 @@ export func Compile(src_file string, flags *Flags) (*AST.Program, int) {
 		return nil, 1;
 	}
 
-	var err ErrorHandler;
+	var err errorHandler;
 	err.Init(src_file, src, flags.columns);
 
 	var scanner Scanner.Scanner;
@@ -148,7 +148,7 @@ export func Compile(src_file string, flags *Flags) (*AST.Program, int) {
 }
 
 
-func FileExists(name string) bool {
+func fileExists(name string) bool {
 	fd, err := OS.Open(name, OS.O_RDONLY, 0);
 	if err == nil {
 		fd.Close();
@@ -158,7 +158,7 @@ func FileExists(name string) bool {
 }
 
 
-func AddDeps(globalset map [string] bool, wset *array.Array, src_file string, flags *Flags) {
+func addDeps(globalset map [string] bool, wset *array.Array, src_file string, flags *Flags) {
 	dummy, found := globalset[src_file];
 	if !found {
 		globalset[src_file] = true;

コアとなるコードの解説

上記の変更箇所は、Go言語の命名規則をコードベースに適用する典型的な例です。

  • 構造体フィールド: ast.goにおけるObjectNodeExprTypeなどの構造体は、GoのASTを表現するための基本的なデータ構造です。これらの構造体のフィールド(例: id, pos, kind, ident)は、ASTを操作する他のパッケージや関数からアクセスされることが想定されます。したがって、これらのフィールド名を大文字(Id, Pos, Kind, Ident)に変更することで、Goの可視性ルールに従い、外部からのアクセスを許可する「エクスポートされた」フィールドとして明示しています。

  • パッケージ内部関数: compilation.goprinter.goなどにおけるErrorHandler, FileExists, AddDeps, HtmlEscape, Untabifyといった関数は、そのパッケージの内部実装の詳細であり、外部に公開する必要がないと判断されたものです。これらの関数名を小文字(errorHandler, fileExists, addDeps, htmlEscape, untabify)に変更することで、Goの可視性ルールに従い、パッケージ内部でのみ利用可能な「エクスポートされない」関数として明示しています。これにより、パッケージのAPIがシンプルに保たれ、内部実装の変更が外部に影響を与えるリスクが低減されます。

  • パッケージ内部変数: ObjectIdTypeIdのような変数は、パッケージ内部で一意なIDを生成・管理するためのカウンターであり、外部から直接操作されるべきではありません。これらを小文字(objectId, typeId)に変更することで、パッケージ内部のプライベートな状態であることを明確にしています。

これらの変更は、単なるスタイルの変更ではなく、Go言語の設計思想に基づいたコードの構造化とAPI設計の改善を目的としています。これにより、コードの意図がより明確になり、将来的な保守性や拡張性が向上します。

関連リンク

参考にした情報源リンク