From: ichimal@... Date: 2003-02-17T01:29:58+09:00 Subject: [ruby-list:37110] Re: Local variables & blocks 鈴木です。 一週間以上間を開けてしまい、すみません。 In message "[ruby-list:37063] Re: Local variables & blocks" on 03/02/06, matz writes: > 「未定義」 > > そのスコープ中で一度も代入されていないこと。つまり、その識 > 別子はそもそもローカル変数を指していないこと。その識別子に > 対する通常のアクセスはエラーになる。defined? <識別子>が偽 > になる。 > > 「未初期化」 > > ローカル変数が初期化されていないこと。つまりどこかに代入 > があるが、その代入は実行されていないこと。その識別子に対 > するアクセスはエラーにならず、値はnil。 > > 鈴木さんの「未初期化」はどちらかというと前者の意味が強いと思 > います。 いえ、私は純粋に後者を指して未初期化と呼んでいます。新スコープルール 下でブロック内に新変数への代入式があれば、静的に (メソッドに局所的な) 変数が定義されるわけです。現状ではその変数の初期値として nil を使う方 針で言語設計がなされていますが、そこに異を唱えたのがそもそもの話です。 つまり、未初期化の定義自体への異義です。 > nilを変数に代入するとい > うことは、未初期化と同じ無効な値を代入するというだけのことで > す。この意味で > > | nil を変数に代入することは、その変数が「(ある文脈において) 無効とみ > |なされるべきオブジェクトを指している」という状態にすることです。しかし、 > |変数を未初期化状態に戻すことではありません。なぜなら、「無効である」と > |いう概念と「初期化されていない」という概念は全く異なる次元のものだから > |です。 > > というのは成立していないと思います。 「未初期化と同じ無効な値を代入する」という概念は、未初期化値を (トリッ キーな手法に頼ることなく) 明に代入できるという前提を必要とします。私は そのような前提は、妥協案としては可能であるにせよ、間違っていると考えま す。 ですから、上記引用部分の私の意見は、件の前提下では成立しないと考える ことが可能であることには同意しますが、そもそもの前提が間違っているとい う立場の下、同意できません。 # ああ、ややこしい。 私は、件の前提が (有用かどうかではなく) 妥当であるためには x = x # 変数 x はここで初出 の結果が nil になるように定義されている理由に、便利さ以上の論理的妥当 性が必要だと考えます。この点についてはどうお考えでしょうか。 > 「未初期化」と「無効である」はほぼ同じです。 ほぼ同じだ、と妥協することが可能であることは認めます。が、それらはや はり概念的に異なるものです。 > | しかし、新提案のスコープルールは、「定義されているが未初期化」という > |状態を容認する意味論に即したものです。そこに nil を旧来の定義に即した > |未初期化値として持ち込むのは、double meaning です。 > > すでに述べましたが、「定義されているが未初期化」という状態は > 現在も存在しています。 現在も存在しますねぇ。新スコープルールに移行すると double meaning に なってしまうというのは撤回します。しかし、現状の nil が明に代入可能な 無効値の代表値である以上、現状で既に double (triple?) meaning だと考え ます。 そして、この double meaning は互換性の問題を考えても解消可能な範疇に あると考えます。というのは (1) 田中さんが示したような現状でも存在する 「定義されているが未初期化」状態を生成するようなコードが、つまるところ 「そのようにも書ける」というだけのものに過ぎず、また (2) 新スコープルー ルへの移行自体に非互換性が存在するからです。 # talk を読んでいない方のために捕捉しますが、その非互換性については、 # talk [63262] でまつもとさん自身が # # > | * Threads # > # > Incompatibility can be a problem here. But language designers also # > need a chance to fix bad design. We are not perfect. # # とおっしゃっています。 > 「nil で明示的に初期化したのか本当に未初期化なのかの区別をし > なければならないとき」ってのが存在するとは思えないのですが。 しなければならない状況ですか。そんなものはコーディング方針を (ちょっ と) 変更することで全て回避できるでしょうね。しかし区別するように書いた 方がすっきり書けるような状況というものは存在するはずです。 ただし、talk で polcy matter だと聞いて早々に自案を引っ込めた理由は ここにあります。というのは、そのような区別を許すかどうかは言語設計上の 問題ですが、実際にそれを区別させたいようなプログラムを書くかどうかはプ ログラミングスタイルの問題に過ぎないからです。 仮に私の提案したような未初期化状態を言語に取り込めば、それを積極的に 利用したプログラムを書く人は現れるでしょう。しかし、プログラマ全員が積 極的に利用するようになるかどうかは別問題です。そして、未初期化状態の存 在意義に異を唱え、不便さを口にする人も出てきてしまうでしょう。 # 当然、そんなの条件判断で区別するくらいなら例外使えという意見も出るで # しょう。 というわけで、無効値と未初期化値に違いがあるかどうかを、純粋に概念的 な観点と「Rubyかくあるべし論 (現行版)」と「Rubyかくあるべし論 (将来版)」 で切り分けた上での御意見を伺いたいです。 > 「有効なnil」というのも「有効な無効値」という自己矛盾を起こ > してますし。 どちらかと言えば「有用なnil」==「有用な無効値」ですかね。厳密に言え ば nil は「『ある文脈において無効とみなされる値』という有効な値」だと 思いますが、ここで言う「有効」という語は「有用」と読み替えても問題無い わけでして。 > それにNilClassから、その値が未初期化か無効化を判断する方法は > ないと思います。未定義かどうかならdefined?を使うことができま > すが、未定義かどうかの判定って(コンパイル時に決まるので)たぶ > ん意味がないですよね。 たとえばポインタに未初期化ビットを立てるなどの手法を用いれば NilClass の唯一のインスタンスという形式を維持したままでも実装可能だと 思います。他にも実装方法はいくらでもあるでしょう。もっとも、そんなもの は不可能じゃないという程度にしか意味は無いんですが。 > | 本題 (1) をまとめます。 > | (*) 「無効」と「未初期化」は別概念 > > 私はここに異議を唱えます。未初期化つまり、実行時に代入されて > ないってことはその変数は有効な値を持たないということで、それ > は無効値を持つと同義ではないかと考えます。 これらを同義とするように定義することも可能だ、ということは認めます。 しかし、それはプログラミング言語設計における policy matter であって、 根本的には別概念だと主張します。 > 未定義、つまりその変数が定義されていない場合にはアクセスその > ものがエラーになりますから、値はありません。ですから、未定義 > の変数の値は存在しないので定義する必要はありません。 これは全面的に同意します。未初期化かどうかが問題になるのはあくまで定 義された変数についてです。 > 仮に上で述べた「未定義値」が存在する(必要がある)のであれば、 > その値は本題(1)で示されたような性質 snip > に加えて真偽値としての性質も持たない方が良いという主張は理解 > できます。 :-) > しかし、そもそも未定義値は存在しない(する必要がない)と考えます。 「する必要がない」という表現に、強い policy を感じますね。 > falseとnilの両方が偽であることによって発生しうる問題のひとつ > ですね かつて "nil" が Lisp における唯一の偽だったことには納得できます。nil が何重に意味を持っていようとも、それが唯一絶対の存在だったからです。 Lisp の問題は、"false" を導入してしまったことなのかもしれません。 > (もうひとつは英語での説明がややこしいこと - false and > nil are false values...)。 これがややこしいのは nil のせいではなく、false というシンボル名のせ いだと思います。 > ただ、これはトレードオフで妥協できるのではないかと考えています。 同意します。くどいようですが、この問題は半ば policy matter に属しま す。 > また、無効であることを示す方法にはもうひとつ例外があります。無自覚に > nilを返すよりは例外をあげた方がスタイルとしては良いのではないかと思 > います。 無効値の代表値を返すくらいなら例外の方がましだと考えます。そもそも無 効値の代表値を返して何が嬉しいんだかさっぱりわかりません。 思うに、 foo = nil while cond do { foo = ... } p foo のようなコードは、意図が明確であるという点に於て while cond do { foo = ... } p foo のようなコードよりも優れているんですよ。初期状態の存在しないオートマト ンの各状態は全て到達不能なんですよ、エエ。 # ただし、変数をうっかり使い回してしまったときの被害を軽減できる、とい # う観点から前者の優位性を主張するつもりはありません。 nil を未初期化値と読み替えた場合は…これも policy matter ですね。未 初期化値を返すような仕様の方が自由度は高くなるはずですが、その自由度の 高さを嬉しいと考えるかどうかは設計者次第です。 ---- 1002.(ichimal) 2千5百通強の未読メールを処理するのは苦痛だった… 鈴木信吾