yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2018/09 の記事
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
フルキャストエクセプション
2007/08/03(Fri)19:27:15
 今度はフルキャストに業務停止命令。専門知識が必要かつ危険であるとして派遣が禁じられている業種への派遣を繰り返し、自治体から是正指導や業務改善命令を受けていたにもかかわらず、同じようなことを好き勝手に繰り返していたといいます。
 処分は当然どころか、特定業種への派遣は危険だから禁じられているのであり、人命を危険にさらした罰が業務停止などとはあまりに軽すぎます。確かに業務停止は組織としては重い処分ですが、これが「1度のうっかりミス」ならともかく、組織立った確信犯である可能性が極めて高いのですから、解散や売却譲渡が必要なほどの罰を与えてもやりすぎではありません。それが違法行為への報いであり、自業自得です。嫌なら違法行為をしなければ良いのです。
 クリスタル、グッドウィル、フルキャストといった具合に、腐りきった派遣業の実態を嫌というほど見せられる今日。その間に他の業界でも様々な不正が起きましたが、どうやら派遣業には特に不正が起きやすい土壌があるようです。少し前まではピンハネ行為が常態化しており、偽装請負も偽装派遣も何でもあり。かのキヤノンすら偽装を行っていたのです。
 そもそも派遣業が長らく解禁されていなかったのは、この業種の存在自体がピンハネであることによります。そうした懸念から禁止されてきたにもかかわらず、それをあっさり解禁したところ、懸念は大当たり。圧倒的な力関係を利用して力ずくでピンハネを認めさせ、そればかりか免許を持っていないのに機械を制御させるなどの違法行為を強い、事故による死者まで出ました。解禁しない方が日本のためになったものと考えられます。
 相次ぐ問題で派遣業に対する風当たりは明らかに強くなっていますし、またそうなってもらわなければ困ります。派遣業の売り上げは全部ピンハネによって出されているわけですから、ここまで肥大化する会社というのは、それだけピンハネを行っていることになります。派遣業が解禁されて何十年と経たないにもかかわらず、ここまで会社が肥大化したり、雨後のたけのこのごとく派遣会社が湧き出てくる現状は、どう考えても異常です。
 安易な規制緩和は災いを招きます。派遣業に関してはこれでもう明らかでしょう。今後は安易な規制緩和を避け、派遣業については少しずつ規制を元に戻していくことが必要であると考えられます。派遣会社からは異論も出るでしょうが、これまでの自らの行いを省みずに異論のみ元気良く主張するような連中の言い分に耳を貸す必要はありません。平たく言ってしまえば、規制とは「ネコとネズミ」や「ライオンとシマウマ」が平等に試合をするための土俵を準備しているようなものですから、これをなくせばどうなるかは明らかです。ご存知の通り、派遣業ではネズミがネコに食い物にされ、その力関係によってピンハネも違法行為もやり放題です。
 ここまで問題が頻発するとなれば、おそらく役人連中といえど黙っていることはできません。これまでは規制緩和の上にあぐらをかいていたとしても、今後の派遣業への規制強化と罰則強化は不可避の流れでしょう。規制強化は安倍政権である限り無理としても、違法派遣に適用される罰則が重くなることはあっても軽くなることはないものと考えられます。これも自分がまいた種ですから、当然の結末です。

 政治資金規正で、領収書添付1円から案に自民党内で異論噴出。予想されていたこととはいえ、これだけ惨敗しておきながら懲りない連中です。このような醜態をひたすらさらした挙句、結局骨抜き法案を強引に成立させ、国民にそっぽを向かれて民主党が政権を取り、元野党共同で厳しい規制法を出す、などという流れになるのであれば、それも良いでしょうが。政治資金規正法に関しては、与党より野党案の方が明らかに優秀であるものと考えられますが、双方が法案を出してきたとしても、双方が合意しなければ通りません。しかし、おそらく自民党は厳しい野党案を拒むでしょう。野党は骨抜き与党案に合意するかどうか。合意しても骨抜きですし、合意しなければ今のまま変わらないのです。肝心なところが骨抜きならどちらも同じでしょうが。
 具体的には「慶弔費では領収書は取れず、現実的でない」といった意見が存在するようです。確かにそのような場合もあるでしょうが、どうしても領収書が取れないようであれば、領収書が得られない場合に限って領収書と同等の申告書なりに書くことを義務付ければ済みます。無論、申告書には領収書を取れない理由を明記し、かつ使用額と使途はすべて一般に公開し、申告書で不当な横領が行われないことを担保します。冠婚葬祭の使用額があまりにも不当であったり、議員の行動と名目が一致しなかったり、本来領収書が出る場面なのに申告書を使っていたら、全部バレるという寸法です。わざわざ情報公開を求めなければ入手できないのではなく、政府のWebページで公開するのが良いでしょう。
 当然のことながら、迂回路は絶対に認めてはいけません。いかなるルートを通ろうとも、その使途は最後の1円まで徹底的に突き止める必要があります。ぬるま湯につかってきた政治家にとっては難しそうですが、支出金と使途の帳尻が合うのは当然です。突き止められない分は弁済していただくと同時に、明らかにおかしな使途や額の支出が発覚したら、その支出の事実や適切さを証明する責任も負わせる必要があります。
 安倍氏は当初、「月800円で」などとして赤城氏をかばっていましたが、これほどとんちんかんな言は聞いたことがありません。そもそも800円などという規模ではなく、領収書の2重提出までやっていた、ということは置くとしても、不正行為を行う体質や思考が問題なのであり、ごまかしが1円だろうが1億だろうが辞任に値します。これが「月800万円」なら同じことは言わなかったのでしょうが、行いは同じにもかかわらず「月800円」なら良くて「月800万円」ならダメという根拠も不明です。なぜ即座に首を切らなかったのか、理解に苦しみます
 不正を防ぐには、政治家の自浄作用に期待していてはいけません。厳しい規制と徹底的な情報公開、これしかありません。もしそれが嫌だとワガママを言い出すようであれば、共産党のように交付金を受け取らなかったり、経費を全部自腹で行うなど、最初から領収書が要らない方法を使えば良いのです。それができないというのなら、やはり領収書を金額にかかわらず添付し、1円単位まで帳尻が合わないものは認めないようにすることは必須です。

 帳簿の帳尻が合わず、差額が9で割り切れるなら、桁違いを疑えとは先人の知恵です。しかし、もし政治家が相手であれば、「11」や「111」で割り切れるなら、が正しいかもしれません。2重勘定などやった日には、普通の人なら真っ青になるところなのですが。
 ところで、小沢体制になってからは本当に「反対ばかり」が目立ってきた民主党。政治資金規正についてはぜひとも厳しい対案をぶち上げて欲しいところです。しかし、それ以前は過剰なほどは「何でも反対」ではなかった気がするのですが、なぜあそこまで「何でも反対」扱いされる必要があるのでしょう。参院選の野党過半数を受け、読売新聞も「これからは何でも反対ばかりではいられない」などと書いていましたが。
 しかし、「テロ特措法 民主党は延長反対を再考せよ」なる社説見出しを見て分かりました。要するに自分が賛成している事柄に反対するから「何でも反対」呼ばわりなのです。そもそも野党は自力で法案を成立させられないのですから、与党案に対する賛否が主な行動になるのは避けられませんが、与党がムチャクチャなものばかり出してきたら、それは反対せざるを得ないでしょう。それで、その「ムチャクチャなもの」を支持していた連中が、民主党を「何でも反対」扱いするという。
 とりあえず、民主党が参院提出した政治資金規正法案や年金流用停止法案をもし与党が否決したら、「自民党は何でも反対だ」とでも言ってくださいな。それから、民主党には「新聞の特殊指定廃止」や「個人情報保護」の法案を出すか、これらへの自民党の規制強化に賛成し、「我々は反対ばかりの党ではない」とマスコミの前で堂々と言い切って欲しいです。その時に「何でも反対」と言い続けていたマスコミがどういう顔をするか、実に面白そうです。
 後は阿久悠氏が死去。「ジョニィへの伝言」はこの人の作詞でしたか。当時の名曲は今でも数多く残っています。しかし、今の音楽が20年後、30年後に残っているかといえば、おそらく残るのはごく一部でしょう。ベートーベンが書いた曲は何百年も残り、現代人が書いた曲は10年も経てば消えるのです。つくづく、現代の作詞作曲家やアーティストはもっと曲を大切にしても良いのでは。どうも現代はそのような傾向が強いようです。ゲームなども映像は綺麗になっているようですが、キャラクター、ストーリー、システムが相対的にぞんざいになり、作者の愛着が減ってきているといいましょうか。
 さて、今回はこれまで(なぜか)扱っていなかったイテレータを。PHPで次のような書き方ができることは知られています。
