西@九大です。
#【今日の心の準備】200行あります。(疲れた)

From: Minero Aoki <aamine / dp.u-netsurf.ne.jp>
> 西さんが最初に書いておられたのは、「破壊的抽出がほしい」ということ
> だったはずです。しかし、splice でそれができるということがわかったからと
> いって splice の全機能を実装する理由はありません。
> 欲しいものだけ(extract)を実装するだけではなぜだめなのか、ということです。

私の要求はそれ(extract)で満たされるので、それだけでも結構です。(これが
賛成した理由)。でも、せっかくなので、他言語に存在するさらに上位互換な
機能(splice)も参考にして、よい物であればさらなる機能を取り込みたいと思
っています。

全機能を実装する理由はありませんが、同じくらい、現在の要求がある機能だ
けを実装した方がよい、という理由も見あたりません。で、恐らく問題の本質
である、それは本当にいい機能か?(extract+αの機能を持たせるべきか?)に
なる訳ですね。

> しかし、それならばまず「spliceを導入するに足る根拠」を挙げる
> べきでしょう。しかし西さんからはまだなにも適切な理由が挙げられて

まず最初に。私の立場は「意地でも splice!」派というものではありません。
最初、何もない状態で「Perl#splice」に動作が似ている、という話があった
ので、「それでよさそう」と提案しました。その程度の動機なので、その時点
での導入の根拠は?と聞かれれば、、、

> 見えるのは「Perl で使われている」というものだけですから、

に違いありません。これが「導入するに足る根拠」だと言う正当性は、「Perl
にあるものはいいもの(機能)だろう」「互換性を持つべきだ」という個人的な
仮説なだけで、確かにそれは不十分(誤り)です。そこらへん、詳しく考えずに
Perl を盲信したのは確かに過ちでした。(反省)。

盲信というか、ライバル心と言えるかもしれません。Ruby(Array)になくて 
Perl(splice)にある機能が存在するのも悔しいので、条件反射的に splice の
全機能を求めてしまった感があります。軽率でした。

> ぼくも「Rubyではそういう使われ方はない(Perlでは適切でもRubyでは
> 適切でないかもしれないではないか)」と反論しました。

そこはよくわかります。前メールの

>> 後に値を代入するのは、array[args]=val または fill でできる

は、なるほど、と思いました。ただ、それ以外の部分(現在の Ruby との整合
性(意訳)云々)に関しては、先述の通りです。まあ、そこらへんは多分お互い
にもう解決(意志疎通)できていると解釈し、次(本題)に進みます。

> それに、ぼくは Perl は使わないので事情は知りませんが、
> 「機能はあるけど結局ある使いかたでしか使われない」ということは
> ありえるのではないですか?それはみんな知っていても、互換性が
> あるから外せないということは十分考えられます。

はい。複数の機能を持つある関数(メソッド)がある。だが、その中の1つは殆
ど使われない機能である。その関数を別言語に移植するときに、その余分だと
思われる機能も移植すべきか?という事ですね。まあ、恐らく移植しなくても
よいでしょうが、問題はそれが本当に「使われない/余分」かどうか?ですね。

> splice は存在理由が薄い。
> 西さんも extract には反対でない、とおっしゃっているので、じきに
> extract 相当の機能が実装されたとした場合、Ruby には範囲のある
> 抽出もあるし、破壊的取りだしもある。[]= で範囲のある挿入/交換もできる。
> それでは splice はどんな場合に使われるでしょうか?

問題となる機能をまとめると、

Perl#splice
  [1] 範囲を指定した破壊的抽出
  [2] 範囲を指定した挿入/交換
  [3] 範囲を指定した破壊的抽出+代入([1]+[2]と等価)

Ruby#Array
  [1] 範囲を指定した破壊的抽出(extract)
  [2] 範囲を指定した挿入/交換([]=)
  [3] !!!

であり、あおきさんの主張は、

  Perl#splice[3] に該当する Ruby#Array[3] は、標準(基本)メソッドとして
  は存在しないが、所詮 [1]+[2] でできるので、標準メソッド的には不要。
  (array.extract(xxx);array[id,0]=yyy と書けばいーじゃん/できるじゃん)
  
となりますね。ていうか、冷静に私の request の動機を追うと、常にここら
へんに収束する(いつも「語彙だー!」とか同じ事を言って騒いでる)、怠慢が
原因というのが客観的に見えてしまい、ちょっと恥ずかしかったり。(ぽっ)

[3]を標準装備するかについては、その使用頻度に依存しますね。これを定量
的に測る術がないので、これ以上積極的に要求する事はできない気がします。
しかも、他の機能は既に Ruby#Array にあるので、わざわざ splice を持ちだ
す(導入する)のは大袈裟だ、というあおきさんの言い分もよくわかります。

> extract してさらに []= するとき(つまり、splice 本来の目的として)
> ですよね。そんな機会がそう頻繁にあるんでしょうか?(いやない。)

あーん、ここまで折角、もの凄く論理的なよい文章だったのに、何でこの大事
な部分を反語調で片付けようとするのですか!?(泣)。

