yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2018/11 の記事
[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
ブログ - yamicha.com's Blog

 存在する記事 776 件の中から 161-165 件を表示しています。
サマータイムのザマ
2007/12/10(Mon)01:18:42
 今まで散々秘密主義が批判されてきた日本の「死刑」ですが、ここでようやく執行者の氏名が公表されるに至りました。遅すぎる歩みと言うしかありませんが、今まで人数が公表されるのみであったことを考えれば、多少は評価に値します。
 しかし、法務省が「情報公開」の理念を遵守または拡大するのため、あるいは「死刑執行は重大な行為であり、国民がそれを知ることができないのは問題」という考えに基づいて氏名公開を決めたのであれば、法務省の決定を支持しない理由はありませんが、実際には法務省の思惑が優先されている印象は否めません
 まず、皆様ご存知の通り、これまでも死刑執行時には執行されたとみられる死刑囚の氏名が報道されてきました。法務省が氏名を公表しなくても、死刑執行された死刑囚の氏名は分かってしまうため、今さら法務省が「公式発表」として氏名を公表したところで、法務省の側としては痛くもかゆくもありません。せいぜい死刑執行を伝える記事の内容が「執行されたのは○○死刑囚とみられる」から「執行されたのは○○死刑囚」に変わる程度です。
 ではなぜ法務省が今さら氏名の公表に踏み切ったのかといいますと、まず考えられるのは「一般予防」の強化です。死刑の秘密主義が多少なりとも改善されるとなれば、マスコミがこれを報道する可能性は高いです。事実、今回も報道されています。また、死刑執行のたびに死刑囚の氏名や犯罪の摘要が取り上げられれば、マスコミが勝手に「死刑による法への信頼効果」と「死刑の恐怖による抑止効果」を向上させるような報道を行ってくれるため、何の代償もなく一般予防効果を上げることができます。
 また、死刑に相当する罪の冤罪・無罪判決や裁判員制度、死刑廃止国の増加など、昨今は日本でも死刑廃止の機運が高まりかねない状況ですが、今回の決定はこうした死刑廃止論へのけん制の意味もあると見られます。死刑に値する罪は当然のことながら重罪であり、死刑時の氏名公表によって死刑囚の罪の重さを国民に印象付ければ、死刑の是非を冷静に考えるより応報感情が先に立つのは当然というものです。
 ところで、なぜ私が「法務省は自らの思惑ありきで、本気で情報公開を考えてはいない」と判断したかといいますと、3人の死刑執行の事実及び氏名が公表されたのが12月7日であるためです。そして、2007年12月7日は言うまでもなく金曜日です。おそらくマスコミや死刑反対論者による追求を避けるためなのでしょうが、死刑は週末に近い木曜日または金曜日に行われるのがもはや慣例のような状態となっています。法務省がまじめに死刑について考えているのであれば、金曜日に執行する必要はありません。
 そして、今回ようやく氏名が公表されるようになったとはいえ、死刑の様態は未だに秘密主義の壁に包まれています。死刑の場面を公開しろとまでは言いませんが、執行所の様子や刑の方法もろくに公表しないようでは「死刑は残虐か」という問題にさえ結論を出せません。日本の死刑がどのようなもので、どのように行われているかも知らぬまま、死刑に関して論じるのは困難です。
 たびたび述べていますが、私は死刑に賛成でも反対でもありません。これは判断を放棄したのではなく、判断材料がないため留保せざるを得ないのです。死刑は残虐な刑罰でないとする最高裁の判決もありますが、ここまでの秘密主義では死刑がどの程度残虐なのかも知ることは困難です。主要な死刑肯定論として「犯罪抑止効果」がありますが、本当に犯罪抑止効果があることを示すデータが提示されたことは1度としてありません。データが示されるとすれば、「死刑は必要」と答えた人が多数を占めるというアンケートの結果のみです。アンケートを見る限り、確かに「死刑による法への信頼性」は存在するらしいのですが、死刑が効果的というデータが示されたこともないのに死刑への信頼性が高いというのは、一種の思い込みでしょう。
 死刑について十分な情報公開を行い、抑止効果を示す検証可能なデータを示されることがなければ、死刑の是非は判断できません。法務省は今後とも情報公開を行うべきであり、それを拒むようなら今回の情報公開も単なる自己都合によるものであると考えて間違いないでしょう。

 温暖化に効果があると主張されている「サマータイム」の導入に賛否。賛成派が省エネ効果による二酸化炭素排出量の削減を主張する一方、反対側は「1時間早く出勤することになり、労働時間が増えるだけ」として反対しています。京都議定書の数値を遵守するにはかなり大規模な対策が必要であり、その1つがサマータイム案のようです。
 私の見解はといいますと、現時点でサマータイムにはとても賛成できません。現実的な危険やコスト増はいくらでも存在し、利便性が損なわれる例ならいくらでも考えられるのに、メリットは非現実的な論や試算ばかりであるためです。賛成論の一部には冷静な分析や理念によるものも存在するのでしょうが、残念ながら多くは机上の空論です。
 まず省エネ効果ですが、有利な試算だけでなく不利な試算も並べて検討すべきです。サマータイムは単に時計を1時間ずらすだけであり、暑い時間が1時間短くなるわけではありません。冷房が必要な暑い時間の長さは同じなのですから、会社員が帰宅後に冷房をつけるなら、結局冷房の稼働時間は変わりません。こうした計算を無視する行為は、単に数字を別のところに付け替えてごまかしているだけにすぎません。
 そればかりか、会社などの組織では最後の1人が退出するまで、もしくは冷房が不要になる時間帯まで冷房を使い、自宅では冷房が不要になる時間帯まで冷房を使うとすれば、わざわざ自宅での暑い時間を1時間延ばすサマータイムより、暑さが和らぐまで多人数をカバーできる組織の冷房の方が効率が良いとも考えられます。サマータイムにしようがしまいが残業者が存在し、その人が冷房が不要になるまで冷房をつけているとするならなおさらです。
 ただ、これを回避する方法が1つあります。それこそが「1時間早く出て労働時間を1時間増やす」ことです。すなわち、サマータイムで効果を上げようとするなら、「労働時間が増える」というサマータイムの懸念を現実化するしかないのです。無論、これでも「1時間早出の上、帰宅はサマータイム適用前の通り」ですから、省エネ効果は疑問視する必要があります。
 一方、サマータイム導入にはシステムの改修などが必要であり、しかも改修後には十分なテストを行わなくてはなりません。日本人は時間に不寛容であり、電車など公共機関での時間の遅れは致命的ですから、ミスを出すことは絶対にできません。したがって、毎年2度の綿密な確認やテストが必要となり、これにかかるコストは相当なものとなります。当然のことながら、この行為にもエネルギーを使用することは言うまでもありません。
 さらに、定時を18時ごろに設定している会社が多いようですが、それを現在の17時に移動しようものなら、その時間帯がかなりの猛暑であることは容易に想像できます。実際に実行されようものなら、迷惑極まりないというのが多くの人の本音ではないでしょうか。さらに問題となるのが学生であり、例えば小中学校などで16時過ぎ下校であれば現在の15時過ぎごろに帰らなくてはなりません。しかも小学生などは「寄り道するな」「店に入るな」「買い食い禁止」などと言われていることが多く、大人のように暑いからと冷房のある建物に避難したり、飲み物を買って飲むことは困難です。子どもは体積の割に表面積が大きく、蓄積できる水分量も少ないため、日射病や脱水症状になる恐れもあります。
 また、サマータイムの趣旨では「夕方の明るい時間を有効に使う」などともっともらしいことが言われていますが、朝の散歩やジョギングなど何らかの習慣がある人のライフスタイルを破壊する点は考えていないようです。見方があまりに一方的過ぎます。
 もしサマータイムに微々たるエネルギー節約効果があったとしても、こうしたデメリットですべて吹き飛んでしまうことでしょう。労働時間増加については厳しい残業代割り増しと無賃残業規制で対策できないことはありませんが(無賃残業合法化などもってのほか)、人間が時計を1時間ずらそうがお天道様には何の関係もなく、冷房が必要な時間は決して減少しないこと、大変暑い時間に帰宅しなければならないこと、システムの改修などでかえってコストとエネルギーがかかるなどの問題を解決するのは困難です。したがって、サマータイムに反対する理由ならいくらでもありますが、賛成する理由は現時点では一切ありません。

 続・Groovy。これで結構色々なことができるようです。
 まずは以前に書いていなかった基本から。Groovyにはプリミティブとインスタンスの区別がありませんが、そこで問題になるのが次のような場合です。一体どうなるのでしょうか。
// パターン1
a = "str"
b = "str"

if(a == b){
	...
}

// パターン2
a = new Integer(100);
b = new Integer(100);

if(a == b){
	...
}
 こうした問題を避けるため、Groovyの==はequals()と同じ挙動となっています。したがって、equals()をオーバーライドしてやれば、Groovyでは==をオーバーロードしたのと同じことになります。
public class Value{
	def int value;
	public boolean equals(Object o){
		if(o instanceof Integer)
			return value == ((Integer)o).intValue();
		return false;
	}
}

Value value = new Value(value:100);
println(value == 100);
 アドレスの比較を行いたい時には「===」なるPHPのような演算子が使えます。
 リストの比較もサポートされています。リストの全要素が同じ場合にのみtrueとなり、要素が同じであっても順番が違うとfalseとなります。
println([0 , 1] == [0 , 1]);	// true
println([0 , 1] == [1 , 0]);	// false
println([0 , 1] == [0 , 1 , 2]);	// false
 マップに順番はないため、マップの場合は順番が違ってもtrueになります。
println(["a":1,"b":2] == ["b":2,"a":1]);	// true
 しかし、ハッシュの初期化方法は言語ごとに違ってややこしくていけません。JavaのコレクションのHashtableやらC++のSTLやらはともかく、スクリプト言語には大抵ハッシュの初期化記述が設けられており、それが混乱のもとです。
%hash = ("name" => "value");	# Perl(hash)
$ref = {"name" => "value"};	# Perl(hash reference)
$hash = ("name" => "value")	# PHP
hash = {"name" => "value"}	# Ruby
hash = {"name" : "value"}	# Python
hash = ["name" : "value"]	# Groovy
 Groovyにはクロージャ(Rubyのブロック付きメソッド呼び出しのようなもの)が存在することは以前に述べましたが、Groovyでは様々なクラスがクロージャをサポートするように拡張されているため、SQLまでもをクロージャの対象にすることができます。また、クロージャといえどもJavaでは単なる1つのクラスであるため、それに基づいてクロージャに対応したクラスを自作することもできます。
 クロージャにはいくつかの暗黙変数が存在し、それを宣言なしに用いることができます。具体的には、渡されたパラメータを表すit、自分自身のクラスオブジェクトであるthis、クロージャを所有している(このクロージャが他のクロージャで囲まれていれば外側のクロージャ、そうでなければthis)オブジェクトが格納されるowner、通常はthisと同じであるものの、必要に応じて他のオブジェクトが取得できる場合があるdelegateがあり、これらを必要に応じて使うことができます。この中でも特に重要なのはitでしょう。{var -> ...}の宣言を書くようにすればitを使う必要はありませんが、他人の書いたGroovyではitが使われているかもしれないため、意味は把握しておくべきです。
// この2つは同じ意味
[1 , 2 , 4 , 8].each({var -> println(var)});
[1 , 2 , 4 , 8].each({println(it)});
 ハッシュではキーと値の2つの変数が必要であるため、{key , value -> ...}としてitを使わないことが多いようですが、必ずしも使えないことはありません。
["a":1 , "b":2].each({println(it.getKey() + ":" + it.getValue())});
 ただ、これでは面倒な上に分かりづらいため、itを使わない書き方を使った方がが良いでしょう。
 さて、こうしてクロージャを使用できることは分かりましたので、ここはぜひとも自作してみたいところです。GroovyはJavaですから、クロージャも単なるクラスのインスタンスに過ぎず、自作できないわけがありません。
// 文字列を1文字ずつ抽出してクロージャに渡すクラス
public class StringEach{
	private String str;
	public StringEach(String str){
		this.str = str;
	}
	public void each(Closure c){
		for(int i = 0; i < str.length(); i++){
			c.call(str.substring(i , i + 1));
		}
	}
}
// 小数点型データの配列を acos にかけ、その結果をクロージャに渡すクラス
public class AcosEach{
	private List<Double> list;
	public AcosEach(List<Double> list){
		this.list = list;
	}
	public void each(Closure c){
		for(double d in list){
			c.call(Math.acos(d));
		}
	}
}

// StringEach を使用
StringEach e = new StringEach("Groovy!");
e.each({value -> 
	println(value)
});

// AcosEach を使用
AcosEach a = new AcosEach([0.1 , 0.2 , 0.5 , 0.7 , 0.8 , 1.0]);
a.each({value -> 
	println(Math.toDegrees(value))
});
 これを実行すると、次のような結果が得られます。
G
r
o
o
v
y
!
84.26082952273322
78.46304096718453
60.00000000000001
45.5729959991943
36.86989764584401
0.0

 ちなみに、クロージャは引数として渡す代わりにメソッドの最後につなげて書くこともできますし(この場合もメソッドのカッコはあってもなくても構わない)、Closureのobject.call()メソッド呼び出しはメソッド名を書かずに行うこともできるようです。Javaらしさは失われてしまいますが、文法は覚えておくに越したことはありません。上記の規則に従い、先のStringEachを「スクリプトらしく」書き換えるとこうなります。
public class StringEach{
	private String str;
	public StringEach(String str){
		this.str = str;
	}
	// yield args または yield(args) とすると
	// 自動的に yield.call(args) が呼ばれる
	// なお、Closure の変数名を yield としたのは
	// Ruby などに似せるためで、実際は好きな名前で構わない
	public void each(Closure yield){
		for(int i = 0; i < str.length(); i++){
			yield str.substring(i , i + 1);
		}
	}
}

StringEach e = new StringEach("Java");
// メソッドの最後に{}ブロックをつなげればクロージャとなる
// メソッドのカッコは書いても書かなくても構わない
e.each{value -> 
	println(value)
};
 なお、クロージャは自身のインスタンスに依存した変数も使うことができます。例えば、クロージャ内で自クラスのインスタンス変数やメソッドを使用し、そのクロージャを戻り値としてクラス外へと返すことも可能です。内部クラスのようなものと考えれば分かりやすいでしょうか。
public class DependClosure{
	def int first;
	public Closure timesClosure(){
		// このメソッドは以下のクロージャをクラス外部に渡すものだが
		// 自分のインスタンスに依存するメソッド times を使っている
		// そのメソッドではインスタンス変数 first を使っている
		return {times(it)};
	}
	public int times(int second){
		return first * second;
	}
}

DependClosure dc = new DependClosure(first:4);
Closure times = dc.timesClosure();
println(times.call(5));
 単純なクロージャを返すばかりか、Pythonのラムダと似たようなことさえ可能なのが分かります。
# Python のラムダ
def times(first):
    return lambda second : first * second

l = times(4)
print l(5)	# 20
 GroovyでSQLも書いてみましょう。GroovyによるSQLの特徴は、ResultSetをクロージャによって処理できてしまうところです。
import groovy.sql.*;

Sql sql = Sql.newInstance(
	"mysql:///yamicha?user=yamicha&password=password&" + 
	"useUnicode=true&characterEncoding=SJIS" , 
	"com.mysql.jdbc.Driver");

sql.executeUpdate(
	"CREATE TABLE groovy_test(number INT , name VARCHAR(32) , " + 
	"PRIMARY KEY(number))");

[
	["number":1 , "name":"Java"] , 
	["number":2 , "name":"Groovy"] , 
	["number":3 , "name":"JRuby"] , 
	["number":4 , "name":"Jython"] , 
	["number":5 , "name":"Rhino"]
].each({map -> 
	sql.executeUpdate("INSERT INTO groovy_test VALUES(? , ?)" , 
		[map["number"] , map["name"]]);
});

sql.commit();

sql.eachRow("SELECT number , name FROM groovy_test" , {row -> 
	println(row[0] + "\t" + row[1]);
});

sql.close();
 クロージャで非常に簡単に書いていますが、しっかり動きます。これを実行すると次のような結果が得られます。
1	Java
2	Groovy
3	JRuby
4	Jython
5	Rhino

 それから、Groovyでは関数ポインタのようなものが使用できます。引数がある場合は呼び出し時に引数を渡すことができ、インスタンスに依存したメソッドを呼ぶこともできます。
public class MethodPointer{
	def int first;
	public int times(int second){
		return first * second;
	}
}

MethodPointer mp = new MethodPointer(first:8);
pointer = mp.&times;

println(pointer(6));
 スクリプト言語はコンパイル言語よりも堅牢さが低く、Groovyは一応通常のJavaクラスも作れるとはいえ、勝手にインタフェースをインプリメントするなど制約もあるため、テスト以外の用途で使用することがあるかは分かりませんが、小回りが効く辺りは使いやすそうです。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

短命語大賞
2007/12/03(Mon)22:41:08
 金融庁、電子マネーの消費者保護法制を検討。SUICAなど様々な電子マネーが実際に使われる中で、現状では電子マネーの消費者保護がおざなりになっており、法が後手に回ってしまっているため、規制強化を図る模様です。一方、電子マネーの換金を解禁することも検討するようです。
 電子マネーの危険性については以前に述べた通りです。消費者を保護する規定に乏しく、しかも規制が甘いため、まともな電子マネーであっても倒産時などの消費者保護が期待できない上、詐欺の道具として用いられる恐れもあります。したがって、こうした状況を改善するために規制強化を行うことは当然であり、一刻も早く実効性のある規制を打ち出すべきでしょう。
 まず定めるべきは、電子マネーの払戻余力の確保を義務付けることです。今のところ、電子マネーは「前払式証票の規制等に関する法律」という法律によって規制されているらしく、同法の13条1項には次のように記載されています。

第十三条
 自家型発行者等は、基準日において、その発行した前払式証票の基準日未使用残高(次条第一項の権利の実行の手続が終了した日以後の基準日にあっては、同条第二項の公示に係る前払式証票がないものとみなして第二条第二項の規定により算出した額。以下この項及び第六項において同じ。)が届出基準額を超える額で政令で定める額を超えるときは、当該基準日未使用残高の二分の一以上の額に相当する額の発行保証金を当該基準日の翌日から二月以内に主たる営業所又は事務所の最寄りの供託所に供託しなければならない。

 すなわち、「届出基準額を超える額で政令で定める額を超えるとき」は「未使用残高の二分の一以上の額に相当する額」を保持しておかなければならないことになります。それでは「政令で定める額」がいくらかといいますと、「前払式証票の規制等に関する法律施行令」の8条では「千万円」とされています。供託額や供託を義務付ける下限金額が適切かどうかも含め、こうした規定を電子マネーに合致したものに改めることは当然です。
 また、電子マネーならではの状況に対処することも忘れてはいけません。電子マネーはいわば電子化された貨幣なのですが、この手軽さや分かりづらさが時にトラブルを招きます。例えば、ICカードの中にはかざすだけで処理が行えるものもありますが、バスなどでこれが知らぬ間に処理されてしまい、使ってもいないのに金額が引き落とされてしまうことがあるようです。これは現金であればまず発生しない問題です。
 電子マネーのどこまでが法規制の対象であり、どこまで財物と考えるかという点も問題です。何者かがICカードを不正利用したら、これは窃盗でしょうか。これは窃盗であると考えて異論はないにしても、それでは現金で購入したゲーム内などの仮想通貨が盗まれた場合、これは窃盗でしょうか。ゲーム内通貨は保護対象にならないとするなら、仮にこの通貨と何らかの物品を交換できるとしても、やはり保護の対象にはならないのでしょうか。このように、電子マネーは定義から保護の方法まで難問が山積みであることが分かります。
 しかし、こうした問題のすべてに対して適当な答えを示すことは難しいとしても、電子マネーを詐欺の媒体とする道をふさいだり、現行では不十分な消費者保護を強化することには意義がありますので、素早い法改正が望まれる点に変わりはありません。
 ただ、現状では「電子マネーの換金」には賛成しかねます。換金を可能にするのであれば、十分な規制が必要です。電子マネーは出所が分かりづらく、しかも名義もはっきりしないため、もし大した規制もなく解禁しようものなら、詐欺やマネーロンダリングの道具として使われる可能性が高いのです。詐欺師がこれを利用すれば調査も摘発も困難になり、暴力団の資金源になる恐れすらあります。
 電子マネーの功罪すら未だにはっきりしていない以上、消費者保護のための規制強化は十分に検討されるべきですが、規制緩和には慎重になる必要があります。

 そして今度は、電子マネーを不当に取得した5人が逮捕されました。何でも、本来「1000円」のはずのデータを「1円」に改ざんしたところ、1000ポイント分の電子マネーが1円で購入できてしまったそうです。このシステムは現在では修正され、同様の行為はできなくなっています。
 手元の記事だけでは詳しいことは分かりませんが、これがもし単純なフォームデータの改ざんによる詐欺であるとするなら、明らかに購入システム開発者の怠慢です。オンラインショッピングや電子マネーが抱える問題の1つが、こうしたシステムの欠陥を利用した不正行為であり、仮想ショップが持つ負の面の1つとなっています。
 Web開発者の間では、「ユーザーが送ってきたデータは信用しない」ことは常識です。これはオンラインショッピングシステムにも掲示板プログラムにも通じる常識であり、改ざんされると困るデータは最初からやり取りしないか、正当性のチェックを行ってから使用するようにします。もしそれを怠れば、フォームデータのねつ造はごく簡単であり、その気になれば誰でも詐欺を行えてしまいます。
 インターネットを利用する人の多くは、おそらく1度は掲示板やチャットを利用したことがあるはずですが、例えばチャットで何らかの発言を行うと、「name=名前&message=発言内容」といったデータがサーバーに送信され、サーバー側でそのデータが処理されます。その結果、チャットに発言が書き込まれ、発言後のチャットデータがブラウザに表示されるのです。
 オンラインショッピングも原理は同じであり、購入したい商品のデータを送ると、サーバー側で商品購入の処理がなされ、結果が返ってきます。この際には購入する商品番号やユーザーの会員番号などを送信するわけですが、「ユーザーが送ってきたデータは信用しない」ことをわきまえている開発者であれば、価格などを送信させることは絶対にありません。例えば「user=会員番号&id=商品番号&price=価格」のようなデータをユーザーに送信させようものなら、悪意のある人間が「price」の値を変更してしまわないとも限らないためです。
 したがって、Web開発の常識を知る開発者であれば「price」などというデータは受け取らず、ユーザーから受け取った商品番号を使用し、商品データベースから価格を取得することによって価格を求めます。もしユーザーが商品番号を改ざんしたとしても、別の商品を購入するように処理されるか、さもなくば「商品が見つかりません」とエラーを出すだけですので、改ざんによる被害は生じません。また、会員番号が改ざんされる可能性もありますので、会員番号の他にパスワードも送信させることにより、パスワードが合致していない場合はエラーを出すなどの方法も用います。
 これは「Web開発者の常識」であるため、これを怠って詐欺にあうのは開発者にも非がありますが、ぞんざいな法制は欠陥のあるシステムと同様です。電子マネーに関する法整備をいい加減なものにしてはいけません。

 毎年恒例の流行語大賞。実際に流行している言葉であるかはともかく、世相を表したものであることは事実です。といいますのは、昔の流行語に比べて最近の流行語は政治や世相を表すものが少なく、あっても単純であり、1年もすればいなくなっているような芸人がバカの1つ覚えのように連呼した言葉であったり、その年の有名人になった人にまつわるだけの言葉が採用される傾向が強いのです。実際、「ハニカミ王子」や「大食い」などという言葉を今年の日常で頻繁に使用した人がどれほど存在するのでしょうか
 それでは今年のユーキャン及び自由国民社自称・流行語大賞を。上の2つは年間大賞です。

・(宮崎を)どげんかせんといかん
 同様の方言を用いる地方の方は除いて、誰かこの言葉を日常で使用した方は存在するのでしょうか。「がばい」といい、「人気となった方言をしゃべればウケる、使えば売れる」という傾向は大変嘆かわしい限りです。方言に惑わされる前に本質を見るべきです。
 東国原氏が鳥インフルエンザ問題を終息させた手腕は評価します。しかし、用いた方言を流行語にしたところで何かが変わるわけでもありません。宮崎やその他の地方の改革が、「流行語」のような一過性のものに終わらないことを強く望みます

・ハニカミ王子
 まさに日本のレベル低下を象徴するような流行語です。ハンカチ王子の次はハニカミ王子ですか。こればかりは本気であきれ果てました。何が面白くて王子などと名づけるのでしょう。下手するとゴルフに対する侮辱ではないでしょうか。

・(消えた)年金
 いまさらの感が強いです。社会保険庁はずっと昔から使い込みといい加減な業務をしていたのですから。

・そんなの関係ねぇ
 毎日新聞に「日本のスイッチ」というコーナーがありまして、ここで数週間ほど前に「そんなの関係ないという言葉」についてアンケートがありました。「そんなの関係ねぇ」という言葉が流行している(らしい)ということをここで初めて知りました。「Your not own business!」「欧米か!」とやっている間に、これを言い出した芸人連中の姿も見なくなることでしょう。ちなみに「欧米か!」も初めて見た時は意味が分からず、どうやら芸人が言い出したらしいことが最近になってようやく分かりました。

・どんだけぇ〜
 これがどんだけ流行語にふさわしいのか、私はそれが疑問です。これは確か流行語大賞のサイトの「ノミネート語一覧」で知った言葉です。

・鈍感力
 KY(かき集め、寄せ集め)内閣の安部氏が勘違いして実践し、結局自滅した合言葉。国民のためにもならないような強行採決ラッシュを行う人間は「鈍感」ではなく「愚者」です。官や利権団体、利権企業の声には鈍感に、国民の声には敏感に対応する指導者の登場を求む。

・食品偽装
 流行語かは不明ですが、流行した行為です。賞味期限が偽装されている可能性があるのなら、せめて消費者が賞味期限を遵守するのは自己防衛といいましょうか。

・ネットカフェ難民
 流行語にする前に、政府の怠慢を責めるべきです。すべては無用な規制緩和のもたらした結果であり、派遣規制を中心に規制を戻すのは当然です。

・大食い
 それで、この言葉を実際に使用した人、あるいはこの言葉が流行したがために実践した人は存在するのでしょうか。

・猛暑日
 流行語かはともかく、深刻な言葉です。35度以上の日々が平気で何日も訪れるのは異常です。

 それではこちらも毎年恒例、当サイトの考える流行語大賞2007と参ります。

・原油及びその精製物・関連物(石油、ガソリン、灯油など)
 これぞまさに流行語でしょう。今年中「そんなの関係ねぇ」と言わなかった人は多くても、石油やガソリン、灯油などと言わなかった人はまれでしょう。多くの人はこの言葉を例年より多く使っているはずです。

・ねじれ国会
 これもまた流行語にふさわしい言葉でしょう。少なくとも「どんだけぇ〜」より多く使われたのではないでしょうか。参院を野党が握れば「参院選で野党勝利のねじれ国会」、その後に国会が始まれば「ねじれ国会スタート」、大連立の話が出たのは「ねじれ国会では与党が動けないから」、これが破談になって小沢氏が批判を浴びた時も「ねじれ国会の中で民主党の案を通すには大連立しかないと考えた」という具合に、繰り返し用いられた言葉です。

・家庭だんらん法案
 分かりやすい日本語で言えば「無賃残業合法化法案」。なぜかマスコミがほとんど報道しなかったため、世間の流行語ではないかもしれません。

・学力テスト
 数々の批判を押し切って導入した上、結果発表も遅れて意味不明なまま終わったものと、足立区で不正の媒体となったものの両方を表す言葉です。結論から言えば「無駄」です。ネタとしては面白かったのですが(シークェルのセットメニュー)、決して少なくない国費を使ってネタを提供していただきましても。

・(事前警告型)買収防衛策
 ブルドックの発動が裁判で認められたため、日本での買収防衛策発動は必ずしも違法でないことが分かり、様々な企業が導入したようです。

・身分犯の共犯
 刑法の「共犯」参照のこと。「僕はパパを殺すことに決めた」の著者に適用が検討されましたが、証拠不十分かマスコミのキャンペーンかは知りませんが、起訴は見送られました。その後、守屋前次官の妻が収賄罪(本来なら公務員にのみ適用)で逮捕されました。

 「政治家の不正」やら「いじめ」やらは毎年ノミネートされてもおかしくありませんが、毎年の流行語になってしまうのでやめておきます。

 PythonでCGI。PythonにはCGIを扱うための標準ライブラリが組み込まれており、導入した瞬間からCGIプログラムを組むことができます。
 CGIを処理するためには、最初にcgiライブラリをインポートする必要があります。これは単に「import cgi」と書くだけなのですが、ドキュメント曰く「from cgi import *」と書くべきではないようです。ライブラリ中で大量の名称を使用しており、これらすべてをインポートするのは適当でないという理由によります。
 また、PythonにはCGIのデバッグに役立つライブラリが標準で付属しています。デバッグ中は有効にしておいて、実際に使用する際には削除またはコメントアウトするようにすれば、通常より効率よくプログラムが組めそうです。
# CGI ライブラリのインポート
import cgi

# デバッグを有効にする
# デバッグが不要なら下の2行は不要
import cgitb
cgitb.enable()
 フォームデータは次のようにして読み取ることができます。
form = cgi.FieldStorage()
data = form.getvalue("form_name")
 ただし、getvalue()によって得られる値は同じ名前のデータが1つしかなければ文字列、複数あれば配列です。ユーザーから送られてきたフォームデータは信用できないため、どちらが送られてきても適切に処理できるようプログラムを組まなければなりません。ドキュメントでは次のようなサンプルが例示されています。
item = form.getvalue("item")
if isinstance(item, list):
    # The user is requesting more than one item.
else:
    # The user is requesting only one item.
 いちいちisinstanceでリストかどうかを判別して使用しています。しかし、これでは大変非効率的ですので、もっと容易な方法を用いたいところです。
 そのために役立つのがgetfirst()とgetlist()メソッドです。getfirst()は配列の最初のデータを返すものであり、データが1つしかなければ必ずそのデータを得られるため、1つしか送信しないことを想定しているデータに対して有効です。getlist()はデータが1つであっても配列に格納してデータを返すため、同じ名前のデータが複数送られてくる場合に便利です。はっきり言ってgetvalue()を使う場面はほとんどないでしょう。
 getfirst()は2つの引数を取ることができ、もし1つ目の引数で指定した名前のデータがなければ2つ目の引数のデータを返します。2つ目の引数を省略した場合、指定した名前のデータがなければNoneを返します。Perlでは未定義値を空文字列として扱うことができましたが、Pythonでは下手するとエラーとなってしまいますので、空文字列として扱いたい場合は2つ目の引数に空文字列を渡しておくと良いでしょう。
form = cgi.FieldStorage()
data = form.getfirst("form_name" , "")
 getlist()に2つ目の引数はありませんが、指定した名前のデータが存在しなくてもNoneではなく空の配列を返してくれるため、何のチェックもなしにfor文の対象にすることができます。
 PythonでCGIを組む際の注意点はせいぜいこの程度であり、後は普通にPythonコードを書くだけでCGIを組むことができます。完全オブジェクト指向のRubyよりも敷居が低いため、わりあい簡単に組めるのではないでしょうか。個人的にはオブジェクト指向モデルも好きではありますが(Rubyのモデルはともかく)。
 さて、今回せっかくPythonでCGIを書くのですから、ぜひともPythonからデータベースを使ってみたいところです。そこで「MySQL-Python」をダウンロードしてきました。Win32用インストーラを使えば、簡単にインストールができて便利です。首尾よく導入できたら早速使ってみましょう。
import MySQLdb
 これでMySQLに接続する準備が整いました。後は実際に接続し、任意のクエリを打ってみるだけです。
c = MySQLdb.connect(user = "yamicha" , 
	passwd = "password" , db = "yamicha" , 
	use_unicode=False , charset="sjis")

cursor = c.cursor()
cursor.execute("SQL QUERY")
c.commit()
 このライブラリはPython Database API 2.0準拠とのことですから、どうやらダック・タイピング型の移植性を持っているようです。どうやら標準でオートコミットはされないらしいため、データを変更する際はしっかりコミットするようにしましょう。
 SELECT文などデータが返る文を打った場合には、カーソルからデータを取得することができます。
cursor.execute("SELECT ...")
datas = cursor.fetchone()
 fetchone()の返り値はタプルであり、上の場合は「datas[0]」「datas[1]」のように内容を取得します。取得できるデータがなくなるとNoneを返します。したがって、Noneを返すまでループを続けることで、データをすべて取得することができます。
while True:
	datas = cursor.fetchone()
	if datas == None:
		break

	# 何らかの処理
 C/C++/Javaの経験がある人なら、次のようなコードを書きそうですが、
while (datas = cursor.fetchone()) != None:
	# 何らかの処理
 残念ながら動作しませんでした。
 これを踏まえて作成したのが以下の簡易SQLブラウザです。1行目のPythonのパスは使用する環境に合わせてください。
#!/usr/python/python
# -*- coding: Shift_JIS -*-

import cgi
import MySQLdb

form = cgi.FieldStorage()

print """
<html>
<head>
<title>Python SQL</title>
</head>
<body bgcolor="#FFFFFF" , text="#000000">

<b>Python SQL</b>
"""

query = form.getfirst("query" , "")

print """
<form method="POST">
<textarea name="query" cols="75" rows="6">
%(query)s</textarea><br />
<input type="submit" value="クエリの送信" />
</form>
""" % {"query" : query}

if query != "":
 try:
  c = MySQLdb.connect(user = "yamicha" , 
   passwd = "password" , db = "yamicha" , 
   use_unicode=False , charset="sjis")

  try:
   cursor = c.cursor()
   try:
    cursor.execute(query)
    c.commit()

    print "<table border=\"1\"><tr>"

    cols = cursor.description
    if cols != None:
     for col in cols:
      print "<td bgcolor=\"#CCDDFF\">" + col[0] + "</td>"

    print "</tr>"

    while True:
     datas = cursor.fetchone()
     if datas == None:
      break

     print "<tr>"
     for data in datas:
      print "<td>" + str(data) + "</td>"
     print "</tr>"

    print "</table>"
   except StandardError , e:
    print e
  except StandardError , e:
   pass
  finally:
   try:
    c.close()
   except StandardError , e:
    pass
 except StandardError , e:
  pass

print """
<hr />
<div align="center">
<small>Python SQL - yamicha.com</small>
</div>
</body>
</html>
"""
 しかし、上記のコードはSQLのテストとしては十分ですが、CGIの例としては十分ではありません。そこで作成したのが以下の簡易チャットです。Pythonは基本的に構文が簡単であるため、覚えて数日もすればこの程度のコードを書けるようになります。
 これを動作させるには、このCGIを置いたコードと同じディレクトリに空ファイル「pythonchat.log」と空ディレクトリ「lock」が必要です。パーミッションが存在するOSであれば、それぞれ666と777を割り当てます。
#!/usr/python/python
# -*- coding: Shift_JIS -*-

import os
import time
import cgi

# 設定
title = "Python Chat"
bgcolor = "#FFFFFF"
text = "#000000"
link = "#0000FF"
alink = "#FF0000"
vlink = "#0000FF"

max_log = 50
log_file = "pythonchat.log"
lock_dir = "lock"

header_printed = False

def loginform():
	print """
<b>Python Chat</b><small> - Login</small>

<form method="POST">
名前<input type="text" name="name" size="20" /><br />
発言<input type="text" name="message" size="50" /><br />
<input type="hidden" name="mode" value="login" />
<input type="submit" value="入室">
</form>
"""

def chatform():
	print """
<b>Python Chat</b>

<form method="POST">
%(name)s : <input type="text" name="message" size="70" />
<input type="submit" value="発言/更新">
<input type="hidden" name="mode" value="write" />
<input type="hidden" name="name" value="%(name)s" />
<input type="hidden" name="mode" value="form" />
</form>

<form method="POST">
<input type="hidden" name="name" value="%(name)s" />
<input type="hidden" name="mode" value="logout" />
<input type="submit" value="退室" />
</form>
""" % {"name" : form.getfirst("name" , "")}

def login():
	name = striptags(form.getfirst("name" , ""))
	message = striptags(form.getfirst("message" , ""))

	if name == "":
		errmsg("名前を入力してください。")

	message += "(入室)"
	date = str(time.time())
	ip = os.environ["REMOTE_ADDR"]

	logwrite([name , message , date , ip])

def write():
	name = striptags(form.getfirst("name" , ""))
	message = striptags(form.getfirst("message" , ""))

	if name == "":
		errmsg("名前が存在しません。")
	if message == "":
		return	# リロードとみなして書き込まない

	date = str(time.time())
	ip = os.environ["REMOTE_ADDR"]

	logwrite([name , message , date , ip])

def logout():
	name = striptags(form.getfirst("name" , ""))
	message = striptags(form.getfirst("message" , ""))

	if name == "":
		errmsg("名前が存在しません。")

	message += "(退室)"
	date = str(time.time())
	ip = os.environ["REMOTE_ADDR"]

	logwrite([name , message , date , ip])

def logwrite(log):
	lock_begin(lock_dir , "pythonchat")

	logs = readlog()
	logs.insert(0 , log)

	while len(logs) > max_log:
		logs.pop()

	writelog(logs)

	lock_free(lock_dir , "pythonchat")

def striptags(str):
	return cgi.escape(str).replace("\n" , "").replace("\r" , "")

def log():
	lock_begin(lock_dir , "pythonchat")
	logs = readlog()
	lock_free(lock_dir , "pythonchat")

	for log in logs:
		print "<hr />"

		date = time.strftime("%Y/%m/%d %H:%M:%S" , 
			time.localtime(float(log[2])))
		print "<b>" + log[0] + "</b>: " + log[1] + 
			"<small> - " + date + "</small>"

def readlog():
	try:
		f = open(log_file , "r")
	except:
		errmsg("ファイル " + log_file + " が見つかりません。")

	filedata = f.read()
	f.close()

	if filedata == "":
		return []

	logs = filedata.split("\n")

	data = []
	for log in logs:
		data.append(log.split("\t"))

	return data

def writelog(logs):
	list = []
	for log in logs:
		list.append("\t".join(log))

	data = "\n".join(list)

	try:
		f = open(log_file , "w")
	except:
		errmsg("ファイル " + log_file + " が見つかりません。")

	f.write(data)

	f.close()

def header():
	global header_printed
	if not header_printed:
		header_printed = True

		print "Content-type:text/html\n\n"
		print """
<html>
<head>
<title>%(title)s</title>
</head>
<body bgcolor="%(bgcolor)s" text="%(text)s" 
link="%(link)s" alink="%(alink)s" vlink="%(vlink)s">
""" % {"title" : title , "bgcolor" : bgcolor , "text" : text , 
		"link" : link , "alink" : alink , "vlink" : vlink}

def footer():
	print """
<hr />
<div align="center">
<small>Python Chat by <a href="http://www.yamicha.com/">yamicha.com</a></small>
</div>
</body>
</html>
"""

def errmsg(msg):
	header()
	print "<b>Error</b><br />"
	print msg
	footer()
	exit()

def lock_begin(dir , name , retry = 5 , wait = 1):
	lock = dir + "/" + name

	loop = 0
	while loop < retry:
		# ロックディレクトリを作成
		try:
			os.mkdir(lock)
			return
		except:
			pass

		# デッドロック(1分以上持続しているロック)は削除
		# 上記 mkdir の例外〜stat の間にディレクトリがなくなっていると
		# 例外を出すため、しっかりキャッチしておく
		try:
			status = os.stat(lock)
			if time.time() > status.st_mtime + 60:
				# lock_free の時点で ディレクトリが
				# 消えていることも考えられる
				# lock_free で例外を except すれば問題は出ない
				lock_free(dir , name)
		except:
			pass

		time.sleep(wait)
		loop += 1

	errmsg("ロックがビジー状態です。")

def lock_free(dir , name):
	lock = dir + "/" + name
	try:
		os.rmdir(lock)
	except:
		pass

# 関数呼び出し
form = cgi.FieldStorage()

mode = form.getfirst("mode" , "")
if mode == "":
	header()
	loginform()
	log()
	footer()

if mode == "login":
	header()
	login()
	chatform()
	log()
	footer()

if mode == "write":
	header()
	write()
	chatform()
	log()
	footer()

if mode == "logout":
	header()
	logout()
	loginform()
	log()
	footer()
 簡素なチャットですが、しっかり動作します。また、名前や本文にタグを使用しても、ログ書き込み時に無効化されます。
 コード自体はほとんど標準ライブラリの応用であり、これといった注意点はありません。mkdirなどは失敗時に例外を投げるため、try〜exceptをしっかり書く必要があります。なお、上記のコードに含まれる「os.environ["REMOTE_ADDR"]」を見ての通り、環境変数はos.environに辞書型として格納されていますので、CGIを作成するのであれば覚えておきましょう。
 後は日本でPythonをサポートするサーバーが多ければ、は禁句でしょうか。Perlは当然として、PHPとPython程度は使いたいです。
カテゴリ [開発魔法][社会問題][経済・知的財産] [トラックバック 0][コメント 0]

証人の関門
2007/11/30(Fri)01:11:25
 山田洋行問題で、かなりの独裁ぶりを発揮していたと伝えられる守屋夫妻が逮捕されました。事件の経緯はどうあれ、一昔前なら闇に葬られていた可能性すらある汚職事件でしっかり捜査が行われるようになったのは良いことです。守屋氏といえば、小池氏との間で起こした「ケンカ」でも名の知れた人ですが、この問題といい防衛族の利権のとりでは固いようです。
 ちなみに、収賄罪は公務員に対して適用されるものであり、氏の妻には本来適用されないものなのですが、「身分犯の共犯」の規定によって同罪を適用したようです。身分犯の共犯といえば、秘密漏示の共犯行為の末になぜか起訴が見送られたジャーナリストがいましたが、マスコミはこれをマスコミ関係者相手に適用することには強く反発するものの、次官の妻への適用はさまたげないようです。無論、どちらの事件も逮捕なり起訴なりに値することは言うまでもなく、今回の適用は評価できます。
 しかし、守屋氏らは逮捕となったものの、この問題の余波はしばらく続きそうです。それというのも、守屋氏は先に行われた証人喚問で「久間氏と額賀氏が宴席に同席していた」ことを証言し、しかも額賀氏に関しては「はっきり覚えている」というのです。証人喚問で虚偽の情報を述べれば偽証罪に問われますので、証言が事実である可能性は十分あります。
 ところが、久間氏は「あったかもしれない」と守屋氏の証言が事実である可能性を認めるも、額賀氏はこれを強く否定しています。そればかりか、写真を提示して「その時に宴席には出ていなかった」と述べるなど、「物的証拠」まで使って守屋氏の証言を否定しました。どちらが正しいかは未だにはっきりしませんが、ここまで発言が食い違っている以上、どちらかの主張が虚偽であることはまず間違いありません。
 ここで民主党は額賀氏の証人喚問を要求、参院での「強行採決」によって証人喚問を可決しました。与党はこれの取り消しを求めるも、民主党は拒否しているようです。ただ、額賀氏もそれなりの証拠を提示しており、守屋氏の証言が間違っている可能性もある以上、民主党内には「偽メール」の二の舞を危惧する声もあるようです。
 それでは、民主党はこのまま額賀氏の証人喚問を行うべきなのか。額賀氏参加の是非はどうあれ、私は証人喚問に賛成します。証人喚問の上での守屋氏の発言と、証人喚問ではない額賀氏の発言では、どうしても重さが異なるためです。以前にヒューザーの社長が証人喚問の席に立ったことがありましたが、喚問前は非常に威勢良く発言していたにもかかわらず、喚問の場では別人のように「訴追の恐れがありますので証言を控えます」を連発してひんしゅくを買いました。これなどはまさに、証人喚問での発言の重さ、逆に言えば喚問以外での発言の軽さを示す好例です。証人喚問も万能ではありませんが、少なくとも無意味ではありません。
 無論、額賀氏は実際には潔白であり、守屋氏が嘘をついていた、または記憶違いという可能性もあり得ます。しかし、その場合でも「偽メール」の二の舞にはなりませんし、してはいけません。守屋氏の発言中に額賀氏の名前が登場したため、その真偽を確かめるために発言に重みがある証人喚問の場で額賀氏の言い分を聞き、事件の全容を解明するというのがこの証人喚問の目指すところであり、額賀氏が潔白であるなら自らの言い分を堂々と主張すれば済むことです。証人喚問は問題の全容解明のためという目的も忘れ、「額賀氏が潔白なら民主党が悪く、そうでなければ自民党が悪い」などという意味不明な考え方をするのでもなければ、当然のことです。
 何はともあれ、とにかく汚職の全容解明を望みます。証人喚問はその手段であり、これに惑わされて問題がうやむやになってしまうようでは意味がありません。

 他の業界と比べて防衛利権が発生しやすい原因は「装備は特殊設備であるため、適正な相場が分かりづらい」「機密事項とされやすく、情報が隠ぺいされる」ことがあるようです。何らかの施設の建設にせよ、データ処理システムの発注にせよ、一応は相場というものがあるものですが、「高性能ランチャー」や「携帯用重火器」などと言われても、相場がなかなか分かりません。また、本来は日本に機密とすべき事項などほとんど存在しないはずなのですが、やはり利権のためか機密事項が多く、これも利権の温床となる恐れがあります。軍需とは少々違いますが、以前に機密費流用問題があったことは皆様ご存知でしょう。
 どうやらこのような例は珍しくないようで、「華氏911」にはブッシュ政権と軍需会社カーライルの癒着を指摘するシーンがありました。これが事実かはともかく、軍需に利権が絡みやすいのは事実のようです。民間に「軍隊会社」などがない以上、軍需はほぼすべて公によるものですし、色々と特殊な事情がある以上、他より利権が発生しやすいのは当然ではあります。さらに言えば、その防衛関連の事項は「スーツ組」などと揶揄されるごく一部の関係者が握っており、明らかに癒着が起きやすい状態です。しかも日本の軍事費は世界の中でも上位に位置し、利権のパイはかなり大きいようです。
 ついでに、以前に守屋氏と「痛み分け」となった小池氏、守屋氏について「女の直感でよろしくないと思った」とのこと。確かに守屋氏はよろしくありませんが、「女の直感」とやらを理由にクビやら更迭やら、果ては国の上層部でケンカやらが行われるのもかなり異常なのでは。冗談で言っているとしても、適当ではありません。私もカンはかなり利きますが、カンが理由の時こそ通常より検証を重んじます。
 しかし、このような利権作りは防衛省に限らずどこでもやっているのではないでしょうか。私のカンがそう告げています。

 開発といえばカン、カンといえば開発、嫌でもカンが洗練されてしまうのですが、言語によって使うべきカンが微妙に異なるのが困りものです。そんなこんなで、Pythonを始めました。
 Pythonとはニシキヘビのことなのですが、公式ドキュメント(の翻訳版)によると「これは爬虫類からではなく、英国のコメディ番組モンティ・パイソンから名づけられました」とのこと。そのくせ、Pythonのドキュメントのfaviconはニシキヘビです。
 この言語を「ピトゥーン」と発音するのではないかと考えたのは私だけでしょうか。由来の通り、これの読み方は「パイソン」です。「SQL」は「シークェル」ですし、「Java」は言語であれば「ジャバ」、地名であれば「ジャワ」といった具合に、読み方がややこしい言語はやたらと多いのです。ちなみに「Perl」はパールですが、真珠は「Pearl」です。
 ところで、モンティ・パイソンと聞いたところで、私はモンティ・ホールの問題を連想してしまいました(Wikipediaに記事があります)。言うまでもなく両者に関係はなく、当然ながらモンティ・ホールとPythonの間にも何の関係もありませんが、連想したついでに少々触れておきます。
 モンティ・ホールの問題といいますのは、次のような問題です。

 ここに3つの扉がある。ただし、そのうちの2つの扉はハズレであり、当たりは1つしかない。まず、回答者はそのうち1つを選択する。回答者が扉を選んだら、司会は「回答者が選んでいない扉のうちハズレの扉」を1つ開放する。回答者が選んでいない扉が2つともハズレであるなら、司会がどちらを開放するかはランダムに決定される。この後、回答者は1度だけ選択した扉を変更することができる。回答者は扉を変更すべきであるか。

 これが大まかな問題の概要です。さて、皆様答えはお分かりでしょうか。Wikipediaに答えは書いてありますが、読んでも釈然としない方も多いことでしょう。ここは実際に検証してみるべきでしょう。

 SQLモンティ・ホール編。空飛ぶモンティ・シークェル。

魔道士イリアス「突然だけど、サーラ」
騎士サーラ「何でしょうか」
魔道士イリアス「モンティ・ホールの問題って知ってる?」
騎士サーラ「本当に突然ですね・・・」
魔道士イリアス「それで、知ってる?」
騎士サーラ「存じております。確率論の問題ですね」
魔道士イリアス「あれって良く分からないんだけど、説明してもらえないかしら」
騎士サーラ「はい。ではまず・・・カードやコインはありませんか?」
魔道士イリアス「カード?タロットでいいかしら。シェリー、タロットはアル・・・」
イリスのシェリー「イリアスさん、これです」
魔道士イリアス「あっ、シェリー、どうして私が言ってる途中で割り込んでくるのよ!」
騎士サーラ「イリアスさん、タロットはアルカナ、などと言うのは結構ですが、3度目にもなると・・・」
魔道士イリアス「それで、これを一体何に使うのよ」
騎士サーラ「まずは適当に3枚取り出しまして・・・デビル、タワー、プリエステスですか。イリアスさん、この中でお好きなものを1枚選んでいただけますか?」
魔道士イリアス「サーラ、好きなのを選べなんてセリフは、もっとマシなカードがある時に言ってよ・・・。プリエステスしか選択肢がないわね」
騎士サーラ「分かりました。それでは、この3枚のカードを裏返しにしてシャッフルしまして・・・イリアスさん、どれかお好きなカードを1枚選んでください」
魔道士イリアス「じゃあ、この左端のカードね」
騎士サーラ「では私が、イリアスさんが選んだカード以外の2枚のカードから、ハズレのカードを1枚開きます。ハズレが2枚ある場合には、コインを投げてどちらを開くかを決定します」
魔道士イリアス「じゃ、コインを投げなかった場合には、ハズレが1枚しかないってことよね」
騎士サーラ「それでは問題が変わってしまいますので、そうはいきません。ハズレが1枚の場合でも形式だけコインを投げるか、あるいはコイン投げはイリアスさんに見えないところで行います」
魔道士イリアス「えーっ!?」
騎士サーラ「では、ハズレのカードとして右端をめくりましょう。・・・この通り、右端のカードはタワーです」
魔道士イリアス「残りはプリエステスとデビルね」
騎士サーラ「イリアスさん、ここで選択を1度だけ変更することができます。イリアスさんは現在、左端のカードを選択されていますが、これを中央のカードに変更できます。変更されますか?」
魔道士イリアス「えっ?そう言われると迷うわね・・・」
騎士サーラ「イリアスさん、実はこの場面では、カードを変更した方が当たる確率が上がるのです」
魔道士イリアス「ええっ!?どうしてそうなるのよ?」
騎士サーラ「まず、イリアスさんは左端のカードを選択されました。これで当たる確率は1/3です。残りの2枚のカードのいずれかに正解がある確率は2/3です。この時点ではどのカードを選んでも確率は1/3なのですが、私が残りのカードのうちハズレのものを開けました。これで残りのカードの正解率は2/3、残りカードは1枚ですから、このカードの正解率が2/3です。したがって、変更しない場合は1/3、した場合は2/3の確率で正解できます」
魔道士イリアス「あの、意味分からないんだけど・・・。もっと分かりやすい説明はないの?」
騎士サーラ「分かりやすい説明・・・ですか。イリアスさんに簡潔に理解していただくには、シークェルを使うのが最適でしょうか・・・」
魔道士イリアス「シークェルで?できるの?」
騎士サーラ「やってみましょう」

 一般人ならなおさら分からなくなりそうですが、そこはさすがに開発魔道士。シークェルで問題を解くことができるのでしょうか。

模範解答
 カードが全部で3つあり、回答者がそのうち1つを選択、続いて司会が回答者が選んでいないカードのうちハズレを1枚オープンし、ここでもう1度回答者がカードを選び直せるというこの問題。まずはカードとカードの場所を表すテーブルを作ります。
CREATE TABLE card(c INT , n VARCHAR(32));
CREATE TABLE pos(p INT);

INSERT INTO card VALUES(1 , 'Priestess') , (2 , 'Devil') , (3 , 'Tower');
INSERT INTO pos VALUES(1) , (2) , (3);
 cardがカードの種類、posが位置データです。さて、まずは単に「3枚のうち1枚を選んでオープン」した場合の正解率を考えます。正解がどこにあるかは分かりませんから、choiceを選んだカードの場所、answerを正解があるカードの場所としまして、
SELECT SUM(ELT(choice.p , p1.c , p2.c , p3.c) = 1) AS 'OK' , COUNT(*) AS 'ALL' 
FROM card p1 , card p2 , card p3 , pos choice 
WHERE p1.c != p2.c AND p1.c != p3.c AND p2.c != p3.c;

OK	ALL
6	18
 見ての通り、これは1/3の確率です。カードの並び順パターン及び回答者の選択パターンの組み合わせは18個あり、うち6パターンで選んだカードがプリエステスとなります。
 それではモンティ・ホールの問題の場合はどうでしょう。1度答えた後、自分が選んだカード以外からコイン投げでハズレのカードが選択され、その後にもう1度カードを選ぶかどうか選択するのがこの問題のルールです。ハズレが2枚であれば、コインの表と裏でそれぞれ違うカードがオープンされますが、ハズレが1枚なら表でも裏でもオープンされるカードは同じです。
CREATE TABLE coin(n INT);

INSERT INTO coin VALUES(1) , (2);

SELECT SUM(ELT(rechoice.p , p1.c , p2.c , p3.c) = 1 AND 
choice.p != rechoice.p) AS 'Change' , 
SUM(ELT(rechoice.p , p1.c , p2.c , p3.c) = 1 AND 
choice.p = rechoice.p) AS 'NoChange' 
FROM card p1 , card p2 , card p3 , 
pos choice , pos rechoice , pos front , pos behind , coin 
WHERE p1.c != p2.c AND p1.c != p3.c AND p2.c != p3.c AND 
front.p != choice.p AND ELT(front.p , p1.c , p2.c , p3.c) != 1 AND 
behind.p != choice.p AND ELT(behind.p , p1.c , p2.c , p3.c) != 1 AND 
(ELT(choice.p , p1.c , p2.c , p3.c) = 1) != (front.p = behind.p) AND 
front.p <= behind.p AND ELT(coin.n , front.p , behind.p) != rechoice.p;
 カラムchoiceが最初に選んだカード、rechoiceが最後に選んだカード、frontがコインが表の場合に開くカード、behindがコインが裏の場合に開くカードです。もし回答者が最初に正解のカードを選択した場合、ハズレが2枚ですからfrontとbehindで開くカードは異なりますが、ハズレのカードを選択した場合、frontでもbehindでも開くカードは同一です。なお、コインの表裏によって開くカードが異なる場合、裏は表より番号が大きい(番号を左端から数えているのであれば、より左端に近い)カードを開くルールとなっています。
 参考までに、内訳を出すクエリは次の通り(番号が小さいものを左端とします)。
SELECT ELT(choice.p , p1.n , p2.n , p3.n) AS '最初' , 
ELT(ELT(coin.n , front.p , behind.p) , p1.n , p2.n , p3.n) AS 'オープン' , 
ELT(rechoice.p , p1.n , p2.n , p3.n) AS '決定' , 
p1.n AS '左' , p2.n AS '中央' , p3.n AS '右' , 
ELT(coin.n , '表' , '裏') AS 'コイン'
FROM card p1 , card p2 , card p3 , 
pos choice , pos rechoice , pos front , pos behind , coin 
WHERE p1.c != p2.c AND p1.c != p3.c AND p2.c != p3.c AND 
front.p != choice.p AND ELT(front.p , p1.c , p2.c , p3.c) != 1 AND 
behind.p != choice.p AND ELT(behind.p , p1.c , p2.c , p3.c) != 1 AND 
(ELT(choice.p , p1.c , p2.c , p3.c) = 1) != (front.p = behind.p) AND 
front.p <= behind.p AND ELT(coin.n , front.p , behind.p) != rechoice.p;
 いずれにせよ、答えを変えた場合が24、変えなかった場合が12ですから、変えた方が確率が高いことが分かります。なお、内訳クエリで72行のセットが出るのを見ての通り、上記のクエリで得られる結果はハズレまで合わせれば72件であり、そのうち36件(司会がハズレを開いた後は2択となるため)が正解となります。

騎士サーラ「お分かりでしょうか」
魔道士イリアス「うーん・・・。こうして結果を示されると、そう考えるしかないわね」
騎士サーラ「クエリを色々変更して、レコードのデータやフォーマットなどを変えてみると、もう少し理解しやすいかもしれません」
魔道士イリアス「ところでサーラ、変更すると正解率が倍になるのよね?」
騎士サーラ「はい」
魔道士イリアス「じゃ、開くのを真ん中のカードに変更するわ」
騎士サーラ「分かりました。真ん中のカードですね・・・」
魔道士イリアス「ええっ!?デビル!?」
騎士サーラ「どうやら、左端のカードがプリエステスのようですね」
魔道士イリアス「どうしてそうなるのよ!」
騎士サーラ「イリアスさん、シュレーディンガーのシェリーです」

 このように、モンティ・ホールもSQLなのです。

 さて、Pythonについて。この言語の特徴は、他の言語では飾りに過ぎないインデントが構文上意味を持つ点です。以下にコードを示します。
i = 0
while i < 10:
	if i < 5:
		print "i < 5"
	else:
		print "i >= 5"
		i += 1
	i += 1
print "loop end"
 このコードはiが10になるまでループするのですが、iが5以上の時には1ループ毎にiへの加算を2度行っています。つまり、1度のループでiが2ずつ増えるようになっています。iが10以上となったらループから抜けてメッセージを表示します。
 上記のプログラムに明示的なスコープの終了はありませんが、どこからどこまでがスコープであるかは分かります。これがPythonの流儀です。C/C++、Javaなどではインデントを使って読みやすいコードを書くのが慣習かつ常識ではあるものの、場合によっては慣習を無視したコードを書くことができますが、Pythonでそのようなコードは許されません。特定のスコープ内の構文はすべて同数のスペースかタブでインデントしなければなりません。また、インデントを開始する構文は「:」で終わります。
 例外として、1行だけの記述であれば、「:」の後に続けて書くことでインデントを省略することができます。if文などでは、この構文を並べて書くこともできます。
if i < 10: print "i < 10"
elif i < 20: print "i < 20"
else: print "other"
 見ての通り、Pythonの「ここまでのifには当てはまらず、なおかつ指定した条件に当てはまる場合」の構文はelifです。言語をあれこれ使っていると、else if、elsif、elifの差だけでも頭が混乱してきます。
 それでは言語の使い方を。Perlなどと違い、Pythonではいきなり日本語コードが含まれるプログラムを書くことはできません。日本語を使うには、コードの1行目か2行目で宣言を行わなければなりません。
# -*- coding: Shift_JIS -*-
 当然のことながら、Shift_JIS以外のコードでも構いません。2行目に書くのが許容されているのは、CGIではPythonのパス(#!/usr/...)を先頭に書かなければならないためでしょう。
 この宣言さえしてしまえば、後は自由にプログラムを書くことができます。まずはプログラムを組む上で基本となる関数宣言の方法から。
# 宣言の方法
def func(arg):
	print arg

# 使い方
func("引数")
 Pythonは関数でもクラスでもインデントを使って記述します。
 引数は順番に並べて書く他に、引数名を指定して値を渡すこともできます。
def func(arg):
	print arg

func(arg="文字列")
 デフォルト引数も使用できます。
def func(arg = "default"):
	print arg

func()
 returnで値を返せるのはその他一般の言語と同じです。
 Pythonで既存のライブラリを使用する構文にはimportがあり、これはPerlのuseやrequire、PHPのinclude_onceに似ているのですが、Pythonのimport文にはimportで指定した名前が名前空間のように扱われるという特徴があります。import文で指定する名前はファイル名から.pyを除いたものですから、ライブラリに属する関数は「ファイル名.関数名」のように呼び出すことになります。
 例えば、Pythonでファイルやディレクトリ操作などを行うライブラリに「os」というものが存在しますが、これは次のように使います。
import os

os.mkdir("name")
 いちいちこのような構文で参照するのが面倒であれば、関数名などをそのまま取り込んでしまうこともできます。
# 通常の書き方
import time
print time.strftime("%Y/%m/%d %H:%M:%S" , time.localtime(1196350000))

# time. を省略する書き方
from time import localtime , strftime
print strftime("%Y/%m/%d %H:%M:%S" , localtime(1196350000))
 また、「from time import *」ですべての定義を取り込むこともできます。
 Pythonはイテレータをサポートしており、Rubyのブロック付きメソッド呼び出しとほぼ同じことができます。for文はイテレータ実装クラス及び配列に対して実行できます(イテレータ実装クラスについては後述)。
datas = [10 , 20 , 30]

for data in datas:
	print data
 Pythonの配列は基本的に[]で記述しますが、{}の構文でハッシュ(Pythonでは「辞書」と呼ばれる)を記述することができるほか、()で「タプル」と呼ばれるリストを構築することができます。
print [10 , 20 , 30]
print {"a" : 10 , "b" : 20}
print (10 , 20 , 30)

# 要素が1つのタプルを次の記述で構築すると
# 普通のカッコとみなされてしまって失敗する
print (10)

# 代わりにこのように記述すること
print (10 , )
 ハッシュ(辞書)は宣言こそ{}で行いますが、参照は[]で行います。
a = [10 , 20]
print a[1]

h = {"a" : 10}
print h["a"]

t = (10 , 20)
print t[1]
 通常の配列とハッシュ(辞書)についてはこれ以上の説明は不要でしょう。タプルは一言で言えば「変更不可能なリスト」です。タプルの要素は配列と同じく添え字を使って参照できるのですが、書き込むことはできません。
 それが何の役に立つのかといいますと、どうやらタプルは配列というより名前のない構造体に近いものとされているようです。これは通常の配列を使っても同じではありますが、タプルを関数の返り値とすれば複数の値を返せます。また、ハッシュ(辞書)配列のキーにできる点もポイントです。
h = {("a" , "b") : 10}
print h[("a" , "b")]
 通常の配列をキーにすることはできません。次のような場合に困るからとのことです。
array = ["a" , "b"]
hash = {a : 10}	# 実際にはここでエラー
array[0] = "b"

print hash[array]
print hash[["a" , "b"]]
 hashの中身が表示される時点では、arrayの内容は「["b" , "b"]」になっています。ところが、キーとして登録した際のarrayは「["a" , "b"]」でした。この場合、「hash[array]」でデータを取得するのか、「hash[["a" , "b"]]」でデータを取得するのかがあいまいです。したがって、変更不可能なタプルにのみこれが認められています。
 Pythonは例外機構も持っています。例外はraiseで投げ、try〜except〜else〜finallyで処理します。
try:
	print open("dummy.error")
except IOError , (no , str):
	print "例外" + str
finally:
	print "例外を投げても投げなくても実行"
 exceptは複数書くこともでき、型を省略するとすべての例外がキャッチされます。また、1つのexceptで複数の型の例外を受け取れます。
try:
	print open("dummy.error")
except (IOError , Exception):
	print "例外"
except StopIteration:
	pass
finally:
	print "例外を投げても投げなくても実行"

# どうでも良いですが、pass は何も行わない構文です
# C のセミコロンだけの行と同じです
# for(int i = 0; i < 10000; i++)
# 	;	# pass と同じ
# StopIteration はイテレータで使うもので、エラーではありませんが、
# 一応例外という扱いになっています
 例外を送出するraise文にはいくつかの書き方があります。自作例外クラスを使うこともできます。raiseの1つ目の引数には例外のクラス、2つ目以降には例外の引数を記述します。
try:
	raise Exception , ("例外の" , "タプル")
except Exception , data:
	print data[0] + data[1]
 例外クラスのインスタンスを渡す場合は次のようにします。
# 省略形(自動的にインスタンスの型が例外の型とみなされる)
try:
	raise Exception("例外")
except Exception , data:
	print data[0]

# 型を明示した書き方(インスタンスの型と無関係なものは使えない)
try:
	raise Exception , Exception("例外")
except Exception , data:
	print data[0]
 さて、それではクラスと参りましょう。Pythonは一応オブジェクト指向言語であるらしく、オブジェクト指向が使えます。そのモデルはPerlに良く似ており、インスタンスメソッド(いわゆるメンバ関数)の第一引数には自分自身が渡され、第二引数以降がその関数本来の引数になります。PythonはPerlと違って引数を宣言しなければならないため、インスタンスメソッドの1つ目の引数は必ず自分自身を格納する変数となります。これはそのメソッドが引数を取らない場合であっても同じです。
 Pythonの継承モデルは多重継承であり、クラス名の後にカッコでくくって指定します。すべてのメソッドはC++のvirtualと同等で、自動的に継承されます。また、すべての変数はpublicであり、外部からアクセスすることができますが、変数名を「__var」とすることで、この変数は自動的に「_ClassName__var」という名前に変換され、外部からのアクセスや変数名の競合をある程度避けることができます。
 コンストラクタは__init__という名前のメソッドとして宣言します。
class Base:
	def __init__(self , str):
		self.__str = str
	def method(self):
		print self.__str

class Child(Base):
	def __init__(self , str):
		Base.__init__(self , str)
	def method(self):
		print "override"
		Base.method(self)

instance = Child("str")
instance.method()
 1つ目の引数の名前がselfである必要はありませんが、慣習でselfとされています。
 子クラスのメソッドからオーバーライドで隠ぺいされた親クラスのメソッドを呼び出すには、「ClassName.MethodName(self , args...)」の構文を使用します。第一引数にselfを渡す構文で呼び出しているのが少々気持ち悪いですが、他にやり方がないため仕方ありません。自分自身の他のメソッドなど、隠ぺいされていないメソッドを呼び出すのであれば、「self.method()」の構文が使えます。
 インスタンスの生成は「ClassName(args...)」という記述で行います。Javaの構文(new ClassName(args...))から先頭のnewを取り外すだけです。これで自動的に__init()__がコールされ、初期化がなされます。言うまでもありませんが、ここで指定した引数は__init()__に渡されます。コンストラクタに引数を使わない場合でも、__init()__は第一引数として必ずselfを取らなければならない点に注意しましょう。
 残るはイテレータです。PythonでサポートされているイテレータはほとんどJavaのIteratorと同じです。クラスをイテレータ対応にするには、__iter()__メソッドを実装しなければなりません。__iter()__メソッドからはnext()メソッドを実装したクラスを返す必要があります。
 next()メソッドではイテレート処理する値を順番に返し、返す要素がなくなったらStopIteration例外を送出します。
# イテレータに対応したインスタンス
class IterList:
	def __init__(self , list):
		self.list = list
	def __iter__(self):
		return IterData(self.list)

# イテレータの実装
class IterData:
	def __init__(self , list):
		self.list = list
		self.index = 0
	def next(self):
		if len(self.list) > self.index:
			data = self.list[self.index]
			self.index += 1
			return data
		else:
			raise StopIteration

# リストの内容を順番に取得するイテレータ
list = IterList([4 , 8 , 16 , 32 , 64 , 128])
for e in list:
	print e
 その他、Pythonは「ジェネレータ」と呼ばれる構文にも対応しています。これはイテレータを手軽に実装するためのもので、Rubyのyieldに似ています。ジェネレータでは__iter()__もnext()も実装する必要がなく、任意のメソッドをイテレータとして用いることができます(こちらはクラスのメソッドである必要はなく、通常の関数としても書けます)。
 関数内でyieldを実行するたびにその値を送出し、メソッド・関数を抜けた時点でイテレーションが終了します。
class YieldList:
	def __init__(self , list):
		self.list = list
	def gen(self):
		sum = 0
		for i in self.list:
			sum += i
			yield sum

# リストの内容を次々と加算したものを返すイテレータ
list = YieldList([4 , 8 , 16 , 32 , 64 , 128])
for e in list.gen():
	print e
 以上がPythonの基礎知識です。ここまで知っておけば、大抵のことはできるのではないでしょうか。
 Pythonだけでも結構な量になりましたが、さらにGroovyも始めました。GroovyはJavaで書かれたスクリプト言語であり、スクリプトをJavaのバイトコードに変換して動かします。したがって、Javaで提供されているライブラリを完全にサポートする上、Javaでできることはほとんど可能です。そして何よりうれしいのは、構文がほとんどJavaであるという点です。クロージャをサポートしているなどJavaと違う部分もありますが、ほとんどのJavaコードは多少の手直しだけでGroovyでもそのまま動きます。
 Groovyでの配列は[]を使って宣言し、「["name":"value"]」の構文でハッシュを作ることもできます。それぞれJavaのListやHashとして扱っているようです。また、{}を使ってクロージャも宣言できます。Javaと同様にクラスやインタフェースを作ることもでき、メンバ変数を「def var」のように宣言すれば、自動的にsetter/getterを書いてくれます。
 さらに面白いことに、型は宣言してもしなくても構わないという素晴らしい特徴を持っています。その他、文末のセミコロンは省略してもしなくても構わず、メソッドのカッコも省略してもしなくても構わず、グローバルな部分(クラス及びメソッドの外)にコードを書いても書かなくても構いません。また、クラスにgetter/setterが定義されている場合には、これらをプロパティのように扱えます。つまり、Javaのようにもスクリプトのようにも扱える言語なのです。
 また、ファイル出入力やSQLなどにいくつかの拡張が設けられており、クロージャを使って処理することが可能になっています。クロージャの構文はRubyに似ていますが、区切りに->を使用します。それ自体がClosureという型であるらしく、メソッドの引数として使用できます。
// 1行ずつファイルを読み込んで表示
File f = new File("filename");

f.eachLine({line ->
    println(line)
});
 リストやハッシュもクロージャとして処理する機能が導入されています。
def list = ["n1" : "Value" , "n2" : "Value2"];

list.each({n , v ->
	println(n + ":" + v);
});
 クラスは普通に宣言できますし、型を省略することもできます。ただし、メソッドのアクセス指定はデフォルトでpublicになりますので、必要ならprivateなどの宣言を行うようにしましょう。また、defをフィールド名の頭に付加すれば、privateな上にgetter/setterを持つ変数になります。
 なお、Groovyではローカル変数も含むあらゆる変数を宣言する際には、変数の頭に何らかの記述が必要となっていますので、変数を使用する際には注意しましょう。以前のGroovyでは何も書かなくても動作したようですが、最近のGroovyでは必要となっています。ローカル変数を使用する際、型などを宣言する必要がなければ、頭にdefをつけるだけで構いません。
var = "data";	// エラー : 変数の頭に記述がない
def var = "data";	// OK : def が記述されている
String var = "data";	// OK : String が記述されている
def String var = "data";	// OK : String だけの場合と同じ
 クラスの宣言方法自体はJavaとほぼ同じです。クラス生成時には、コンストラクタが定義されていなくても、変数に代入を行うことができます
// ここでは def String として宣言しているが
// 型を省略したければ String なし(def だけ)でも動作する
// def を使うと自動的に変数が private となり、getter/setter が生成される
public class GroovyClass{
	def String name;
	def String value;
}

// GroovyClass にはコンストラクタが定義されていないが
// 以下の構文で変数への代入を行うことができる
def i = new GroovyClass(name:"Name" , value:"Value")
 このように、Groovyは「Javaをスクリプト言語風に書けるようにしたもの」なのですが、私が試したところによると、いくつかJavaと同じコードが動かない場面が存在しました。まずは配列絡みの場合です。Groovyでは[]後置型の配列型宣言ができないようです。
String str[];	// ダメ
String[] str;	// OK
 私はC時代の習慣から上の構文を良く使いますので、これは痛いです。というのも、型名の後に[]を置くのは、「int[] i1 , i2」のような場合に「int[]型なのはi1だけなのか、i1とi2の両方がint[]型なのか」が紛らわしいためです。ちなみにこの場合、Javaでは両方ともint[]になるのですが、C/C++で「int* i1 , i2」のように書くと、i1のみがポインタになります。
 それから、{...}による宣言時代入は[...]に置き換える必要があります。また、new int[]{...}のような書き方の配列インスタンス生成はできないようです。
char[] cs = {'a' , 'b' , '\0'};	// エラー
char[] cs = ['a' , 'b' , '\0'];	// OK
char[] cs = new char[]{'a' , 'b' , '\0'};	// エラー
char[] cs = new char[]['a' , 'b' , '\0'];	// エラー
 さらに、どうやら匿名クラスやローカルクラスのサポートもないようです。
public interface Anonymous{
    void anonyMethod();
}

public void p(Anonymous a){
    a.anonyMethod();
}

// エラー
p(new Anonymous(){
    public void anonyMethod(){
        println("anony");
    }
});
 当然のことながらインスタンス自体は使用でき、普通にインプリメントしたクラスを書くことはできます。
 他にもいくつか面白い機能はありますが、別にGroovy特有の機能を覚えなくても、構文自体がJavaとほとんど同じですので、Javaさえ知っていればすぐにでも書けるのはメリットです。さらにはGroovyのコードからJavaのクラスファイルを生成することまでできるようです。せっかく導入してみたということで、早速テストに使っていますが、上々です。
 しかし、いくら簡単とはいえ、言語を覚えるのはこれで結構難しいです。ループ脱出(continue-break,next-last,next-break)や条件判定(else if,elsif,elif)、例外(throw-try-catch(-else)(-finally),raise-begin-rescue-else-ensure,raise-try-except-else-finally)で迷わない自信がありません。
 そういえば、山田洋行の元専務は「日本ミライズ」という会社を立ち上げていましたが、語源は「me raise」(自分を上げる)とのこと。まさか、raiseは「上げる」という意味ではなく、例外送出の構文なのではないでしょうか。ただ、この例外にrescue(救い)はなかったようです。さらに、この専務や守屋氏が逮捕されても、汚職にfinallyはないことでしょう。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

政治家につけるコウヤクなし
2007/11/25(Sun)22:36:59
 恐るべし舛添氏。実際には舛添氏だけでなく自民党全体にも責任はあるのですが、参院選の公約「年金記録の特定を最後の1人、1円まで行う」は「参院選挙のスローガン」であると述べ、公約を放棄することを自ら認めました。すなわち、公約はスローガンであって国民との契約ではないと語っているのであり、他の公約や今後作る公約も同じ理由によって反故にする可能性があることを明言したも同然です。最近は企業の不祥事が多く発生していますが、もしこのようなことを取締役が行えば、あっという間に株主から糾弾されて席を追われることでしょう。
 日本では長らく「公約とは破るもの」との認識が幅を利かせてきましたが、本来公約は誇大妄想の集大成ではなく、国民との約束事を定めるものです。そして、二大政党制においては政権交代が現実に発生する可能性があり、いわば複数の政党が「商品価値」をアピールして競合している状態です。この状況下での「公約」とは、商品のスペックやアピールポイントを論じたものであり、公約を守らない行為は商品の性能を偽った詐欺と同等です。
 しかし、日本では長らく公約が飾りでしかなかったせいか、国民が公約破りに対して大変寛容であるという印象は否めません。もし通信販売で最新PCを買ったとして、実際に送られてきたのが2年前の型落ちPCであるなら、多くの人は文句をつけるでしょう。また、電気店で洗濯機を注文したにもかかわらず、後で送られてきたのが洗濯機どころか洗濯板であったなら、これまた多くの人は文句をつけるでしょう。ところが、公約においてのみは「洗濯機」と偽って洗濯板を販売することが許されるのです。
 特に今回の公約に関しては、私はこのブログ中でも「絶対に無理」と繰り返し述べてきました。内部事情を詳しく知らない私ですら絶対無理であることが分かるのですから、内部事情を知る政府関係者や舛添氏であれば、無理であると分からないわけがありません。もし本気で無理であると分からなかったのであれば相当な無能者ですし、無理と分かっていながらいい加減なことを言ったのであれば、国民を欺く意思が存在したことになります。
 残念ながら、政治家自らが公約破りを宣言した例は今回が初めてではありません。例えば小泉氏は「公約を破る行為は大したことではない」と言い放ったことがありますが、それにもかかわらず世論の支持で長期政権を築き上げました。つまり、政治家にとって公約とはこの程度のものでしかないのです。さらに言えば、「公約破ります宣言」をした相手をひたすら持ち上げる世論も甘いと言わざるを得ず、これでは公約を破ってくださいと言わんばかりです。
 その点、公約を「マニフェスト」に改める動きは歓迎すべきものでした。マニフェストといえば衆院選で民主党が持ち出したものが有名ですが、注目すべきは知事選などの地方選においてマニフェストを掲げた候補が当選・善戦したことであり、これが「政権公約」の別名と認識されるようになってしまったのは残念でなりません。公約をどう呼ぶかはともかく、「公約は国民との契約である」「公約を実行しないのはニセ商品を売りつける詐欺と同じ」などという当然のことを未だに政治家が認識していないのは恥ずべきことです。
 それにしても、今回も舛添氏のいい加減さには感服させられました。「小人のざれ言」「バカ市長」と言ってみたり、物理的に100%無理であることは明らかなのに「期間内に年金記録の処理を最後の1人までやる」と言ってみたり、無賃残業合法化法案を「横文字にするから残業代ゼロ法案と書かれて廃案になった。家庭だんらん法案なら通る」として「家庭だんらん法案」で提出させようとしたり、やっていることが幼稚としか言いようがありません。このような、どう考えても厚生労働相に向かない人間が一部から支持を集めている図式には恐ろしささえ覚えます。

 民主党の協力が得られないとあって、自民党は給油法案の再可決も辞さない方針です。確かに、国会の規定に従う限りは再可決・成立を行うことはできます。しかし、この行為はどう考えてもおかしいのです。
 まず、この2/3もの議席は前の前の内閣である小泉内閣が取ったものであり、その際には郵政民営化のみを争点としていました。この選挙自体、やり口からして民意を反映しているかは非常に疑問なのですが、ともかく与党は議席を2/3確保しました。したがって、もしその際に野党が参院の過半数を握っており、そこで解散に打って出て2/3を確保したのであれば、選挙のやり方は別としても郵政民営化を再可決することは民意です。
 しかし、この議席を得た内閣は終わり、その次に発足した内閣も終わり、福田内閣が作られました。ところが、福田内閣は選挙による信任をただの1度も受けていません。安部内閣は1度たりとも選挙による信任を受けぬまま我を通し、どうしようもない法案を徹底的に強行採決した末に不信任を突きつけられて退場しましたが、再可決はまさにこれと同じ行為です。しかも小泉内閣の時点では、与党がここで得た議席を後に再可決に使うであろうことなど誰も予想していませんでした。小泉内閣が、しかも郵政のみを争点とした選挙で得た2/3の議席を、福田内閣が給油活動の再可決に使う行為には全く大義がないのです。
 さらに、与党は繰り返し「野党の問責決議案に従う必要はない」としていますが、そうはいきません。なぜなら、最も直前に行われた選挙において、国民が野党に問責決議案を出せる権限を与えたためです。少なくとも、再可決や問責決議案無視は規定の上では行うことができますが、民意に真っ向から逆らう行為であり、正当性は全くありません。
 それならどうすべきかといいますと、できるだけ早期に衆院を解散し、解散総選挙によって2/3の議席を確保し、堂々と再可決を行うべきなのです。国民は野党が参院を握っていることを知っていますから、給油法案などの再可決を支持するなら与党に2/3の議席を与えるはずです。もし過半数は超えても2/3を超えないようであれば、政権交代はさせないが再可決を行ってはいけないという民意ですし、過半数割れなら政権交代すべしという民意です。もし「衆院を解散しても2/3は取れないから、今のうちに再可決をしておこう」と考えているのであれば、与党は再可決の信任を受けられないことを知っていながら再可決を行おうとしているのであり、それこそ民意無視というものです。正当性のある再可決を行うには、衆院解散しかありません。
 福田内閣は安部内閣と違い、安定性と堅実さを持つ内閣であると私は考えています。安部内閣のように国民のためにもならない法案を強引に通すようなこともしていませんし、独善的な自分の思想を実現するために好き勝手なことばかりしているわけでもありません。したがって、支持するとまではいきませんが、批判すべき点もさほどなく、安部内閣時のように明日にでも無賃残業合法化などの国民殺し法案を通されかねないという怖さもなく、極めて危なっかしい安部内閣と違って安心できる内閣ではありました。福田内閣で救いようのない部分といえば、安部内閣からシフトした舛添氏程度のものです。しかし、もし大義もなく再可決を用いるようであれば、この認識は捨てざるを得ません。
 再可決をするなら解散総選挙で2/3を確保してからです。福田氏の良識に期待します。
 それから、政治的な問題はこの際置いておくとして、「83会」(いわゆる「小泉チルドレン」)の国民にとって役に立ちもしない無能者を一刻も早くクビにするためにも、少しでも早い解散総選挙を望みます。これらの中には、低IQ選挙でなければ100%当選しなかったであろう見識も資質もない人間、客寄せパンダとするために比例区で「当選保証」されていて、どう転んでも必ず当選することになっていた人間などもおり、これらの者が議員になったのは民意とは言いがたいため、一刻も早い解散によってこれらの人間の処遇を決めなければなりません。

 Rubyインタプリタは入れてみたものの、それでも重要なのがJRubyです。それというのも、JRubyがRubyには実装されていない強力な機能を備えているためです。その機能こそがRubyからJavaへのアクセスです。
 なに、RubyなどでJavaにアクセスするなら、最初から100% Pure Javaで書くか、最悪でもJNIを使ってCで書けば足りる、ですと?すべておっしゃる通りです。わざわざRubyで書く義理も大義もありません。特定の言語を取り扱うサイトなどでは、よく「〜という処理を〜言語で書くと、効率が大幅にアップする」などという文言を見かけますが、比較対象の言語が余程劣っている、または使用する言語が特定の処理に特化しているのでない限り、そこまでの差が生じる方が変です。確かに、C++よりJavaの方がGCがある分書きやすいのではありますが、JavaとRubyでそこまでの差が生じるというのは、Javaが余程苦手か、Rubyが余程得意でなければあり得ません。
 一応明記しておきますが、私は別にRubyが非効率的であると言いたいのではありません。もし100% Pure Rubyのコードに理由もなくJavaコードを混在させようとすれば、私はそちらにも疑問を覚えるでしょう。「正当な理由なく」「大部分を特定の言語で書いているものに対して」「異なる言語を用いる」ことが問題なのです。このようなことをすると、以下のような問題が発生する恐れがあります。

・複数の言語を取り扱う際には、それらすべての言語に対する知識が必要。マルチランゲージの開発者は意外に少ないようです。
・複数の言語を動かせる環境が必要であるため、移植性がかなり落ちる。例えばPerl 6からJavaを呼び出す際にはJava VMが必要です。したがって、Perl 6からJavaを動かそうとすると、Perl 6とJava VMの両方が必要です。
・時に環境依存が発生。例えばJavaはOS無関係に動くというのが建前ですが、JNIでOS依存のネイティブコードを使うと特定のOSでしか動かなくなります。
・パフォーマンスが落ちる。JRubyのように特定の言語上で特定の言語を動かす仕組みであるなら、JavaだけならJava VMがクラスファイルをパースすれば足りるのに、JRubyを使うとRubyコードを解釈しなければなりません。Perl 6のようにPerl 6からJava VMを呼び出すのであれば、Perl 6とJava VMの両方の起動や処理のオーバーヘッドがかかります。
・可読性が落ち、実装に制限が出るため、プログラムを書きづらい。いくらたくさん言語を使えても、言語が混在したプログラムを扱うのは結構難しいのです。また、例えばJavaのsynchronizedロックはPerlには持ち越せず、必要なら共用できるロックが必要です。同じく、JavaではEJBを介して、PerlではDBIを使ってデータベースを読み込んでいるような場合、トランザクションが上手く機能しない恐れがあるため、特別な実装が必要になることがあります。

 そういうわけで、JavaコードをRubyで書くメリットはほぼありません。Javaで書きましょう。しかし、これではJRubyの存在価値がなくなってしまうため、今回はJRubyからJavaを使ってみることにしましょう。実際、これまでにもJavaからJavaScript、PHPからJava、Perl 6からJavaといった具合に結構似たようなことを行っています。JNIが本来想定している使い方のように、特定の言語でしか提供されていない有用な機能を用いるなどの使い方をする分には便利かもしれません。
 さて、まずはRubyのパース方法ですが、jrubyでソースファイルを解釈しても、jirbでコマンド プロンプトにプログラムを打っても、どちらでも構いません。単純な実験ならjirbが手軽ですが、長いコードならjrubyを使う方が良いでしょう。
 それではRuby中でJavaコードを使う方法から。念のために書いておきますが、この機能を使うにはJRubyを使う必要があります。通常のRubyでは動かせません。
require "java"
 これでJavaを使う準備ができました。JRubyはもともとJavaで作られているため、PHPやPerl 6のような面倒な作業は不要です。JAVA_HOMEなどの環境変数さえ設定されていればJRubyを起動でき、JRubyが起動できればJavaコードも最初から使えるため、かなりお手軽です。
 それでは試しにHello Worldから。
require "java"
java::lang::System.out.println("Hello World!")
 Rubyコードですからセミコロンは不要です。これはJavaでいう以下の記述と同等です。
java.lang.System.out.println("Hello World");
 しかし、毎回「java::lang::System」と書くのは手間ですし、Javaではこれを省略する方法が存在します。Rubyでも何とかならないものでしょうか。しかし、そこはさすがにJava上のRuby、import文と同じ効果を持つものとして「include_class」メソッドが用意されています。
include_class("java.lang.System")
System.out.println("Hello World");
 ただし、私が試したところによれば、StringなどRubyの組み込み型とかぶる名前のクラスはinclude_classできないようです。そうしたクラスはそのつど「java::lang::String」などと完全名で指定するか、エイリアス名をつけて参照する必要があります。
include_class("java.lang.String") do |pkg,name|
	"Java" + name
end
 いわゆるブロック付きメソッド呼び出しというものです。pkgにはパッケージ名が(「java.lang」などのように)、nameにはクラス名が格納されており、ブロック内で参照できます。ここでは「"Java" + name」であるため、「JavaString」という別名が付きます。
JavaString.new("string")
 もっとも、Javaのメソッドの引数に文字列を渡すような場合、RubyのStringとjava.lang.StringとはJRubyが自動的に変換してくれるらしいため、明示的なjava::lang::Stringにお世話になることはあまりないでしょう。
 このように、JRubyはいくつかの型を変換してくれますが、どうも配列型は上手くいかないようです。
list = ["a" , "b" , "c"]
# char[] 版のコンストラクタのつもりなのですが...
java::lang::String.new(list)
 プリミティブ型はともかく、クラス型の配列変数の作り方なら分かりました。
list = java.lang.String[2].new()
list[0] = "String1"
list[1] = "String2"
java::lang::System.out.println(list[0])
java::lang::System.out.println(list[1])
java::lang::System.out.println(list)
 これで「[Ljava/lang/String;」型のインスタンスが作成できます。
 一方、プリミティブ型の作り方は不明でしたが、試しに次のように打ってみたところ、何とかなってしまいました。
list = Java.char[5].new()
 ところが、要素への代入のやり方が良く分からないのでありました。
 それでは少しまともなプログラムを書いてみるとしましょうか。ここでは「Java上で何らかのスクリプト言語を動かすための機構及び言語名」を登録するMXBeanを作るものとします。
 まずはクラスを作成するのですが、クラスファイルは「JRuby\bin」内に設置するようにします。どうやらJRuby内でもCLASSPATHは有効なようで、大抵の人はCLASSPATHに「.」を設定しているはずですから、これで動作させることができます。もし上手くいかない場合は、JRubyのbinディレクトリをカレントにしてからjrubyコマンドを実行してみてください。
 下準備として以下のJavaソースファイルを作成します。
// ScriptParsersMXBean.java
import javax.management.MXBean;
import java.util.List;

@MXBean public interface ScriptParsersMXBean{
	String getName();
	void setName(String n);
	List<ScriptParser> getParsers();
	void setParsers(List<ScriptParser> list);
}

// ScriptParsers.java
import javax.management.MXBean;
import java.util.List;
import java.util.ArrayList;

public class ScriptParsers implements ScriptParsersMXBean , 
	java.io.Serializable{
	private String name;
	private List<ScriptParser> parsers;

	public ScriptParsers(){
		name = "";
		parsers = new ArrayList<ScriptParser>();
	}

	public String getName(){
		return name;
	}
	public void setName(String n){
		name = n;
	}
	public List<ScriptParser> getParsers(){
		return parsers;
	}
	public void setParsers(List<ScriptParser> list){
		parsers = list;
	}
}

// ScriptParser.java
import javax.management.MXBean;
import java.beans.ConstructorProperties;
import java.util.List;
import java.util.ArrayList;

public class ScriptParser implements java.io.Serializable{
	private String name;
	private String language;

	@ConstructorProperties({"name" , "language"}) 
		public ScriptParser(String name , String language){
		this.name = name;
		this.language = language;
	}

	public String getName(){
		return name;
	}
	public void setName(String n){
		name = n;
	}
	public String getLanguage(){
		return language;
	}
	public void setLanguage(String l){
		language = l;
	}
}
 これらの準備ができたら、適当な場所にルビーのソースファイルを作成します。
require "java"

include_class("ScriptParsersMXBean")
include_class("ScriptParsers")
include_class("ScriptParser")
include_class("javax.management.openmbean.CompositeData")
include_class("javax.management.openmbean.ArrayType")
include_class("javax.management.JMX")
include_class("javax.management.remote.JMXServiceURL")
include_class("javax.management.remote.JMXConnector")
include_class("javax.management.remote.JMXConnectorFactory")
include_class("javax.management.remote.JMXConnectorServer")
include_class("javax.management.remote.JMXConnectorServerFactory")
include_class("javax.management.MBeanServer")
include_class("javax.management.MBeanServerConnection")
include_class("javax.management.ObjectName")
include_class("java.lang.management.ManagementFactory")
include_class("java.rmi.registry.Registry")
include_class("java.rmi.registry.LocateRegistry")
include_class("javax.rmi.PortableRemoteObject")

BEAN_URL = "service:jmx:rmi:///jndi/rmi://localhost:8082/ScriptParsers"
BEAN_NAME = "com.yamicha.scriptparsers:type=ScriptParsers"
PORT = 8082

on = ObjectName.new(BEAN_NAME)

registry = LocateRegistry::createRegistry(PORT)

mbs = ManagementFactory::getPlatformMBeanServer()
jmxcs = JMXConnectorServerFactory::newJMXConnectorServer(
	JMXServiceURL.new(BEAN_URL) , nil , mbs)
jmxcs.start()

sp = ScriptParsers.new()
sp.setName("Javaで使えるスクリプト言語")
parsers = sp.getParsers()
parsers.add(ScriptParser.new("rhino" , "JavaScript"))
parsers.add(ScriptParser.new("JRuby" , "Ruby"))
parsers.add(ScriptParser.new("Groovy" , "Groovy"))
parsers.add(ScriptParser.new("Jython" , "Python"))

# Bean を登録する
if !mbs.isRegistered(on) then
	mbs.registerMBean(sp , on)
	print "Bean を新規登録しました。\n"
else
	print "Bean は登録済みです。\n"
end

# Bean を読み取り・変更
connector = JMXConnectorFactory::connect(JMXServiceURL.new(BEAN_URL))
mbs = connector.getMBeanServerConnection()

if mbs.isRegistered(on) then
	# アトリビュート版
	name = mbs.getAttribute(on , "Name")
	print name + "\n"

	ps = mbs.getAttribute(on , "Parsers")
	ps.each() do |p| 
		print p.get("name") + "=" + p.get("language") + "\n"
	end

	# オブジェクト取得版
	sp = JMX::newMXBeanProxy(mbs , on , 
		java::lang::Class::forName("ScriptParsersMXBean"))
	print sp.getName() + "\n"
	ps = sp.getParsers()
	ps.each() do |p| 
		print p.getName() + "=" + p.getLanguage() + "\n"
	end

else
	print "Bean が登録されていないため、処理を実行できません。\n"
end

# 終了
jmxcs.stop()
 これでJRuby上からMXBeanを登録して読み込むことができます。
 ちなみに、setter/getterが取る引数などの関係上、今回それをするのは少々難しいのですが、JRubyにはJavaのコードを「Ruby風に」書く方法が用意されています。個人的にはRubyよりJavaの方が好きですので、少し苦手なのですが。
 例えばjava::util::Calendarを例に取ると、get/setの代わりにこのように書くことができます。
c = java::util::Calendar.instance
date = c.time
newdate = java::util::Date.new(date.time + 1000*60*60*24)
c.time = newdate
p c.get(java::util::Calendar::DAY_OF_MONTH)
 おそらく明日の日付が表示されることでしょう。また、Javaの「methodName」のスタイルではなく、「method_name」のスタイルの名前を使うこともできます。
p java::lang::String.new("letter").to_upper_case()
 これで文字列が全部大文字になります。
 is〜メソッドについては、isを取り除いた名前のフィールドとしても、isを取り除いた名前のメソッドとしても、さらにはRuby風にメソッド名末尾に?が付加されたメソッドとしても参照できるようです。
str = java::lang::String.new("")
str.isEmpty()
str.empty
str.empty()
str.empty?()
 ただ、実際に確認してはいないものの、フィールドやメソッド名として呼び出す方式を使うと、get〜がある場合はそちらが呼ばれそうな気がします。したがって、Ruby風に?をつけるのが最も確実かつ分かりやすいのではないでしょうか。そのようなことを考えている間に、Javaメソッド名そのままのis〜()形式で呼び出せば済むのではありますが。
 それにしても、こうした「言語から他の言語を使う」技術がさらに推進されると、最終的には1つ2つの言語を覚えるだけでは開発者と名乗れず、ただでさえ高い敷居がさらに高くなったりしないでしょうか。現状でさえ、ServletやEJBを扱うにはXMLが、DBIやJDBCを扱うにはSQLが、CGIやPHP、Servlet/JSPを扱う際には時としてJavaScriptが必要になったりするというのに。しかし実際、言語を3つも4つもというマルチランゲージの開発者は少ないようでもありますし、本当のところはどのような状況なのでしょうか。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

万能細胞生成手続
2007/11/22(Thu)21:47:14
 人間の皮膚の細胞に特殊な加工を加えることで、ES細胞と同等のものを作成する技術がこのほど発見されました。ES細胞はいわば「細胞の素」であり、様々な臓器に変化する可能性を持っていますが、これはもともと受精卵に存在するものであり、ES細胞を取り出すにはこれを作って破壊しなければならないため、倫理上の観点から疑問が呈されていました。受精卵を破壊するのは生命を破壊する行為であるという疑念がある上、クローン人間を作ることも可能であるため、様々な意味で問題が多かったようです。
 今回作られたiPS細胞はES細胞と類似の機能を持つ上、上記のような倫理上の問題も回避されるため、自分のDNAを持つ臓器再生医療に道を開いたものであるといえます。しかも動物実験の段階ではなく、人間の細胞に対する実験まで成功したとあっては、注目が集まるのは当然というものです。
 これまではES細胞で同様のことが言われてきましたが、結局ES細胞の研究は頓挫してしまった印象があります。こちらも有用な技術であるにもかかわらず、期待とは裏腹に研究が進まなかった原因としては、実験に用いる卵子などの入手が困難であることに加え、「倫理観」を理由とした研究妨害や研究への障壁が考えられます。
 倫理を理由としてES細胞を否定することの是非はここでは述べません。しかし、ES細胞やクローン人間の作成・研究を法律や規定で禁じたり、厳しい制限を課したりしている国はかなり多いようです。禁じられている場合は研究はできませんし、禁じられていない場合も予算や被験者の確保が難しく、研究続行が非常に困難であろうことは想像に難くありません。つまり、倫理上の問題が少ないiPS細胞の研究はこの点でもES細胞より有利であると考えられます。
 一方、iPS細胞にも倫理上の危機感が存在しないことはないようです。これを使って精子と卵子を作れば、特定の遺伝子を「親」に持つ人間などという、いわば「人工の生命」ともいえるものが作れてしまうため、iPS細胞が倫理上の問題すべてを克服したとはいえません。
 しかし、万能細胞技術で倫理上の問題を完全に克服することはまず不可能と見るべきです。この技術はあらゆる臓器に変化する細胞が作れるからこそ注目されているのであり、したがって理論上はクローン人間または類似のものを作ることができます。「あらゆる臓器にはなるが、クローン人間は作れない」などという都合の良い技術はまずあり得ません。
 つまり、万能細胞技術を研究または利用する行為とクローン人間などの倫理上の問題とはトレードオフであり、これは同種の技術がいくら研究されてもおそらく変わりません。ただ、ES細胞では生命となるものを破壊する必要がありましたが、iPS細胞ではそれをする必要がないため、倫理上の問題はES細胞に比べて明らかに軽いです。そして、トレードオフとなる部分のメリットとデメリットを比べた場合、どちらを重要とするかは主観にもよりますが、「クローン人間や類似のものが作られるかもしれない」という不確かな危険よりも臓器再生医療の方を重いとみなす人が大部分ではないでしょうか。
 しかし、ES細胞やiPS細胞の問題に限らず、DNAの利用に高い倫理観が要求されることは言うまでもありません。無論、研究者に倫理観が必要であることは当然として、研究者でない人も十分な倫理観を持つことが必要です。現実問題として、保険会社の一部は将来的にDNAの危険因子によって保険料に差を設けることを検討しているようですが、DNAは本人の意思や努力ではどうすることもできず、これを問題視する声は少なくありません。また、白人による黒人の差別、土地や血筋による差別などが現実に存在していたり、かつて存在したことがありましたが、DNAによって差別が生じることも懸念されています。米国で著名人が「黒人は白人に劣る」と発言して問題になった事例がありましたが、「特定の遺伝子がない者は劣る」などという差別が横行する可能性は捨て切れません。血液型占いのような無根拠で差別的な占いや思想がはびこる恐れもあります。
 ヒトゲノム計画が行われ、臓器再生の可能性も出てくるなど、ここ数十年のうちに技術は大きく進歩しました。しかし、DNAによる差別などといった懸念を見る限り、人間自体はろくに進歩していないようです。万能細胞による臓器再生技術を確立したり、DNAによる発病因子などのリスク評価技術を進歩させるより、DNAや万能細胞といった技術を受け入れられるほどまでに人間を進歩させる方が難しい気がしてなりません。

 冤罪によって強姦事件の犯人とされ、先に無事釈放された柳原さんが再就職との記事がありました。本来再就職は困難であったものの、一連の報道で事件のあらましを知った老人施設から申し出があったといいます。マスコミもここまで報道する必要はない気がしますが、この記事は色々な問題点や教訓を打ち出してくれます。
 まずは、国が冤罪を含む服役者に非常に冷たいことが分かります。「犯罪者の6割が再犯」などという調査結果も出ましたが、これでは当然というものです。以前から言われていますが、国は「出所後のサポート」も十分に行うべきでしょう。犯罪加害者に対して世話を焼くことを批判する向きもあるでしょうが、これをすれば再犯を抑制できる可能性があり、治安を改善することができるのですから、少なくとも無駄な行為ではありません。さらに、通常の服役者でさえ支援不足が指摘されているのに、何の落ち度もない冤罪被害者すら放置などといった状況は最悪です。
 こうしたことからも、冤罪の被害回復が非常に困難であることが分かります。服役に費やされた時間が戻らないことは当然として、地位が損なわれる上、名誉も侵害されます。しかも、それらすべてを回復することは非常に困難ですが、国はこれを一部でも回復する方策すら十分に用意してはいません。今回の問題は「施設が報道を見て申し出た」ことによって記事の通りの運びとなりましたが、報道もなくろくな名誉回復もなされない人が多いであろうことは十分想像できます。
 また、マスコミの一部は今回のような問題を「報道によって人が救われた例」などとして美談にしそうですが、当のマスコミが多くの人の名誉を毀損していることを忘れてはいけません。マスコミの報道のせいで名誉や地位を失い、被害回復もなされぬまま放置されている人が存在することは言うまでもありませんし、河野氏のようにそのせいで実際に逮捕されてしまった人までいます。氏はその後にジャーナリストとして活動しており、少なくとも名誉だけはある程度回復されていますが、それすらない人が大勢いることを忘れてはいけません。
 そして、冤罪被害者に対する国の被害回復が不十分であることは言うまでもありませんが、マスコミはそれ以上に何もしません。例えば、冤罪逮捕によって被害を招いた国には刑事補償法国家賠償法による賠償義務が生じますが、マスコミにはそれすらありません。民事で訴えたとしても、10万や20万などという裁判費用にもならない額が得られるのみです。さらに、どのマスコミも同業者による不祥事の追求には及び腰であり、結果として名誉回復も被害回復も大変難しい状況となります。
 「疑わしきは罰せず」など冤罪をできるだけ作らないための規定は色々あるのですが、実際に冤罪がなくなる様子はありません。冤罪を確実には回避できない以上、被害回復にも力を注がなければならないのは当然です。また、実際には「犯罪が増加している」という確固たる事実はないものの、治安の悪化を不安とする人が多いことは事実であり、もし犯罪を減らしたいなら最も大きな犯罪の山、すなわち再犯防止に手をつけるのが合理的です。これは冤罪被害者及び受刑者への支援が必要であることを示しています。マスコミによる名誉毀損については、「自主規制」などが何の役にも立たない以上、法律によって定めを作ることもやむを得ません。まずは被害回復を最優先する方法を考えるべきです。

 続・Ruby。早速RubyによってCGIを書くことにしてはみましたが、これが非常に難解な作業となりました。
 Rubyはカッコではなく命令文によってスコープなどほとんどのものを制御します。例えば、以下は諸言語とRubyの比較です。
※Perl/PHP では変数名の前に $ を付加

// 一般的な言語(C/C++、Java、Perl、PHP、C#、JavaScript...)
if(value > 100){
	// implements...
}

// Perl 以外はほとんど以下の記述も使える(1行の場合のみ)
if(value > 100)
	// implements...

# Ruby
if value > 100 then
	# implements...
end

// 以下はオマケ
' VB
If value > 100 Then
	' implements...
End If

# SQL
SELECT IF(value > 100 , implements... , ...) FROM table_name;

# XQuery
if(value > 100) then implements...
 RubyでCGIを書く際につらいのは、end文が他のソースにまぎれてしまうことが結構ある点です。そのようなものはインデントで分かると言うなかれ、CGIを書くとなるとヒアドキュメントなしでは非常に辛い上、ヒアドキュメントではタブやスペースも出力されるため、うかつに使うことができないのです。HTMLでは一応空白やタブを無視してくれますが、たまにこれがアクシデントを招く上、長々としたHTMLソースが右に寄って異常に見づらくなります。何よりプログラムにおいて「ぱっと見で分からない」のはかなり致命的です。
 この時点でCGIを書くにはPerlに利があるのですが、Rubyでは想像もしなかったところからいきなり例外が投げられてプログラムが強制終了したり、軽量スクリプト言語なのに型が厳しく簡単にTypeErrorを起こしたり、PerlやPHPと違ってローカル変数に$をつける必要がなく、さらにC/C++/Javaなどと違って関数をカッコなしで呼び出せるため、ローカル変数名にうっかり関数名と同名のものを使うとエラーを投げたり、かなりやっていられません。ローカル変数の名づけでイライラしたのはJavaScriptぶりです。
 例外を投げることは時として異常動作の回避やデバッグに役立つのですが、Perlではdieしない(evalでキャッチする必要がない)ようなところでも平然と例外を投げてくるため、失敗時の結果まで見越してエラー処理なしで関数を呼び出す、といったことはできません。そのつどrescueを書くことになります。さらにthrowsがなく、例外を正しくキャッチできるようにしているかなどという判定もないため、いきなり例外が飛んできてあせることが多々あります。
 型宣言がないのに型が厳しいのはかなり致命的です。PerlやPHPでは数字でも文字列として扱うことができ、文字列も数値データなら数字として扱えるのですが、Rubyでは整数なら整数、文字列なら文字列です。したがって、パラメータ(文字列)を数値として扱うには変換をしなくてはなりません。変換なしにうっかり扱うと、例外を投げられてしまいます。
 型が厳しいのはServletでも同じなのですが、Servlet/JSPでは型宣言があるため型を間違う可能性は低いです。その点、Rubyではどの変数が何型なのかをかなり把握しづらくなっています。さらに、Rubyでは型の不整合を実行時にしか判定してくれないため、これまたいきなり例外が飛んできてあわてるハメになります。これはPerlやPHPの変数でも同じなのですが、PerlやPHPは文字列や数値の自動変換が可能なのに比べ、Rubyではこれらでも例外が飛んできます。さらに、判定時にしか型のエラーが分からないため、条件分岐によって例外が出る場合と出ない場合があるなどといったことが発生し、バグの発見を大変困難にさせます。
 変数名によってエラーが出やすいのも致命的です。どの言語にも多かれ少なかれ予約語というものはありますが、クラス名や関数名と変数名がかぶると面倒であるため、多くの言語では回避する方策が採られています。Perlでは$,@,%、PHPでは$を変数の頭につけることで、またC/C++やJavaなど多くの言語ではクラス名と変数名がかぶっても正しく認識できるようにしたり、記述ルールを設けて両者がかぶることを回避したり、カッコの有無で関数と変数を区別したりしています。ところが、Rubyでは平気で変数名と関数名(実際には特定のクラスメンバを関数のように呼び出せるだけで、その実体はクラスメソッドであるとのこと。最初から関数形式で使えないようにしてくれれば助かったのですが)がかぶるため、非常に難儀します。クラス名の頭は大文字と定められており、クラス名と変数名がかぶらないだけマシとすべきでしょうか。
 正直言ってかなり厳しかったのですが、何とか書いたのが以下の「Ruby BBS」です。様々な記述には参りましたが、書いている間は結構面白いものではありました。Perlと違ってオブジェクト指向が平気で使えるため、書くのが大変愉快なのです(Perlでも5以降はオブジェクト指向は使えます。念のため。ただ、対応していないバージョンがある上、use baseなどのオブジェクト指向に関する記述には対応しているサーバーとしていないサーバーがあり、オブジェクト指向で徹底的に書くのは移植性に問題があります。blessなども少々面倒です。Perl 6では「Perl 5のOOPコードの1割はbless」などと揶揄されていました)。どうやら私の頭にもオブジェクト指向が染み付いてしまっているようで、新しく習得する言語であってもOOPを書いている限りは悪くありません。
 ただ、書くはよいよいデバッグ怖いとはこのことで、コードはほとんど完成系にもかかわらず、デバッグでくじけそうになりました。パラメータ絡みでTypeErrorは投げるわ、予想外の例外が飛んでくるわ、変数名と関数名がかぶるわ、endがコードにまぎれて意味不明になるわで、散々でした。せっかく覚えた以上はRubyで他のCGIを書いてみたいとも考えますが、2度と書きたくないとも考え、結局次に書くとしたらPerlになりそうです。
 なお、このスクリプトのコードの流用や実際の運用は規制しませんが、管理機構も付属しない「書いて見るだけ」の単純なものである上、しっかり検証しているわけではないため、バグがある恐れもあります。ご利用の際はその点にご注意願います。
 デフォルト設定では以下のファイル配置になります。私はWindowsのApacheサーバーですが、Unix系ならパーミッション設定も必要でしょう。
rubybbs.cgi(755) - 以下に示すソースの CGI ファイル
rubybbs.log(666) - 空のファイル
/lock(777) - 空のディレクトリ
 rubybbs.cgiのソースは以下の通り。
#!/usr/local/bin/ruby

# 掲示板の設定
class Config
	# タイトル
	Title = "Ruby BBS"

	# ホームページ
	Homepage = "http://www.yamicha.com/"

	# ログファイル名
	LogFile = "./rubybbs.log";

	# ロックディレクトリ
	LockDir = "./lock"

	# ロックディレクトリ内に作られるロック用ディレクトリ名
	LockName = "rubybbs"

	# 最大保持ログ数
	MaxLog = 100

	# 1ページに表示される最大数
	MaxView = 10

	# body タグのアトリビュート
	Text = "#000000"
	Bgcolor = "#FFFFFF"
	Link = "#0000FF"
	Alink = "#FF0000"
	Vlink = "#0000FF"

	# テーブル背景色
	Menu = "#CCDDFF"
end

# mkdir によるロックを行うクラス
# Ruby は ダック・タイピング言語であるため
# 同じメソッド名さえ使っていれば symlink なり fopen なり好きな手法で
# 実装でき、単にインスタンスを差し替えるだけで動作する
class MkdirLock
	# コンストラクタ
	# name : ロックに用いるファイル名
	# limit : ロックをデッドロックとみなして無効化する秒数
	# r : ロック時の再試行回数
	# wait : ロック時の再試行時に待機する秒数
	def initialize(name , limit , r , wait)
		@name = name
		@limit = limit
		@retry = r
		@wait = wait
	end
	def begin()
		i = 0
		while(true)
			begin
				Dir.mkdir(@name , 0777)
				return
			rescue => e
				i += 1
				if i >= @retry then
					raise "Lock is Busy"
				end

				# mkdir の時にはディレクトリが存在
				# していたものの stat の時点では
				# 消えているかもしれないので rescue
				stat = File.stat(@name) rescue continue

				# 指定された秒数より前に作成された
				if stat.mtime + @limit < Time.now then
					free()	# デッドロックとみなして解放
					next
				end

				sleep(@wait)
			end
		end
	end
	def free()
		begin
			Dir.rmdir(@name)
		rescue
		end
	end
end

# エラーメッセージを表示するクラス
# 今回作成したモデルにおいては ViewError のみをエラーメッセージとみなし
# 他の例外はすべてバグとみなして Ruby を強制終了するものとする
class ViewError < StandardError
	def initialize(message)
		@message = message
	end
	def message()
		return @message
	end
end

# CGI を処理する基底のモデル
# header() -> request() -> footer() の順にコールされる
# request() 中で ViewError を投げると
# error() をコールすることができる
class ViewModel
	def header_call()
		if !@is_head then
			@is_head = true
			header()
		end
	end

	def header()
	end

	def footer()
	end

	def service()
		@is_head = false

		header_call()
		begin
			request()
		rescue ViewError => e
			error_call(e.message)
		end

		footer()
	end

	def request()
	end

	def error_call(str)
		if !@is_head then
			header()
		end

		error(str)
	end

	def error(str)
	end
end

# フッターを実装したモデル
class HTMLModel < ViewModel
	def footer()
		print <<EOF
<hr />
<small>
Presented by 
<a href="http://www.yamicha.com/">yamicha.com</a><br />
このプログラムを書き直し、または流用し、
著作権の記載を削除することを一切制限しません。
</small>

</body>
</html>
EOF
	end
end

# BBS のデータ構造マッピング
class BBSData
	def initialize(t , n , d , m)
		@title = t
		@name = n
		@date = d.to_i()
		@message = m
	end

	# クラス(Java でいう static)メソッド
	# 記事を \n で区切り、データを \t で区切っている
	# 複数記事を含む文字列データを BBSData の配列として返す
	def self.parse(source)
		strs = source.split("\n")
		datas = []

		strs.each() do |str|
			log = str.split("\t")
			datas.push(BBSData.new(
				log[0] , log[1] , log[2] , log[3]))
		end

		return datas
	end

	# この BBSData をタブ区切り文字列として返す
	def serialize()
		return [@title , @name , @date , @message].join("\t")
	end

	# クラスメソッド
	# 渡された BBSData の配列を改行区切り文字列として返す
	def self.serialize_list(datas)
		serial = []

		datas.each() do |data|
			serial.push(data.serialize())
		end

		return serial.join("\n")
	end

	def title()
		return @title
	end
	def name()
		return @name
	end
	def date()
		return @date
	end
	def message()
		return @message
	end

	def set_title(str)
		@title = str
	end
	def set_name(str)
		@name = str
	end
	def set_date(d)
		@date = d.to_i()
	end
	def set_message(str)
		@message = str
	end
end

# BBS を制御するモデル
class BBSView < HTMLModel
	def initialize()
		# ロック用のインスタンスを生成
		@lock = MkdirLock.new(Config::LockDir + "/" + 
			Config::LockName , 60 , 5 , 1)

		# パラメータを取得
		require "cgi"
		@param = CGI.new().params
	end

	def header()
		print <<EOF
Content-type:text/html

<html>
<head>
<title>#{Config::Title}</title>
</head>

<body bgcolor="#{Config::Bgcolor}" text="#{Config::Text}" 
link="#{Config::Link}" alink="#{Config::Alink}" vlink="#{Config::Vlink}">

<b>#{Config::Title}</b><br />
<a href="#{Config::Homepage}">Homepage</a>
<hr />
EOF
	end

	def request()
		mode = @param["mode"][0]

		page = 0
		if(@param["page"][0] != nil) then
			page = @param["page"][0].to_i()
		end

		# Perl/PHP と違い、nil の場合の判定も用意しておかないと
		# 空白では nil と一致しないので注意
		if mode == "" || mode == nil then
			form()
			view(page , Config::MaxView)
		elsif mode == "write" then
			write(BBSData.new(@param["title"][0] , 
				@param["name"][0] , Time.now().to_i() , 
				@param["message"][0]))
			form()
			view(page , Config::MaxView)
		else
			raise ViewError.new("定義されていない動作です。")
		end
	end

	def form()
		print <<EOF
<form method="POST" action="?">
<b>記事投稿フォーム</b>
<table border="0">
<tr>
<td bgcolor="#{Config::Menu}">タイトル</td>
<td><input type="text" name="title" size="30" /></td>
</tr>

<tr>
<td bgcolor="#{Config::Menu}">名前</td>
<td><input type="text" name="name" size="30" /></td>
</tr>

<tr>
<td bgcolor="#{Config::Menu}">本文</td>
<td>
<textarea cols="65" rows="5" name="message"></textarea>
</td>
</tr>
</table>
<input type="hidden" name="mode" value="write" />
<input type="submit" value="送信" />
</form>
EOF
	end

	def view(page , max)
		# ロック開始
		@lock.begin() rescue raise ViewError.new(
			"ロック時にエラーが発生しました。")

		# ファイルを開く
		begin
			file = File.open(Config::LogFile , "r")
		rescue
			@lock.free()
			raise ViewError.new("ファイル " + 
				Config::LogFile + " を開けません。")
		end

		# 内容を読み込む(Ruby では read() だけで全部読める)
		filedata = file.read()
		# クラスメソッドを使ってパース
		rawlist = BBSData.parse(filedata)
		# 解放
		file.close()

		@lock.free()

		# リストから表示する部分のみを抽出
		list = rawlist[page , max]

		# ブロック付きメソッド呼び出しで処理
		list.each() do |data|
			print <<EOF
<table border="0" cellpadding="1" width="75%">
<tr>
<td bgcolor="#{Config::Menu}"><b>#{data.title()}</b>
<small> - 
#{Time.at(data.date()).strftime("%Y/%m/%d %c(%a)")}</small>
</td>
</tr>

<tr><td>
<table border="0" cellspacing="0">
<tr>
<td width="5"></td>
<td>#{data.name()}</td>
</tr>
</table>
</td></tr>

<tr><td>
<table border="0" cellspacing="0">
<tr>
<td width="15"></td>
<td>#{data.message()}</td>
</tr>
</table>
</td></tr>

</table>

<br />
EOF

		end

		# ページ移動
		print "<b>Pages</b>"

		len = rawlist.length() - 1
		if len < 0 then
			len = 0
		end

		i = 0
		index = 0
		while index <= len
			print " ["
			if index != page then
				print "<a href=\"?page=" + 
					index.to_s() + "\">" + 
					(i + 1).to_s() + "</a>"
			else
				print "<b>" + 
					(i + 1).to_s() + "</b>"
			end
			print "]"

			i += 1
			index += max
		end
	end

	def write(data)
		# 入力に不備があるならエラーメッセージ
		if data.name() == "" then
			raise ViewError.new("名前が入力されていません。")
		end
		if data.title() == "" then
			raise ViewError.new("タイトルが入力されていません。")
		end
		if data.message() == "" then
			raise ViewError.new("本文が入力されていません。")
		end

		# \n を改行タグに、\t を文字参照に置き換え
		message = data.message().gsub(/(?:\r\n|\r|\n)/ , "<br />")
		message = message.gsub(/\t/ , "	")
		data.set_message(message)

		# ロック開始
		@lock.begin() rescue raise ViewError.new(
			"ロック時にエラーが発生しました。")

		# ファイル読み込み
		begin
			file = File.open(Config::LogFile , "r")
		rescue
			@lock.free()
			raise ViewError.new("ファイル " + 
				Config::LogFile + " を開けません。")
		end

		filedata = file.read()
		list = BBSData.parse(filedata)
		file.close()

		# 書き込みのあったデータをリストに登録
		list.unshift(data)

		# 記事数が最大保存値を上回っているなら削除
		while list.length() > Config::MaxLog
			list.pop()
		end

		# リストを文字列化
		serial = BBSData.serialize_list(list)

		# ファイルを書き込みモードで開く
		begin
			file = File.open(Config::LogFile , "w")
		rescue
			@lock.free()
			raise ViewError.new("ファイル " + 
				Config::LogFile + " を開けません。")
		end

		# 書き込み
		file.write(serial)
		file.close()

		# ロックを解放
		@lock.free()
	end

	def error(str)
		print <<EOF
<b>Error</b><br />
次のエラーが発生しました : #{str}
EOF
	end
end

process = BBSView.new()
process.service()
 CGIを書くとなると、まずはパラメータの取り方を知る必要がありますが、Rubyではこれが結構簡単に行えます。
require "cgi"
@param = CGI.new().params
 返り値の@paramは配列であり、引数nameは次のように参照します。
@param["name"][0]
 末尾に[0]とつけているのは、@paramが二次元配列であるためです。ではなぜ二次元配列なのかといいますと、同じ名前の複数パラメータを受け取った時のためです。それ以外は特段難しいこともありません。Perlと違ってパースルーチンを自分で書かなくて済むのはありがたいところです。
 他に注目すべき点があるとすれば、コードの埋め込みでしょうか。Perlではヒアドキュメント内でも平気で変数が使えましたが、Rubyではそもそもローカル変数名に$がつかないこともあり、変数を埋め込めません。しかし、それでは不便ということで、コードを埋め込むことができます。
print <<EOF
#{code}
EOF
 変数を使いたければ、カッコ内に変数をそのまま書くだけです。また、Perlと同様にシングルクォーテーションを使えば、
print <<'EOF'
...
EOF
 コードの埋め込みを無効にできます。
 これ以外には特段説明すべき点もないでしょう。後はいずれも標準ドキュメントに記載されている組み込み関数・クラスの機能を使っているだけに過ぎません。さすがにオブジェクト指向だけはあり、ファイルでも何でもオブジェクト指向です。ちなみに、バイナリファイルを読み込む際には
file.binmode()
 このようにしてバイナリモード化できるようです。
 以上、今回はせっかくオブジェクト指向言語を使うのだからと、完全オブジェクト指向で組んでみました。クラスの外側に存在するのは、動作を開始するための変数のみです。しかし、CGIをオブジェクト指向で書けるのは本当に気持ち良いのですが、それ以外の点ではさすがに参りました。Rubyを平然と書いている人を尊敬します。
 私も開発者の端くれですから、動くものは何とか書けるということで。久々にPerlも書きたくなってきました。
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]

<-前のページ [29] [30] [31] [32] [33] [34] [35] [36] [37] 次のページ->
- Blog by yamicha.com -