$array = array("a" , "b" , "c");

foreach($array as $value){
	// ...
}
 このように、配列に対してforeachによる読み込みが可能になっています。配列がハッシュの場合はこうなります。
foreach($array as $name => $value){
	// ...
}
 実のところ、PHPの配列は添え字がキーであるハッシュと同等であり、「$array[0]」と「$array["0"]」では同じなのですが。さらに、PHPではオブジェクトもおおむね配列とみなされており、フィールドをforeachで取ってくることができます。
class Test{
	var $a;
	public $b;
	protected $c;
	private $d;
	function __construct(){
		$this->a = "A";
		$this->b = "B";
		$this->c = "C";
		$this->d = "D";
	}
}

$t = new Test();
foreach($t as $name => $value){
	print "$name=$value\n";
}
 結果はこうなります。
a=A
b=B
 public変数を配列として取得していることが分かります。それにしてもこのいまいましい$this->、何とかならないものでしょうか。今回もこれのせいでまた書き間違えました。これが何と、Perl 6では「$.var」や「$!var」だけで済むのです。PHPはせっかくJavaモデルのオブジェクト指向を提供しているのに、私はこれとGLOBALSのせいでPHPでコードを書く気になれません。$this及びグローバル関連のバグを出さない自信がないのです。Perlなら最初からこうした問題は避けられますし、ローカル変数はmy宣言するだけ、my宣言を忘れるのが怖いなら「use strict;」で解決です。
 Cはグローバルの宝庫です。そういう言語ですから仕方ありません。C++はクラスのおかげでCのコードやライブラリを使う場合にのみグローバルを使えば良いようになりましたし、Javaはそもそもグローバル変数がありません。Perlに関しては、Cの#DEFINEやJavaのpublic static finalに当たるものがないため、設定用変数をグローバルにすることが多いのですが、それを除けば残りのほとんどの変数にはmyをつけても大丈夫ですし、そのようなコーディングでないコードは綺麗とは言いがたいです。
 しかしPHPはといえば。GLOBALSのおかげでグローバル変数は使い物になりませんし、下手に使うとコードが読みにくくなり、バグの温床になります。「グローバルで困り果てるのはCも同じ」とオブジェクト指向にしてみれば、今度は$thisが頭を悩ませてくれるのです。もちろん1箇所でも$thisを忘れるとバグですし、それが単なる変数の場合、Perlの「use strict;」のように警告があるわけでもなく、空変数として扱われるのみです。これがなければPHPはもっと普及していたでしょう。
 それでは本題、イテレータです。PHPでは上記の通り、配列やオブジェクトをforeachで処理することができるのですが、PHP 5ではオブジェクトへのforeachの処理を定義できるようになっています。おそらくドキュメントを一通り読んだ方ならご存知でしょう。最初から用意されているクラスである「Iterator」をインプリメントするだけです。
 ここでは「渡された文字列を1文字ずつ返す」コードをサンプルとします。
