/ 最近 .rdf 追記 設定 本棚

脳log[2009-12-12~]



2009年12月12日 (土) [tDiary] 特定のエディタ向けの設定をスクリプトに追加する話。そんなんエディタの側で設定せーよ、とは思うけど、体裁としてはファイル末尾のコメントなので、勝手にすればいいんじゃないかな。でもね、6行は多いよ。


2009年12月11日 (金) ロンバケ(再)が終わってしまいました。


2009年12月10日 (木) [C++] delete this; あえてこういう質問をするからにはできるんだろう。メンバ変数にアクセスしなければ無事にやりすごせる気がする。規格として結果が定義されてるかどうかは知らない。どういうシチュエーションだろう。自分がヒープ上に置かれていることを知ってるってのは。自己発生して自動消滅するオブジェクト……。@2009-12-11 元記事の、「v-tableがどうのというやつがいるがそれはクラスに一つだ」と(までは書いていないがそう)いうくだりまで読んだ。仮想関数の呼び出しもできなくなりそう。vptrがなくなるから。今まで vptrという単語を知らず、vtblと vptrを混同していたのは内緒。


2009年12月09日 (水) [HTML] CSSって実装しなくてもいい部分がわりとある。この日記の「ツッコミを入れる」(border-style:outset)をそれっぽく表示してくれるのは 5つのうち Firefoxと Operaだけ。


2009年12月08日 (火) ゲーム用パソコン「ASG7711-A46」(日本エイサー) : PC : 新着 ハード&ソフト : ネット&デジタル : YOMIURI ONLINE(読売新聞)」<<< わずかな本文を取り囲む大量のテンプレ。ハイパーリンクが使えず、不足している情報を補うこともできていない。価値ないよ。


2009年12月07日 (月) 予測変換機能や連想変換は知らない単語が出てくるのが楽しい。辞書がセットになっているなら意味もでてくる。知らない単語だから変換の役には立たないけど。


2009年12月06日 (日) [C++]「ヘッダファイルの依存を減らす」<端緒。パフォーマンスの本といえば『Efficient C++』だけかと思っていた(『Boost』にそのように書かれていた)ら、目当ての本の横に『C++パフォーマンス戦略』という本が。これまでのところ大垣書店はすごくよくやっている。Amazonで注文する前にとりあえずのぞいてみて、一度も期待を裏切られていない。

最終更新: 2013-05-21T00:39+0900

[tDiary] つれづれに書き連ねるとリンクしにくいらしいので……(誰の話でしょうね。それにあそこははてな)

<h4>と <h5>にもアンカー(<a name="..."></a>)を与える。href属性や中のテキスト(&nbsp;)は URLをコピーしやすくするためのおまけ。そもそも <h4>や <h5>に id属性を付加するのでなく <a>を利用しているところからが利便性目的以外のなにものでもない。<h4>と <h5>の中に <a>を置くことには、highlight.rbを修正しなくてもハイライトが機能するというメリットもある。デメリットは見出し語の先頭に余分な空白が挿入されている、ということ。セクションタイトル右端の編集用リンク「✍」は、<h3>に含まれないように気をつかっているのですよ。

 core/tdiary/wiki_style.rb, TDiary::WikiSection#do_html4