> ひとつのメソッドとしては想像しにくい。また、実際これまでそれなりに
> Rubyスクリプトを書いてきて(CVSのリポジトリで1MBちょっと)、splice の
> ようなことをしたいと思ったことは一回もありません。一方、extract の
> ような使いかたをしたことはあります。

あ、こういう経験的感覚が根拠な訳ですね。「あおきさんの経験」と言われる
と、それなりの説得力があると思います。確かに不要かもしれません。

> そう頻繁に使われるとも思えないメソッドふたつのくみあわせを
> ひとつにするために標準の機能としてsplice メソッドを用意する
> 必要はないと思います。

問題なのは、任意の2つのメソッドの組み合せでなく、少しは使われる可能性
のある一連の2つのメソッドである、という事。そして、他言語に存在する以
上、全くの無意味なメソッドだとは思い難い、というのが私の意見です。(あ
るかな?と思ってあった時や、ここにはコレがまさにピッタリ!と感じた時に
落ちる鱗もあるんです)。

後は、「無意味でない、でも頻繁に使われる事もない」というメソッドを標準
で実装するかどうか、という問題です。これは、まつもとさんが決定される事
で、これまで、そういうものはあまり実装されてないので、やや不利な気はし
ています。(いいけど)

というか、primitive なメソッドだけでは不満・使い辛いという思う背景には、
蒸しかえすようですが「カスケード式メッセージが送れない」のが原因なので
す。それさえできれば1行で書けるところが、仮変数への代入込みで、3行になっ
たりするのです。

  * a = xxx.yyy.zzz.splice(b..c, val)            # splice
  * a = xxx.yyy.zzz{[c+1,0]=val; extract(b..c)}  # cascading
  * array = xxx.yyy.zzz                          # now...
    a = array.extract(b..c)
    array[b,0] = val
#splice はその配列を再度参照する事を期待するので、この例は大袈裟かも

という事で、正直、Array#splice はそんなに必要だとは思いません。
(Array#extract があれば)。ていうか、"Array#[start,length]=" 等が削除さ
れた値を返すようにすれば、それはもう splice なのではないでしょうか!?

という事で、話はかわりますが、やはり「カスケード式メッセージ」は欲しい
です。(再燃したらしい)

別メールですが、あおきさんの

From: Minero Aoki <aamine / dp.u-netsurf.ne.jp>
> それで提案なんですが、delete_at( i, len ) を self かなにかを返すように

ここで self を返すというのは、"array.delete_at( i, len )[i,len] = val"
としたい、という cascading 願望の表れではないでしょうか?(多分、違う)。
ほら、やっぱりみんな、欲しいんじゃん!(強引な結論)。


[話は Array#pop(n) へ]
> まず、西さん提案では pop(3) は配列最後尾からみっつということですが、
> 「最後からみっつめをとりだす」という解釈も自然ではないですか?

いえ、自然でないです。pop がスタックという概念上の用語である以上、その
途中の値だけ取り出す事はありえません。「ダルマ落としスタック」なる概念
へ拡張しない限り、本棚は崩れてしまいます。

ですが、「n 個目を取り出す」事はないにしても、本棚を例に考えていたら、
pop(n) で「上から n 冊の本をまとめて取る」という可能性に気付きました。
この場合、私が想定していた「pop を n 回繰り返す」とは要素の順序が違っ
てしまい、pop(n) が一意な意味とはなりませんね。(そいつは、困った)

> あるいは、配列最後尾からみっつをとりだすにしても、配列の順序が
> 逆になっていても自然ではないですか?たとえば以下のように。
...
> ようするに、pop( 3 ) の 3 というのがどういう意味の 3 なのか、
> 何が返ってくるのか、想像がつきにくいんです。それはなぜかというと

はい、おっしゃる通りです。
という事で、Array#pop/shift(n) は取り下げます。

> Ruby のよいところのひとつとして、期待した機能が期待した名前で
> 得られるということがあると思います。これは、これまでのRubyの
> 範疇うんぬんではなく、Rubyの「教条」だと考えます。
> 欲しい機能が得られればいいのではなく、それに適した場所と名前が
> 必要なんです。そしてどのようなものが適するのかと言えば、それは
> UNIX や C 言語や Perl やシェルなどの伝統や、Ruby の慣習、自然言語などに
> 基づいて「自然である」ものがそれに値するわけです。

こちらも、おっしゃる通りです。機能ばかりに目が行ってしまい、名前(とそ
れが示す機能への一意性)を見失っていました。上の文章はちょっとプリント
アウトして Ruby 本に挿んでおきたいと思います。

でも、一つ疑問なのは、「伝統」は良いものだけではない、少々悪いものでも
習慣や互換性から残る可能性もあると思います。そういう「Perl の伝統」的
意味合い(互換性)を考えると、「Perl にあるから」というのは、Perl#splice
を導入するのに十分な理由になりえるのではないでしょうか?
#個人的に gets で $_ に代入する必要性を感じないが「互換性」の前に黙認

------------------------------------------------------------------
九州大学大学院システム情報科学研究科 情報工学専攻 博士後期課程三年
      西 和則   ( e-mail: kazunori / swlab.csce.kyushu-u.ac.jp )
------------------------------------------------------------------