class CharIterator implements Iterator{
	private $str;
	private $index;
	function __construct($str){
		$this->str = $str;
		$this->rewind();
	}
	function rewind(){
		$this->index = 0;
	}
	function key(){
		return $this->index;
	}
	function current(){
		return $this->str[$this->index];
	}
	function next(){
		$this->index ++;
	}
	function valid(){
		return (strlen($this->str) > $this->index);
	}
}

$ci = new CharIterator("PHP Hypertext Preprocessor");
foreach($ci as $c){
	print "$c";
}
 内容は見ての通りでしょう。rewind()は巻き戻し、key()はキー取得、current()は値取得、next()は次の要素に移動、valid()は要素がこれ以上存在するかを確かめます。
 具体的には次のような流れになっているものと考えられます。

1.オブジェクトがforeach()で呼ばれた際にrewind()が呼び出される。上記サンプルでは($indexが初期化されないのは気持ちが悪いため)コンストラクタでrewind()を呼んでいますが、実際には呼ばなくても良いことになります。
2.valid()を呼び出し、要素が存在するかを確かめる。trueなら続行し、falseならそこでforeachループを抜ける。
3.current()で得られる値をas変数に渡す。もしasの部分がハッシュとされていたら(foreach($obj as $name => $value)など)key()の値をキーとして変数に渡す。
4.foreachループ内の処理を実行する。
5.nextを呼び出し、(2)の動作へ戻る。

 おおむねこの通りでしょうが、それにしてもkey()メソッドの動作は分かりづらいところです。JavaのIteratorには存在しない概念ですし。これを使ったサンプルも作成するとしましょうか。
 しかし、キーと値がセットのデータを返すべきオブジェクトとはどのようなものでしょうか。少々考えた末、今回もまたアレの力を借りることにしました。