def do_html4( date, idx, opt )
	strdump = lambda{|s| s.dump.gsub( /%/, '\\\\045' ) }

	r = @html.lstrip
	r.sub!( %r!<h3>(.+?)</h3>!m ) do
		"<h3><%= subtitle_proc( Time::at( #{date.to_i} ), #{strdump.call $1} ) %></h3>"
	end or r.sub!( %r!^<p>(.+?)</p>$!m ) do
		"<p><%= subtitle_proc( Time::at( #{date.to_i} ), #{strdump.call $1} ) %></p>"
	end

	serial = [nil, nil, nil, '%02d'%idx, '00', '00']
	dumped_param = strdump.call "#{date.strftime( '%Y%m%d' )}#p#{'%02d' % idx}"
	header_t = Struct.new(:opentag, :level)
	bqlevel = 0
	r.gsub!( %r!(<blockquote\b)|(</blockquote>)|<h(4|5)[^>]*>!i ) do
		bqlevel += 1 if $1
		bqlevel -= 1 if $2
		next $& if bqlevel != 0 or $3.nil?

		h = header_t.new($&, $3.to_i)
		serial[h.level, serial.length-h.level] = Array.new(serial.length-h.level){|i| i==0 ? serial[h.level].succ : '00' }
		frag = 'p' + serial[3 .. h.level].join('.')
		%!#{h.tag}<a name="#{frag}" href="<%=anchor(#{dumped_param}).gsub(/#p#{'%02d'%idx}/, #{strdump.call('#'+frag)}) %>">&nbsp;</a>!
	end

	r.gsub( /<(\/)?tdiary-section>/, '<\\1p>' )
end

2段階に評価されるせいで、すんごく読みにくい。

ハッシュテーブルのキーがシンボルか文字列か気にしたくないのと、括弧や引用符やコロンがじゃまくさいので、. ひとつで済む Structに登場してもらった。

lambdaの .call() も嫌いだなあ。[] で () を代用するおぞましさよりはマシだが。

