成瀬です。

2008/3/18 <rubikitch / ruby-lang.org>:
> 僕としては、エンコーディングは空気のような存在であるべきだと思っています。

エンコーディングは空気ではありません、文字列の同定に必要不可欠な情報です。
極端なたとえですが、分数の分母みたいなものです。

日本語だけでは同じバイト列で違う意味というケースが想像しづらいかもしれませんが、
例えば ISO 8859 シリーズのエンコーディングを持つ文字列が入り乱れている場合には、
ISO-8859-1 の \xC0 と ISO-8859-2 の \xC0 で == が成立しては困ります。

> Ruby 1.9では同じバイト列であっても異なるエンコーディングの場合は == にはなりません。
> 方向性としては正しいかもしれませんが、ハマるケースが多いのではないでしょうか?

よって、必要な情報が落ちているのですから、ハマるべくしてはまっているのだからしょうがない、
ということになります。といっても、おそらく ISO-8859-1 の \xC0 と ISO-8859-2 の \xC0 で
== が成立してしまう場合でのハマり方に比べればはるかに浅いものでしょう。

> String#inspectがencoding情報を表示しない以上、
> 「同じ文字列なのになんで==にならないの!?おかしい!」と思う人が多いと思います。

String#inspect は永続化用のメソッドではありませんから。
たぶん inspect で encoding が表示されてもうれしくないんじゃないですかねぇ。
String#dump あたりだとうれしくなる人もいそうですけれど。

> 異なるエンコーディングの文字列を結合できないのは当然だと思いますが、
> せめて == での比較は許してもいいのではないでしょうか?
> Rubyの == はFixnumとFloatの比較を許すなど空気を読んでくれる演算子だと思っていますが、
> 現状の String#== は厳密すぎると思います。
> より厳密な比較ならばeql?がありますし。

String は基本的に文字列の比較なのですから、文字列の比較の比較であるべきでしょう。
文字列の比較がどうあるべきかを考えれば挙動は決まってきます。
# 方向性としては、むしろ EUC-JP の "あ" と Shift_JIS の "あ" で == が成立するとか、
# そっちの方向に進むのがあるべき姿じゃないかと。

というわけで、バイト列の比較が欲しいのなら String を ASCII-8BIT にするか、
さもなくばバイト列としての比較を行う新しい方法を提案する方が妥当でしょう。

> いちいちforce_encodingをつけるのも気持ち悪いですし。

経験的に、いちいちつけないといけない場合があれば、
それはそれ以前の段階が間違っているサインであることが多いです。

> たとえばネットワークから読み込んだときサーバーが実際と異なるcharsetを吐き出した場合とか。
> 身近な例では何気なく下のようなコードを書いた場合です。
>
> # -*- coding: euc-jp -*-
> # 日本語を含むコード
> RUBY_VERSION                    # => "1.9.0"
> RUBY_RELEASE_DATE               # => "2008-03-14"
> GZIP_MAGIC = "\x1F\x8B"
> open("/tmp/compressed.txt.gz", "r") do |f|
>  magic = f.read(2)   # => "\x1F\x8B"
>  magic == GZIP_MAGIC # => false
>  if GZIP_MAGIC.respond_to? :encoding
>    GZIP_MAGIC.encoding           # => #<Encoding:EUC-JP>
>    magic.encoding                # => #<Encoding:ASCII-8BIT>
>  end
> end

これの場合は、
> GZIP_MAGIC = "\x1F\x8B".force_encoding("ASCII-8BIT")
が正解ですね。
これだけなら妥協できる範囲だと思いますがいかがでしょう。

なお、ここの force_encoding が面倒ならば、バイト列リテラルの提案という手もあります。

-- 
成瀬ゆい
naruse / airemix.com