CREATE TABLE php_iterator_data(name VARCHAR(32) , value VARCHAR(32) , 
PRIMARY KEY(name));
 相変わらず大活躍のSQL。これなくしては語れません。昨今は「オンラインゲーム依存症」などが問題になっていますが、「SQL依存症」も深刻な問題なのです。SQLサーバーが使えなくなれば、その場で機能停止を余儀なくされるという。私の場合、RSSリーダーもSQLに頼っているため、SQLサーバーが落ちればRSSリーダーすら使えなくなります。
 それは今に始まったことではないとしまして。適当にデータでも登録してみます。
INSERT INTO php_iterator_data VALUES
('php' , 'PHP Hypertext Preprocessor') , ('pdo' , 'PHP Data Object') , 
('dom' , 'Document Object Model');
 名前と値が関係していれば、中身は何でも良いのですが。
 データを登録できたら、次のようにしてIteratorを実装します。
class DataIterator implements Iterator{
	private $pdo;
	private $statement;
	private $data;
	function __construct(){
		$this->pdo = new PDO(
			"mysql:host=localhost;dbname=database" , 
			"username" , "password");
		$this->pdo->exec("SET NAMES sjis");
	}
	function rewind(){
		$this->statement = $this->pdo->prepare(
		"SELECT name , value FROM php_iterator_data ORDER BY name");
		$this->statement->execute();
		$this->next();
	}
	function key(){
		return $this->data["name"];
	}
	function current(){
		return $this->data["value"];
	}
	function next(){
		$this->data = $this->statement->fetch(PDO::FETCH_NAMED);
	}
	function valid(){
		return $this->data;
	}
}

$di = new DataIterator();
foreach($di as $n => $v){
	print "$n:$v\n";
}
 SQLとイテレータの違いといえば、SQLがデータをフェッチして次々とカーソルを進めることに比べ、イテレータでは「データの存在をチェック -> データを取得 -> カーソルを進める」の流れになっている点でしょう。こればかりはイテレータ側で実装すべきことですので、next()時にデータを取得し、valid()でデータの有無を確かめられるようにしています。
 結果は次の通り。