試してないけど、「end or r.sub!(...」を複数の行に分けるとシンタックスエラーになりそうなのも嫌。

破壊的メソッドが返す nilを利用するコードを初めて書いた!

 @2013-05-21 URLが変わる大きな修正

H4のシリアルナンバーが増加したときに H5のシリアルをリセットするように変更した。以前はこういう連番だった。

  • p01.01
    • p01.01.01
  • p01.02
    • p01.02.02

最後が p01.02.01になるように。


 @2009-12-09

URLフォーマットが変わると影響範囲が広くて困る。自分の日記へのリンクを検出する正規表現をあちこちで書き直した。

Index: core/tdiary/wiki_style.rb
===================================================================
--- core/tdiary/wiki_style.rb	(リビジョン 43193)
+++ core/tdiary/wiki_style.rb	(作業コピー)
@@ -149,7 +149,7 @@
 			hikihtml = HikiDoc::HTMLOutput.new
 			html.gsub!( %r!<a href="(.*?)">(.*?)</a>! ) do
 				k, u = hikihtml.unescape_html($2), hikihtml.unescape_html($1)
-				if /^(\d{4}|\d{6}|\d{8}|\d{8}-\d+)[^\d]*?#?([pct]\d+)?$/ =~ u then
+				if /^(\d{4}|\d{6}|\d{8}|\d{8}-\d+)\D*([pct]\d+(?:\.\d+)*)?$/ =~ u then
 					%Q[<%=my '#{$1}#{$2}', '#{escape_quote CGI.escapeHTML k}' %>]
 				elsif /:/ =~ u
 					scheme, path = u.split( /:/, 2 )
Index: core/plugin/00default.rb
===================================================================
--- core/plugin/00default.rb	(リビジョン 43193)
+++ core/plugin/00default.rb	(作業コピー)
@@ -480,7 +480,7 @@
 # make anchor string
 #
 def anchor( s )
-	if /^([\-\d]+)#?([pct]\d*)?$/ =~ s then
+	if /^([\-\d]+)#?([pct][\d\.])?$/ =~ s then
 		if $2 then
 			"?date=#$1##$2"
 		else
@@ -540,7 +540,7 @@
 # make anchor tag in my diary
 #
 def my( a, str, title = nil )
-	date, frag = a.scan( /^(\d{8}-\d+|\d{8}|\d{6}|\d{4}|)\D*([pct]\d+)?$/ )[0]
+	date, frag = a.scan( /^(\d{8}-\d+|\d{8}|\d{6}|\d{4})\D*([pct]\d+(?:\.\d+)*)?$/ )[0]
 	anc = frag ? "#{date}#{frag}" : date
 	index = /^https?:/ =~ @index ? '' : @conf.base_url
 	index += @index.sub(%r|^\./|, '')
Index: plugin/html_anchor.rb
===================================================================
--- plugin/html_anchor.rb	(リビジョン 43193)
+++ plugin/html_anchor.rb	(作業コピー)
@@ -14,7 +14,7 @@
 if @conf.index.empty? or /\/$/ =~ @conf.index
 
 def anchor( s )
-	if /^([\-\d]+)#?([pct]\d*)?$/ =~ s then
+	if /^([\-\d]+)#?([pct][\d\.]*)?$/ =~ s then
 		if $2 then
 			"#$1.html##$2"
 		else
Index: plugin/my-sequel.rb
===================================================================
--- plugin/my-sequel.rb	(リビジョン 43193)
+++ plugin/my-sequel.rb	(作業コピー)
@@ -487,7 +487,7 @@
 	alias :my_sequel_orig_my :my unless defined?(my_sequel_orig_my)
 	def my(*args)
 		if @my_sequel_active and @my_sequel_date and @my_sequel_anchor and @mode != 'preview' then
-			dst_date, frag = args[0].scan(/^(\d{8})\D*(?:p(\d+))?$/)[0]
+			dst_date, frag = args[0].scan(/^(\d{8})\D*(?:p(\d+)(?:\.\d+)*)?$/)[0]
 			if dst_date and dst_date < @my_sequel_date then
 				dst_anchor = "#{dst_date}#{frag ? "#p%02d" % frag.to_i : ''}"
 				@my_sequel.add(@my_sequel_anchor, dst_anchor)
Index: plugin/my-ex.rb
===================================================================
--- plugin/my-ex.rb	(リビジョン 43193)
+++ plugin/my-ex.rb	(作業コピー)
@@ -13,9 +13,10 @@
 
 unless @conf.mobile_agent?
 
+alias :my_overwritten_by_my_ex :my
 def my( a, str, title = nil )
 	m = /^(\d{8})\D*(?:([pct])(\d+))?$/.match( a )
-	return '' unless m
+	return my_overwritten_by_my_ex( a, str, title ) unless m
 	_, date, place, frag = *m
 
 	if title.nil? and date and frag and @diaries[date] then

 @2010-03-08: 「ツッコミを入れる」リンクが無効になってしまっていた。

misc/plugin/html_anchor.rbと plugin/00default.rbプラグインを再び修正。

元々if /^([\-\d]+)#?([pct]\d*)?$/ =~ s then
修正ミスif /^([\-\d]+)#?([pct]\d+(?:\.\d+)*)?$/ =~ s then
OKif /^([\-\d]+)#?([pct][\d\.]*)?$/ =~ s then

「ツッコミを入れる」リンクは YYYYMMDD#c へのリンクなので、cの後ろに数字が続いていない。これをうっかり除外してしまっていた。

最終更新: 2014-12-18T13:09+0900

[Ruby] メソッドの困った上書き

すぐ上のセクションで出てきた(俺が書いたんだけど)こういうの、

alias :my_overwritten_by_my_ex :my
def my
  ...
end

こういう「エイリアス&上書き」が嫌いで、不完全ながらこういうものを書いたことがある。(今でも使っている。セミコロンを抑制する努力をしていない頃に書いたもののようだ。Rubyのバージョンで nameをシンボルにするか文字列にするか振り分けているが、今ならやらない。先頭要素を取り出してそれがシンボルか文字列かを調べる。そして、代入を ifで囲うのではなく ifの結果を代入する)

 overwrite.rb

class ::Object
	def overwrite(name, &block)
		if('1.9.0'<=RUBY_VERSION); name = name.to_sym; else name = name.to_s; end
		if(self.singleton_methods(false).member?(name))
			$dirty = [name, block];
			class <<self
				name, block = *$dirty;
				old = instance_method(name);
				remove_method(name);
#				define_method(name){|*params|
#					block.call(old.bind(self), *params); # ブロックは渡せない? 1.9ならできる?
#				}
				define_method("__overwrite__#{name}__#{block.object_id}", &block);
				define_method(name){|*params|
					send("__overwrite__#{name}__#{block.object_id}", old.bind(self), *params);
				}
			end
		else
			if(true != self.class.ancestors.each{|klass|
				if(klass.methods(false).member?(name))
					klass.instance_eval{
						old = method(name);
						remove_method(name);
#						define_method(name){|*params|
#							block.call(old, *params); # ブロックは渡せない? 1.9ならできる?
#						}
						define_method("__overwrite__#{name}__#{block.object_id}", &block);
						define_method(name){|*params|
							send("__overwrite__#{name}__#{block.object_id}", old, *params);
						}
					}
					break true;
				end
			})
				# failure
				raise;
			end
		end
	end
	private :overwrite
end

グローバル変数は赤色でよく目立つね。$dirtyっていう変数はスコープの断絶を乗り越えるために使ってるんだろう。汚いやり方だ。

もはや自分でも読み解けないが、こうして使う(んだったかな? define_methodしたときはブロックで returnが使えた気がする)。

overwrite(:my){|old, *params|
  # 新しいmyを以下に……

  # 必要なら古い定義も呼び出せる。
  return old.call(*params)
}

継承による overrideであれば、隠された同名のメソッドを superで呼び出せるけど、メソッドの上書きではそれができなくて古い定義を呼び出せない。かといって「alias :foo_bar :foo」「alias :foo_baz :foo」式の無秩序なやり方は見るに堪えない。overwrite.rbがやってることも機械的に名前を付ける以外は同じではあるけども(まだましでしょ?)。

<追記@2009-12-19>コメント部分がなんでコメントアウトされているのかやっと思い出せた気がする。奇しくも自分でその理由を書いていたりするのだが。>「define_methodしたときはブロックで returnが使えた気がする」つまり、新メソッド定義(overwriteメソッドに与えられたブロック)を define_methodでメソッド化しておかなければ returnが使えないからだ。かといって古いメソッド定義を渡すために一段余計な処理を挟まなければいけないから、新メソッド定義(ブロック)をそのままの名前でメソッドにすることもできない。ブロックが保持する bindingに変数(旧メソッドを指している)を注入する方法があれば、ダミーの長ったらしい名前を持つメソッドをこっそり定義する今のやり方から抜け出せるかも。</追記>

俺が知らないだけで 1.9以降では解決策があるんだろうか。こういう現実の問題に対処してほしいなあ。わりと見かける aliasの使い方で、問題含みだと思うんだけど。


一人見つけた。

super=承継元クラスの同名メソッドを呼び出す=とは別に、 overridden=上書きされたメソッドを呼び出す=というのを作るというのはどうでしょう?

こちらはちょっと違う。

aliasによるメソッドの再定義は危険なのでUnboundMethodかextendを使おう - (rubikitch loves (Emacs Ruby CUI))

再ロード対策は考えていなかった。

extendは知らないではないけど……(これが求めていたものなんだろうか?)。


新しい名前を導入しないように extendでやってみた。エラーは出ないけどリンク先のサブタイトルが取得できていない(my-exによる拡張が機能していない)。instance_evalを module_evalにしてみてもだめ。

 my-ex.rb

extend Module.new{|mod| mod.instance_eval{
   define_method(:my){|*params| a, str, title = *params
      # myプラグインを拡張し、リンク先が自分の日記のとき、
      # 可能ならサブタイトルやコメントを取得して title属性にセットします。
   }
}}

オーソドックスにやってみても同じこと。

module MyEx
   def my( a, str, title = nil )
   end
end
extend MyEx

extendする対象を間違えてるんだろうか。Pluginのインスタンスに特異メソッドを定義してるつもりでいるんだけど。いずれにしろ答えにたどり着けないのでは使えないよ。def...end と書いてメソッドの定義を上書きするよりも安全で洗練された代替が欲しいんだから、def...endと書く以上の複雑さは受け容れられない。


 @2009-12-11 aliasとコロン

なんでも、aliasするときにメソッド名にコロンを付けてはいけないらしい。

http://www.loveruby.net/w/RubyCodingStyle.html

なぜ付けるかといえば、ほとんどすべてが「実行される」Rubyにおいて、クラスやメソッドの定義(class...end, def...end)ですら実行時の条件によってふりわけられる Rubyにおいて、構文であること、特別扱いされることが許せないからだ。「alias はメソッド呼び出しではなくて構文である。だからこそ引数の間にカンマがないのだ。そこはわかっていながらなぜエセメソッドのような使いかたをするのか。」それは構文であることへの抵抗なのです(俺の場合)。

「ちなみにどうしてもコロンが付けたければ alias_method を使えばいいんではないかと思う。」

そいつ( alias_method )は知らなかった。コロンだけでなくメソッド名とメソッド名の間にカンマを置くこともできるんだから、喜んでそちらを使いますとも。alias_methodと aliasは使える場所や対象が完全には一致していないけども、aliasでしかできないことをした経験はないから問題はなし。


「aliasでしかできないことをした経験はないから問題はなし」なんて書いたそばからこんな例が……

特異メソッドをalias_methodを使用して別名をつけようとするとエラーになる。(中略) 特異メソッドに別名をつけて退避したい場合は、alias_method (_chain)メソッドではなくてaliasをinstance_evalのブロック内で使用するとよい。

特異メソッドは別、でした。想像だけど extendでプラグインメソッドの上書きができなかったのも特異メソッドがらみだと思うな。


 @2009-12-12

昨日の文章はおかしいな。class...endや def...endという構文を認めながら aliasだけを白眼視する説明になっていないような。

class MyClass; endと書いた場合、MyClassは Classオブジェクトの入った定数(という言語のビルディングブロック)だと認識している。def my_method; endと書いた場合、my_methodはメソッド(という言語の(略)であり、以後、my_methodや my_method()と書いた場合それはメソッドの呼び出しである、というのが Rubyという言語の約束だと認識している。「alias alias_of_my_method my_method」という構文は他の構文との共通性がなく例外的なルールに感じられ、(同じコンテクストで用いられる)includeや private、attr_accessorが Moduleのプライベートメソッドとしてあるなかで構文である必然性が認められず、メソッド名に関するルールを破ってさえいる。そこが許せない。aliasの(メソッドではないから正確には違うが)引数の「alias_of_my_method」や「my_method」を言語としてどう位置づけるのか、そこををはっきりさせないのならばそれは使えない、という主張が aliasのメソッド名部分にコロンを付ける理由。

undefや defined?にも aliasと同じ疑問がある(ただし、undefは defの対称として容易に受け入れられるし、defined?の場合、必然性だけは認められる)。JavaScriptの typeof演算子や delete演算子にすら同じ違和感を覚えている*。コンパイル型言語のように、コンパイル時に評価されるのだという言い訳ができないインタプリタ型言語の弱みだろうか。こういうものを見ると Perlに感じたように言語が突然平板なものに見えてしまって嫌なのだ。そこには対象となるメモリやオブジェクトが存在せず、ソースコードの字面しかないでしょう。

* きちんと定義はされています >「[[8.7 Reference 型 (Reference Type)|http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/8_Types.html#section-8.7]]」

最終更新: 2009-12-28T23:38+0900

[Ruby] 1引数ラムダの冗長さ

もうひとつ、最初のセクションからネタ拾い。こんなのや、

 strdump = lambda{|s| s.dump.gsub( /%/, '\\\\045' ) }

別の場所から持ってきたこんなの

 jsstr = lambda{|s| s.gsub(/["\\]/){|x| "\\#{x}" } }

を、自分はときどき書くようだ。[1,2,3].map{|x| ... } みたいなのを書くことはもっとある。「|x| x.」の部分が冗長だね、っていう話。

省きたいけど、単純に考えるとブロックの中が x. で始まっていなければいけない。適用範囲が狭いんじゃないか?と疑問がわく。Rubyは「オブジェクト指向スクリプト言語」をうたっているからメソッドチェインを促す意味でサポートを行う名目はあるだろう。

メソッド呼び出しの構文をとりながら自身を引数にしてよそのメソッドを呼べるようにしたり(C#3.0の extension method風)、Hikiがすでにやっているように

class String
  def escapeHTML
    CGI::escapeHTML(self)
  end
end

本当にインスタンスメソッドにしてしまったり。CGI::escapeHTML("str") より "str".escapeHTML にしておいた方が(1引数ラムダでの利用に)便利ですよ、という動機付けを言語として行ってもいいと思う。あとは引数の束縛やらラムダの .callと []以外の呼び出し方、ブロックやラムダを用いて定義したブロックを引数にしてメソッドを呼び出したりできれば何かができそうな気がしなくもない予感がなきにしもあらず。

全然関係あるのかないのか、Haskellのポイントフリースタイル(初めて目にしたのは 12月15日頃)を検索してみた。$ で順々に処理をつなげているものがあれば . を使って、途中の処理で必要な引数を押し出していくようにしながら一つの処理に書き換えるのだろうか。ポイントフリーなのにポイント塗れとはこれ如何に? 「firstNLines = (.lines).((unlines.).take)」のように明示されなくなった引数 Nはわかりにくくない? 2引数の関数はポイントフリースタイルで書けるの?『ふつける』を通し読みしただけで、モナドもわからず、一行たりとも Haskellコードを書いたことのない人間には疑問がいっぱいです。


2009年12月05日 (土) 先々月に MDT243WGⅡがでてたってね。PS2をつなぐから超解像がプラスされてるのは魅力だ。


2009年12月04日 (金) 記事を何ページにもぶつ切りにするニュースサイトって何なの? クリックする手間をかけさせるなよ、と思って特に興味をひかれたもの以外は 1ページ目で読むのをやめるのだが、「eコマース利用者が感じる1番のストレスは「ページの重さ」【リサーチ】(1/3):MarkeZine(マーケジン)」では「ページが縦に長すぎる」が 5番目に入っている。ジャンルが違うし、どのくらいの長さをいっているのかもわからんが、俺は、広告や定型パーツなどによる無駄な長さでなければ縦に長くても良い。それらがサイドにあるのならばそれすら問題ではない。


2009年12月03日 (木) [Vista] デスクトップにて。幅0の選択範囲というのは存在しないらしい。マウスを縦にドラッグしてから幅が0になるように横に移動すると、幅が0になった瞬間だけアイコンの選択が解除される。解除する必要ってないよね。


2009年12月02日 (水) なぜかいま Legend of Dragoon。120fps。画面から判断するベストタイミングからきもち遅らせるというようなコンマ 1秒程度の微調整が必要。3回攻撃は全然ポイントがたまらない。敵がわりと強い。ポリゴンが残念。SFCとくらべて PSは陳腐化が激しい。


2009年11月30日 (月) [BAD BOY] シフトワイヤーが切れた。シフトダウンは、ガッと 2、3段落としたりするからだろうなあ。ローノーマルだったらシフトダウン側がバネの力になるからワイヤーをちぎってしまうこともないかも。<<< そうすると今度は信号待ちからの発進で、チョンチョン、チョンチョン、ってなシフトアップ(4段)が問題になるんだよ。

最終更新: 2010-01-15T21:20+0900

[][][雑誌] 【Interface (インターフェース) 2010年 01月号 [雑誌]】 CQ出版

上前津伏見くんの写真の中に、トラ技を背景にする Interface誌を見つけた。その数日前に「ときどきの雑記帖 i戦士篇 2009年11月(上旬)」で同誌の連載について触れられているのを読んでいた。こういう巡り合わせには積極的に乗っかることにしている。

家の本棚にはトランジスタ技術があったけど、読んだのは C言語特集だけ。volatileというキーワードをそこで発見して、十年以上前の Cにはそんなキーワードがあったのかと思ったら、単なる自分の知識の穴であって、その後 volatileを付けないと期待通りに動作しないケースに自分で遭遇することもあったり。ともかく、ハードウェアはわからない。

あらら、今月は隔月連載の載ってない月だ。来月号も買って、それで一年はお腹いっぱい。


「ラプラス変換がラブプラス変換に見えて困る」(某所にて) に対して、ラプラス変換なんて見たことねーよ、と心中で突っ込んでいたら、モーターのところで出てきた。


2009年11月29日 (日) 最先端からは何周遅れかな~。

最終更新: 2010-01-15T21:20+0900

[C++] ミックスイン

読みやすくも正確にも書けないのでリンクだけ。

サクラエディタの肥大化する一方の CEditView(描画、ダイアログの表示、文字列検索、単語判定、URL判定、ドラッグアンドドロップ対応、などなどなんでもござれ)を機能ごとに分割したいなあ、と考えていて、モデルとして想定していたのが Rubyの Enumerableモジュールのミックスイン。Enumerableを ミックスイン(include)するクラスが eachメソッドを提供するだけで、およそシーケンシャルアクセス可能なコレクションに対して行いたい操作(max, min, find, map,...)のすべてが可能になるという仕組み。

C++でやるにはどうするのかな、と想像していたときに「これってあれじゃね?」と結びついたのが「奇妙に再帰したテンプレートパターン(CRTP)」。このパターンは「[単行本(ソフトカバー)] ビョルン・カールソン【Boost C++をチューンアップする最先端ライブラリ】 ピアソンエデュケーション」で仕入れた。

仮に Enumerableモジュールのようなものをこのパターンで実現できたとして、その Enumerableテンプレート(eachメソッドが定義されたクラスをテンプレートパラメータとして受け取る)が配列っぽいあれやこれやのクラスにミックスイン(継承)されたらオブジェクトファイルがすごく肥大化しそうだという気がする。

純粋仮想関数にした eachに依存する形で Enumerableの各メソッドを実装すれば、テンプレートを使ったときと違って実装の共有ができるだろうか。

というようなことを想像してるだけ。


eachが yieldする型は何になるんだ?(C++で yieldなんてできないという話はおいておいて) 結局、型安全性を求めたらテンプレートになって、型ごとに実装(テンプレートのインスタンス)が作られるんじゃないか。

と、ここで boost::anyを使ってはどうか。Enumerableのメソッドの実装は要素の型に依存しないから anyのまま扱う。Enumerableのメソッドを呼び出す側が要素の型を知っているから anyから正しい型のオブジェクトを取り出せる。

と思ったら、「Enumerableのメソッドの実装は要素の型に依存しない」は嘘だ。比較できないと最大値や最小値が求まらん。Enumerableがコレクションに対して求めてるのは eachだけだけど、その要素に対しては比較できることや加算できることなど、いろいろ要求している。これじゃあテンプレートでないとやってられない。

いやいやいや、min, maxをはじめ Enumerableのほとんどのメソッドは要素を引数にとるブロックを受け付けて、その結果を基に処理を行っている。ブロックのコンテキストは Enumerableのメソッドを呼び出す側だから要素の型を知っている。やっぱり Enumerableの実装は要素の型を知らなくてもいい。

ブロックの代わりになるのは関数オブジェクトか traitsかな。


とまあ、かように面倒くさそうなことになるから CEditViewクラスになんでも突っ込む結果になるのも当然。言語の不備だ、とか言ってみる。

あるクラス(CEditDoc, CEditView)にいろいろな特性(検索可能性、ドラッグアンドドロップ可能性、範囲選択可能性、……)を、簡単にクラス外から付加する確立した手順が必要。……と、あくまで想像するだけ。

それに分割してしまうと機能間での連携(依存ともいう)に苦労することになるのが目に見えている。ANSI版の CEditViewはなんでも一カ所につっこめる限界点を超えているとは思うが。


mix-inや traitsは、使われる場所でいろいろ意味が違うみたい。自分は mix-inといえば Rubyのしか知らないし、traitsといえば std::stringの char_traitsしか知らない(それすら知っているとはいえない)。