dom:Document Object Model
pdo:PHP Data Object
php:PHP Hypertext Preprocessor
 なかなか便利です。ハッシュのある言語ならではの特性といいましょうか。
 ところで、これはシングルスレッドなら別に問題なく動作するのですが、マルチスレッドでは少々困ったことになります。スレッドAがforeachを呼び出し、その最中でスレッドBが同じくforeachを呼び出すと、スレッドAが処理しているイテレータまでもが巻き戻されてしまいます。その上、next()が双方で呼び出されるため、取得されるデータがちぐはぐになります。これを防ぐには「foreachのたびにロックをかける」という不毛すぎる処理が必要です。PHPはシングルスレッド前提としても、Javaではどうなっているのでしょう。
 しかしそこはさすがにJava、上手くできています。イテレータ機能を持つIteratorを実装してもfor-each文の対象にはならず、Iterator型を返すメソッドを持つIterableを実装したクラスがfor-eachの対象になるのです。実際、ArrayListはIterableを実装してはいますが、Iteratorを実装していません。for-each文が実装されたのはSE 5の際ですから、今からすればかなり前になりますが、その時に膝を打った人は結構多かったのでは。当然といえば当然ですが。
 ただ、なぜかIteratorにはremove()が存在し(任意のオペレーション)、選択中の要素を削除できるようになっているため、マルチスレッドでこれを使うならsynchronizedが必要でしょう。また、イテレータで読み取り中に元のデータが更新される恐れがあるなら、やはりsynchronizedは避けられません。しかし、2つのスレッドが単にfor-eachでデータを読み取るだけであれば、synchronizedは一切不要です。
 以下、文字列を単語区切りで返すサンプルです。
class StringIterable implements Iterable<String>{
	private String str;

	public StringIterable(String s){
		str = s;
	}
	public Iterator<String> iterator(){
		return new StringIterator(this);
	}
	public String getString(){
		return str;
	}
}

class StringIterator implements Iterator<String>{
	private int pos;
	private StringIterable si;

	public StringIterator(StringIterable si){
		this.si = si;
		pos = 0;
	}
	public boolean hasNext(){
		String str = si.getString();

		int index = str.indexOf(" " , pos);
		if(index == -1){
			if(str.length() <= pos)
				return false;
		}
		return true;
	}
	public String next() throws NoSuchElementException{
		if(!hasNext())
			throw new NoSuchElementException();

		String str = si.getString();
		int index = str.indexOf(" " , pos);
		if(index == -1)
			index = str.length();

		String r = str.substring(pos , index);
		pos = index + 1;
		return r;
	}
	public void remove() throws 
		UnsupportedOperationException , IllegalStateException{
		throw new UnsupportedOperationException();
	}
}
 StringIterableがStringIteratorを返し、StringIteratorがイテレータ処理を提供します。この場合、for-each処理ができるのはStringIterableのインスタンスです。
 JSPであれば以下のように使用できます。Javaアプリケーションの場合、outをSystem.outに直せば使えるでしょう。ジェネリックスのおかげで手間もかかりません。
StringIterable si = new StringIterable("This is the JavaServer Pages");
for(String s : si){
	out.println(s);
}
 結果はこうなります。
This
is
the
JavaServer
Pages
 ついでにマルチスレッド版もあります。
// 宣言
class TestThread extends Thread{
	private StringIterable si;
	private PrintWriter out;

	public TestThread(StringIterable si , PrintWriter w){
		this.si = si;
		out = w;
	}
	public void run(){
		for(String s : si){
			out.println(this + ":" + s);
			try{
				sleep(50);
			}catch(InterruptedException e){
			}
		}
	}
}

// 実装
StringIterable si = new StringIterable("This is the JavaServer Pages");

TestThread t1 = new TestThread(si , new PrintWriter(out));
TestThread t2 = new TestThread(si , new PrintWriter(out));

t1.start();
t2.start();

try{
	t1.join();
	t2.join();
}catch(InterruptedException e){
}
 マルチスレッド環境でも使えることが一目瞭然です。ただ、しつこいようですが、元のデータに手を加える可能性がある場合はロックを忘れないようにしましょう。今回の例では元のデータがprivateであり、しかもsetterも存在しないため、元のデータが変更されることはありませんが。
 そういえば、Java SE 7ではプロパティを導入するなどといった話があるようですが、実際どうなるのでしょう。後は関数を導入したり、クロージャを作るとか。後はJARではなくJAMなるアーカイブ形式を作るそうです。Javaに「サーブレット」というだけである意味しゃれが効いているのに、その上に「JAM」ですか。
 C++のfriendを導入する構想もあるとか。これは賛否ありそうですが、ありではないでしょうか。C++ではクラスがガチガチに固められており、protectedはサブクラス以外、private変数はあらゆるクラスからアクセスできません。日本のお役人と違い、相手が政府高官だろうが米大統領だろうが例外なく弾き飛ばします。
 しかし、friend指定したクラスからのみはこれらにアクセスすることができます。Javaで同じことをするのであれば、一応「パッケージレベル」が存在し、アクセス指定子をつけなかった変数やprotected変数は同じパッケージ内からであれば自由にアクセスできるのですが、これではパッケージを分けることができませんし、パッケージが肥大化してくるとカプセル化の意義が縮小し、オブジェクト指向の観点からも問題になります。
 そうなると、今まで迂回路と見られてきたfriend指定が合理的に見えるから不思議です。Javaは「特定のクラス間で共用したい変数・メソッドは、それらのクラスがパッケージ内にあるならパッケージレベル、そうでないならpublicにせよ」という方針であり、これでは必要以上にアクセス権を上げる必要がありますが、C++なら「特定のクラスをfriend指定せよ」ですから、カプセル化の面ではより安全です。いずれにせよいびつであることは否めませんが。
 例えば上記のStringIterableを例に取れば、本来privateでも良いはずのgetString()をpublic指定にしています。仮にStringIterableの文字列に外部からアクセスされたくなくても、StringIteratorでこれを使用する必要があるため、privateにすることはできないのです。別にpublicでなければならないわけではありませんが、どうしてもパッケージレベル以上のアクセス権は必要になります。
 C++ならこう書けます。
#include <stdio.h>

class Iterator{
public:
	virtual bool hasNext() = 0;
	virtual void* next() = 0;
};
class Iterable{
public:
	virtual Iterator* iterator() = 0;
};

class NoSuchElementException{
};

class ArrayList : public Iterable{
	friend class ArrayIterator;
	void **source;
	int len;
public:
	ArrayList(void** , int);
	Iterator* iterator();
};
class ArrayIterator : public Iterator{
	int index;
	ArrayList *al;
public:
	ArrayIterator(ArrayList*);
	bool hasNext();
	void* next();
};

ArrayIterator::ArrayIterator(ArrayList *a){
	al = a;
	index = 0;
}
bool ArrayIterator::hasNext(){
	if(index < al->len)
		return true;
	return false;
}
void* ArrayIterator::next(){
	if(hasNext()){
		void *data = al->source[index];
		index ++;
		return data;
	}

	throw NoSuchElementException();
}

ArrayList::ArrayList(void **c , int l){
	source = c;
	len = l;
}
Iterator* ArrayList::iterator(){
	return new ArrayIterator(this);
}

void main(){
	char *source[] = {"This" , "is" , "the" , "C++"};
	ArrayList al((void**)source , 4);

	Iterator *i = al.iterator();
	while(i->hasNext()){
		char *str = (char*)i->next();
		printf("%s\n" , str);
	}

	delete i;
}
 やはりコーディングはC++よりJavaの方が楽です。というのは置いておいて。
 Iterable実装クラスであるArrayListのpublicメンバがコンストラクタとiterator()のみである点に注目しましょう。ArrayIteratorはfriend指定されているため、イテレータのためにアクセス権を緩める必要がないのです。
 それにしてもC++、文句を言っても仕方ないのは分かっていますが、どうにかならないのでしょうか。そもそもJavaモデルの実装をC++に持ち込むのが悪いのですが、なかなか厳しいです。iterator()が返すのはIterator*型ですが、ここでポインタでなく実体を返そうとすれば、スライシング現象が発生してIteratorの子クラスを返せなくなってしまいます(それ以前にIteratorは抽象クラスですからコンパイルエラーになります)。かといってArrayIterator型のローカル変数を生成し、そのポインタを返したとしても、iterator()を抜けた時点でその変数は破棄されるため、ポインタは使えなくなります。そうなるとやはりnewしかありませんが、これは受け取った側の責任でdeleteしてもらわなければリークします。
 C++への文句はともかくとして、このようにJavaでfriendが導入されれば使いどころはなくもありません。といっても、先の場合はこう書けば良いのですが。
class StringIterable implements Iterable<String>{
	private String str;

	public StringIterable(String s){
		str = s;
	}
	public Iterator<String> iterator(){
		return new StringIterator(this);
	}
	private String getString(){
		return str;
	}
	public class StringIterator implements Iterator<String>{
		private int pos;
		private StringIterable si;

		public StringIterator(StringIterable si){
			this.si = si;
			pos = 0;
		}
		public boolean hasNext(){
			String str = si.getString();

			int index = str.indexOf(" " , pos);
			if(index == -1){
				if(str.length() <= pos)
					return false;
			}
			return true;
		}
		public String next() throws NoSuchElementException{
			if(!hasNext())
				throw new NoSuchElementException();

			String str = si.getString();
			int index = str.indexOf(" " , pos);
			if(index == -1)
				index = str.length();

			String r = str.substring(pos , index);
			pos = index + 1;
			return r;
		}
		public void remove() throws 
			UnsupportedOperationException , 
			IllegalStateException{
			throw new UnsupportedOperationException();
		}
	}
}
 しかし、例えばJAX-WSではprivateフィールドはXMLに反映されないものとみなされます。これはライブラリ側でprivateフィールドの値を取得・書き込みうできないのが原因なのでしょうが、これをEntity Beanと組み合わせて使用し、さらにID値を自動生成する場合、ID値を手動でsetさせたくないということはあり得ます。このような場合、できればsetメソッドをprivateにしたいところですが、そうするとJAX-WSで弾かれてしまいますので、publicでなくてはなりません。
 このような場合、friendがあれば「JAX-WSなど特定のライブラリクラスにのみ読み書きを許可する」ということができるため、こうした状況に対応しやすくなります。ただ、こうした使い方を想定する場合、Javaの最近のモデルはインタフェースベースであり、JAX-WSにせよEJBにせよ色々な実装が存在する可能性を考えると、例えば「friend oracle.toplink.ClassName」といった具合にfriendクラス名を決め打ちにするわけにもいきませんので、「指定したクラスやインタフェースを継承・実装したクラスもfriendの対象にする」といった独自の宣言を導入するなどし、拡張を図ることが必要でしょう。こうなると「とあるクラスのフィールドにアクセスするためだけに、それにアクセスできるクラス・インタフェースを継承する」といったとんでもない実装がなされる可能性もありますが、これはもう実装者の資質の問題です。全メソッドとフィールドをpublic宣言している人と同じレベルです。
 いずれの方法にせよ、それによって生じるジレンマを避けることはできそうにありませんが、ある意味オブジェクト指向やプログラム言語の歴史にはそういう部分があります。C++が生まれて何年と経つのに、未だにオブジェクト指向言語が作られたり発展しているのを見ての通り、オブジェクト指向にはまだ発展の余地があるようです。ちなみに私が知りたいのは、哲学には「人は現実では存在し得ない完璧なリンゴを頭の中に持っており、それと似ているものをリンゴと判別している」という考え方が存在しますが、他人が想像する「完璧なリンゴ」の姿です。何をどうすれば完全なオブジェクト指向となるのでしょうか。しかし、そもそも「目指すべき完全なオブジェクト指向」の姿が「究極のカプセル化とアクセス制御」とは限らず、Perlのようなスカスカなものである可能性もあるわけです。こればかりは何とも。
 ただ、とにかくJavaはC++に比べて書きやすいです。C++と違ってリソースは「作りっぱなし」にしておけば、後はガベージコレクタが勝手に片付けてくれますし。きっと教育もプログラム言語もガチガチではダメなのでしょう。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -