2010-03-31

ADL再考

以下のコードが、どうも解せない。

namespace A
{
    class class_in_A {} ;
    void f(class_in_A) {  }
}

namespace B
{
    void f(A::class_in_A) {  }
}

int main()
{
    A::class_in_A obj ;

    // lookup A::f via ADL.
    f(obj) ;

{
    using B::f ;
    f(obj) ;// ambiguous.
// B::F is using declaration. Y is not empty.
}

{
    using namespace B ;
    f(obj) ;// lookup B::f.
// because it is not a using declaration, Y is empty.
// GCC, MSVC, Comeau disagreed and make it ambiguous.
}

{
    using namespace B ;
    using B::f ;
    f(obj) ;// ambiguous? because it also contains using declaration?
}

}

規格を素直に解釈すると、こうなると思うのだが。

追記:ambiguousが正しかった。

Raw String Literalとプリプロセッサ

行連結は Raw string literal を解釈するフェーズより前のはずなんだが、
どうなってるんだろう?

いい質問だ。日本もまだまだ捨てたものではない。惜しむらくは、そこまでわかっていながら、なぜドラフトやペーパーを読まないのか。

そこは、なかなか面白い。簡単に言えば、Phase 3で、Raw String Literalに限っては、Phase1, 2で加えられたプリプロセッサによる変換の、「逆変換」を行うのだ。

2.2 Phases of translation [lex.phases] p3

Within the r-char-sequence of a raw string literal, any transformations performed in phases 1 and 2 (trigraphs, universal-character-names, and line splicing) are reverted.

もちろん、ユーザーは、このような規格上の定義は、気にする必要はない。ただ、Raw String Literal内では、プリプロセッサによる変換が行われないと考えておけば、それで問題はない。詳細は、Language lawerの仕事だ。

N3077: Alternative approach to Raw String issues

追記:C++の規格というのは、規格の定義する意味と同じであれば、どのような実装をしても構わないものである。だから、Raw String Literalであることを認識する、賢いプリプロセッサがあってもいいし、実際、ペーパーによれば、多くのコンパイラの実装では、この変換を、覚えているらしい。

Apparently many compilers already keep track of those transformations internally.

どうも、Chromeのパフォーマンスが落ちたような

どうも、最新のDev版のChromeのパフォーマンスが、悪いような気がしてならない。ページのが完全に読み込まれるまで、反応がなくなる。まあ、Dev版なので、こういうこともあるだろうが、早く直して欲しいものだ。

ブログのレイアウトの調整中

セーブして、デフォルトのテンプレートに戻してみるか。どうも、エラーが取れない。

デフォルトのテンプレートを使っても、エラーが出る。Bloggerのせいだろう。

どうも、Bloggerのテンプレートが生成するHTMLで、</p>がひとつ、ミスマッチしている。Bloggerのテンプレートが、あまりにもぐちゃぐちゃで、どこを修正していいのか分からない。

追記、問題箇所を発見した。公式テンプレなのに、p要素がネストしていた。ひどい。

threadは明示的に使うべし

FCDで、thread周りの文面が、さらに明確に定義されるようになった。

たとえば、threadのデストラクタだ。もし、joinable()がtrueを返すthreadオブジェクトのデストラクタが実行された場合、terminate()が呼び出される。それ以外の場合、なにもしない(スレッドは、自分で実行を終えるまで、動き続ける。)

なぜか。もし、暗黙的に、join()やdetach()が呼び出される設計であれば、バグの温床になりえるからだ。

move代入演算子は、move元のオブジェクトが、joinableであった場合、terminate()を呼び出す。これはどうだろう。まあ、たしかに、join()している最中にmoveされたら、たまったものではない。join()出来る可能性があるオブジェクトをmoveするというのは、バグとみなしてもいいのかもしれない。

ChromeがFlash Playerをバンドルした

Chromium Blog: Bringing improved support for Adobe Flash Player to Google Chrome

Flash Playerは、最も普及している、ブラウザのプラグインである。

最新のChromeのDev版は、Flashをバンドルすることにした。つまり、Chromeのアップデートのフレームワークを使って、Flash Playerも、自動的にアップデートされる。

これにより、古いバージョンのFlash Playerを使い続けることによる、セキュリティのリスクがなくなる。Chromeと同じく、自動的に、静かにアップデートされるからだ。

現在、この機能は、実験的なため、コマンドライン引数に、--enable-internal-flash、を指定しないと、動かない。

また、ごく初歩的な、プラグインの管理機能を、about:pluginsタブに、実装した。

この機能は、なるべく早く、安定版にも取り入れるべく、努力されている。

まあ、何と理想をいおうとも、現時点では、まだ、Flashを捨て去ることはできない。とすれば、これは、現実的な問題の解決方法なのだろう。

例外指定について

そもそも、例外指定をdeprecatedにする意味は、例外指定が、現実の世界では、全く役に立たなかったからである。

noexceptの目的は、関数は例外を投げないと明示することより、コンパイラに、最適化のヒントを与えるものである。静的なソースコードの解析が目的ではない。

例外指定の、かつての目的は、単なるシンタックスシュガーであった。最適化のヒントは、全く意図していなかったのである。

なぜ、現実世界では、例外指定は、笑えるほどに失敗したのか。テンプレート引数がどのような型なのか、わからないからである。

template < typename T >
void f( T x ) 
{
// Tのコピーコンストラクタが例外を投げるかもしれない。
}

このようなコードで、例外指定で、実際に投げる例外を指定出来るわけがない。

では、noexceptを指定したコードで、例外を投げるパスがある場合、コンパイラはエラーを出すべきであるという意見はどうか。これは、非現実的である。そのためには、翻訳単位を超えた、大規模な静的解析が必要である。すべてのコンパイラに、そのような実装を求めるのは、現実的ではない。

確かに、エラーになれば、理想的だ。しかし、そんな機能は、exportと同様、主要な実装から、無視されるだけである。

もう一度いう。従来の例外指定は、現実的に無意味なため、廃止された。noexceptは、最適化へのヒントという役割のためだけに採用された機能である。

ただし、規格の文面は、コンパイル時のエラーを、禁止していない。つまり、優れた実装ならば、そのような機能を提供できる。現在、そのような意味を含めた文面を、明示的に追加するべきかどうか、議論中である。

2010-03-30

post-Pittsburgh mailingの簡易レビュー

post-Pittsburgh mailingが公開された。

最新のWorkind Draftは、N3090となった。また、FCDが、N3092として、公開された。中身は、ドラフトとほぼ同じである。これで、後は、修正ぐらいしかできない。がしかし、ひょっとしたら、またもう一度、FCDを出すかもしれない。いずれにせよ、C++0xの規格は、2011年内に、制定されるだろう。

N3047: Fixing is_constructible and is_explicitly_convertible

is_constructibleを、is_explicitly_convertibleと同等にする提案。その結果、is_explicitly_convertibleは、廃止される。

N3048: Defining Swappable Requirements

Swappable Requirementsの追加。言語機能としてのconceptが廃止されたので、概念として定義する必要がある。

N3049: Core issues 743 and 950: Additional decltype(...) uses (revision 1)

decltypeを、より、「型」として使えるようにするための修正。

N3050: Allowing Move Constructors to Throw (Rev. 1)

ライブラリのMoveコンストラクタのrequirementsで、throwを禁止しているが、これをやめる。moveコンストラクタ内からthrowして欲しくない場合は、std::move_if_noexceptw()を使う。

N3051: Deprecating Exception Specifications

例外指定をdeprecateにする。例外指定は、現実では、まったく意味がなかった。例えば、テンプレートが絡むと、明示的に投げる可能性のある例外を指定するなどということは、不可能になってしまう。

ただし、いくつかのコンパイラでは、何も指定しない、throw()を、関数は例外を投げないという指定とみなして、そのような最適化をしている。そこで、noexceptというキーワードを、新たに導入して、「この関数は例外を投げないと保証できる」と宣言出来るようにした。

互換性のために、nothrow()は、noexcept(true)と、同じシグネチャになる。

// noexceptと、noexcept(true)と、throw()は、同じシグネチャとして、認識される。
void trust_me() noexcept ;
void trust_me() noexcept(true) ;
void trust_me() throw() ;

// noexcept(false)と、throw(...)は、同じシグネチャとして、認識される。
void I_will_throw() noexcept(false) ;
void I_will_throw() throw(std::exception) ;

// 例外指定のない関数は、noexcept(false)やthrow(...)とは、違うシグネチャとして、認識される。
void dunno() ;

ちなみに、noexcept、noexcpt(true)、throw()と指定された関数が、もし、例外を投げた場合、std::terminate()が呼ばれる。こう規定することには、ひと議論あった。しかし、この指定はそもそも、例外を投げないという保証を、ユーザーが宣言するのである。例外を投げた場合、どうなろうと、知った事ではない。ユーザーの責任である。

ではなぜ、undefined behaviorではないのか。undefined behaviorでは、ポータブルなコードを書くことができない。たとえば、最適化の結果として、オブジェクトのデストラクタなどが呼ばれず、例外が関数外に送出されるということが起こり得る。これは、セキュリティ上、非常にまずい。

また、std::terminate()を呼び出すと規定しても、パフォーマンス上の影響はないと、その場にいた実装者は、全員同意した。meetingの後に、gccの実装者が、MLで、gccの現状の実装では、コストは全くないとはいい切れないと訂正したが、では、実際に目に見えるコストがかかるかどうかは、その実装者としても、断言できないそうだ。というわけで、コストは、ほぼない。

N3052: Converting Lambdas to Function Pointers

キャプチャリストが空のlambda式を、関数ポインタに変換出来るようにする提案。

void (* ptr )( int ) = [](int) {} ;

N3053: Defining Move Special Member Functions

データメンバーが、すべてmovableであった場合、moveコンストラクタを自動的に定義しようという提案。

N3055: A Taxonomy of Expression Value Categories

lvalueとrvalueを細分化してカテゴリ分けする。詳細は、本の虫: N3055: A Taxonomy of Expression Value Categoriesを参照されたし。

N3056: Conceptless Random Number Generation in C++0X, version 2

乱数ライブラリから、conceptの名残を取り除く提案。

3057: Explicit Initializers for Atomics

atomicオブジェクトのメモリオーダーなどを、明示的に指定して初期化出来るようにする提案。

N3058: Futures and Async Cleanup (Rev.)

futureとasyncライブラリに対する、雑多な細かい修正。

N3059: Proposal to Simplify pair (rev 5.2)

息の長い、pairを単純化しようという提案。

N3060: Extensions to the C++ Library to Support Mathematical Special Functions

C99の数学用の関数を、C++に取り入れる提案。誰が使うのだろう。

N3062: Core issue 789: Fixing Raw Strings wrt. Trigraphs (revision 1)

トライグラフの大半を、規格から削除する。IBMが使っているトライグラフだけは、互換性のために、残す。

N3063: Core issue 968: Disambiguating [[ (revision 1)

attributeと、lambda式、配列とで、文法が曖昧になる。今までの規格では、[[というトークンは、すべてattributeとして解釈するという文面だったが、問題なので、修正する。

以下のようなコードが、問題になる。

int x[10] ;

// x[1] = 0 と同じ。
x[[](){ return 1 ; }()] = 0 ;

N3064: Core issue 374: Explicit specialization outside a template's parent (revision 1)

名前空間の外側で、明示的な特殊化を許可する。

  namespace NS1 {
    template<class T>
    class CDoor {
    public:
      int mtd() { return 1; }
    };
  }
  template<> int NS1::CDoor<char>::mtd()
  {
    return 0;
  }

N3065: Removing Export

exportの廃止。deprecateではなく、完全な削除。ただし、exportというキーワードは、予約語として残す。exportの経緯については、Stroustrup: HOPL-3を参照されたし。よくまとまっている。

N3066: Iterators in C++0x

conceptの研究で得られた成果を、イテレーターに反映させる。

N3067: Core issue 951: Various Attribute Issues (revision 1)

attributeに対する、細かな変更。

N3068: Equality Comparison for Unordered Containers (Rev 2)

unorderedコンテナ同士を、同じかどうか、比較出来るようにする。

N3069: Various threads issues in the library (LWG 1151) (revised)

スレッド間のライブラリの利用における、いくつかの問題を解決。たとえば、複数のスレッドから、ひとつのストリームを読み書きした場合、同期されるのかどうかなど。

N3070 - Handling Detached Threads and thread_local Variables

detachされたスレッドの、thread_local変数のデストラクターが走るタイミングと同期に関する問題の解決。

N3071: Renaming launch::any and what asyncs really might be (Rev.)

名前の通り。launch::anyという名前を、launch::sync_or_asyncに変更する。

N3072: Harmonizing Effects and Returns Elements in Clause 21

stringライブラリの文面が間違っているので、それを修正。

N3073: pecifying Pointer-Like Requirements (Revision 1)

名前通り。ポインターのように振舞う型というrequirementsを定義する。

3074: Updates to C++ Memory Model Based on Formalization

同期まわりの文面の修正。

N3077: Alternative approach to Raw String issues

Raw string literalが、大幅に変わる。

まず、"[...]"ではなく、"(...)"という形に変わる。さらに、Raw string literalは、本当に、Rawになる。つまり、UCNのエスケープシーケンスや、トライグラフ、プリプロセッサの、行末に\を指定することによる、改行の削除の影響すら、受けなくなる。

char const * ptr = R"delimiter(\u1234
\
)delimiter" ;

これは、従来の文字列リテラルでは、

"\\u1234\n\\\n"

と同じである。つまり、UCNも気にしなくていいし、プリプロセッサによる改行の削除の影響も、気にしなくてよくなる。ついに、本当の意味でRawになった。

N3078: Allowing constexpr for reference parameters

constexprな関数の仮引数に、参照を使えるようになった。

constexpr int f( int const & value )
{
    return value ;
}

N3079: Redrafting: issues 667, 861, 990, 818

Issue 667, Issue 990, Issue 818, Issues 861, 919, 920、への解決策。例えば、issue 818については、本の虫: こんな変更ありかよを参照されたし。

N3055: A Taxonomy of Expression Value Categories

N3055: A Taxonomy of Expression Value Categories

lvalueとrvalueが、新たに細分化されてカテゴリ分けされる。

そもそも、rvalueというのは、実際のストレージを持たなくてもいいオブジェクトである。これに対して、rvalue referenceは、実際のストレージが必要である。rvalue referenceを、既存のrvalueという概念に当てはめると、問題がある。

しかし、rvalue、lvalueは、60年代から使われている用語である。その当時からすでに、単なる右辺、左辺という意味ではなかった。

そこで、lvalueとrvalueを、細分化する。

xvalue(eXpiring value)
rvalue referenceに束縛した結果を、xvalueという。これは、eXpiring valueである。rvalue referenceというのは、valueのリソースをmoveするのに使われることから、このように名付けられた。
lvalue
以前と変わらず。
prvalues(pure rvalues)

既存のrvalue、つまり、C++03の意味のrvalueを、prvaluesという。

rvalues

xvalueとprvaluesをあわせて、rvaluesという。

glvalues(generalized lvalue)
xvalueとlvalueをあわせて、glvaluesと言う。

lvalue, rvalueを、左辺値、右辺値などというのは間違っているように、これらは、あえて訳さない方が良い。

これは、新しい機能や概念を導入したわけではない。ただ、既存の概念を、細分化しただけである。

How NOT to write a good javascript code

これでできる! クロスブラウザJavaScript入門:第2回 完全版:ブラウザとデバッグ環境|gihyo.jp … 技術評論社

この記事では、いかにして、バージョンの古いブラウザ環境を構築するかに、紙面の大半を割いている。有害すぎる。

そもそも、バージョンの古いブラウザは、規格を正しく実装せず、必ずセキュリティホールを含んでいるのである。このようなworkaroundは、何も生み出さない。ただ、問題をややこしくするだけである。この記事は、クロスブラウザのための環境構築という大義名分のもと、その実、自分自身が、クロスブラウザに多大な労力をつぎ込まなければならない環境構築の片棒を担いでいるのである。本末転倒も甚だしい。

何のためにWeb標準が策定されているのか。何のために、各ブラウザベンダーは、ブラウザをアップデートしているのか。クロスブラウザなどということを、考えなくても済むようにするためである。この記事は、それらの、より良い未来への努力を、蔑ろにする行為である。もしそれ、真にWebの将来を信じているならば、ブラウザのアップデート方法にこそ、紙面を割くべきである。

今や、ブラウザは、自動的かつ静かにアップデートするのが、主流になりつつある。Chromeは、すでに、この両方を達成している。FirefoxやSafariやOperaやIEは、まだ、ユーザーの許可を求める。これは問題がある。今一歩をあえて進めて、静かにして、かつ、強制的にアップデートするべきである。

クロスブラウザが必要不可欠であるという状況も、変わりつつある。マイクロソフトも、ようやく本腰を上げて、Web標準に追随しだした。現在の発表を信じれば、IE9で、ようやく、他のブラウザの尻に追いつくぐらいのことは、できるだろう。

今や、最大の障害であった、IEですら、変わっていこうとしているのである。それを、このような有害、邪悪な記事でもって、妨げるというのか。

もちろん、実際に、ブラウザのアップデートをしないアホどものために、対応しなければならないという現実がある。それはある。しかし、そのような汚い小手先のworkaroundのための、古い環境の構築方法を公開して、何になるというのだ。

この記事が公開される否や、即座に、はてなブックマークの数字となって、反響が現れていた。そのタグに曰く、「ノウハウ」と。何がHowだ、何が。ユーザーはもとより、Web開発者すら、その心境で、どうしてWeb標準などが普及するというのか。このままでは、Web標準の将来は暗い。

この記事の筆者は、ブログにて、「とくに、Safari/ChromeのWeb Inspector*1や、OperaのDragonflyとかは知らない人も多いと思うので、この機会に試してもらえたら良いなぁと思います。」などと言っている。馬鹿げているにもほどがある。

もし、現段階で、Web InspectorやDragonflyを知らないWeb開発者がいるとすれば、そいつには、開発をさせるべきではない。

嘆かわしいかな、Webの未だにかくあるを。憂うべきかな、ユーザーはもとより、Web開発者の心境すら、旧世紀に異ならざるを。さりとて、吾人、何らの解決策をも持たざるなり。また、やんぬる哉。

こういう記事をありがたがる浅はかなWeb開発者の典型的な例:clear sky source - とてもCSSハックが面倒ですので、何か用意してください

2010-03-29

こんな変更ありかよ

Core Issue 818の解決が、FCDに入るのだが、いやしかしこれは、何の役に立つのだろうか。

template < typename T, typename ... Types >
void f(Types... args, T )


// このコードはill-formed。non-deduce contextのため。
f(0, 0, 0) ;

// FCDにより、well-formedになるコード。
f<int, int, int>(0, 0, 0) ;

ようするに、パラメータパックを、引数リストの最後でなくても、指定出来るようにする変更。ただし、non-deduce contextになる。つまり、argument deductionができないので、明示的に、テンプレート引数を指定してやる必要がある。

何に使うんだろう。こういうことは、できるかもしれない。

// non-deduce contextなので、template parameter packを最後に書かなければならない。
template < typename T, typename ... Types >
void f( Types... , T ) { }

template < typename ... Types >
void g( Types ... args )
{
    f< Types..., int >( args... , 0 ) ;
}

しかし、単に引数の順番という以外の利用方法を、思いつかない。第一、deduceできないのだから、その利用方法が、極端に限られているし、書きにくい。それに、正しいコードを書くためには、argument deductionの、詳細なルールを知っていなければならない。

例えば、以下のコードは、ill-formedである。

template < typename ... Types, typename T >
void f(Types... args, T ) ;

なぜなら、fはnon-deduce contextだからだ。詳しい理由が知りたければ、14.9.2 Template argument deduction [temp.deduct]を熟知する必要がある。こんな微妙すぎる言語仕様、果たして、誰の役に立つというのか。ちなみに、こういうふうに変更した理由は、inconsistentだからだそうだ。いくら言語的にconsistentだとしても、誰も恩恵を受けない言語仕様は、language lawyerはともかく、必要あるのだろうか。

3Dプリンター

すごい時代になったなぁ。

2010-03-28

attributeは難しい

post-Pittsburgh mailingの公開まで、いよいよ日が迫ってきた。FCDが公開されたならば、直ちに変更点を把握して、参考書の執筆を始めなければならない。

ところで、実は、いまもって、よく理解出来ないことがひとつある。attributeだ。

attributeがよく分からない。というのも、あまりにも、記述出来る場所が多すぎるので、一体、どこに書いていいのか、迷うのだ。

たとえば、ある変数に対して、アラインメントを指定したいとしよう。

// 16バイトにアラインメントされてほしい。
char buffer[64] ;

目的は様々だが、とにかく、この変数が、16バイトのアラインメントされていてほしい。では、既存のコンパイラは、どのような拡張機能を提供しているのだろうか。

MSVCの場合、__declspecというキーワードの、一種の、specifierが存在する。以下のように使う。

// どちらも同じ意味。
__declspec( align(16) ) char buffer1[64] ;
char __declspec( align(16) ) buffer2[64] ;

GCCの場合、__alignof__や、__attribute__という、キーワードがある。

// すべて同じ意味。
__attribute__ ((aligned (16))) char buffer1[60] ;
char __attribute__ ((aligned (16)))  buffer2[60] ;
char buffer3 [60] __attribute__ ((aligned (16))) ;

両者とも、何とも、ファジーな文法ではある。

まず、C++0xの、attributeの文法を見てみる。attributeは、実に様々な場所に、記述できる。

[[/* #1 */]] char [[/* #2 */]] buffer [[/* #3 */]] [64] [[/* #4 */]] ;

さて、アラインメントは、どこに記述すればいいのだろうか。

7.6.2 Alignment attribute [dcl.align] p1を読むと、アラインメントのattributeは、「関数パラメーターか、register」以外の(つまり、関数パラメーターや、registerな変数には指定できないという意味)、変数(Variable)か、クラスのデーターメンバー(ただし、ビットフィールドを除く)に指定できる、と書いてある。

この文、非常にわかりにくかったので、わかりやすく改行して引用する。

The attribute can be applied
  to a variable that is neither(i.e except followings)
    a function parameter
  nor
    declared with the register storage class specifier

and(can be applied)
  to a class data member that is not a bit-field.

ということは、一箇所にしか記述できない。すなわち、#3である。

唯一の正しい例は、以下の通りである。

// well-formed.
char buffer [[ align(16)]] [64] ;

以下はすべて、間違った例である。

// ill-formed.
[[ align(16)]] char buffer[64] ;
char [[ align(16)]] buffer[64] ;
char buffer[64] [[ align(16)]] ;

何故か。そもそも、variableというのは、3 Basic concepts [basic] p6に書いてあるように、宣言文によってもたらされる、名前(name)である。ここで、変数の名前とは、bufferである。では、この名前にattributeを指定したい場合は、どこに書けばいいのか。

8 Declarators [dcl.decl] p4に書いてあるように、

noptr-declarator:
    declarator-id attribute-specifieropt

である。つまり、名前の直後に、attributeを指定しなければならない。

この、variable(変数)に対して、指定しなければならないというのは、統一的で、分かりやすい文法である。というのも、C++は、ひとつの宣言文で、複数の変数を宣言できる言語である。

int (*a)(int), b ;

一目瞭然であるが、aは、関数ポインタ型であり、bは、int型である。もし、以下のように、アラインメントattributeを指定できるとしたら、どうにも、言語の文法的に、分かりにくい。

// これはエラー
[[align(16)]] int (*a)(int), b ;

int (*a [[align(16)]] )(int), b [[align(16)]] ;

変数(つまり、変数の名前)に指定するというルールは、文法的には、分かりやすい。ただ、どうも、人間には、わかりやすくないと思う。

int (*a [[align(16)]] [10])(int) ;

まあ、これは、極端な例で、関数ポインタの配列をアラインメントしたいという事は、あまりないだろうが。

基本的に、標準のattributeはすべて、名前に付くとしておけば、とりあえず、参考書の解説としては、分かりやすいだろうか。どうもこの詳細は、参考書で書いても、無駄にページを浪費するだけだと思う。

読み方の分からなかった漢字:蟇

U+87C7、ひきがえる

手持ちの、角川の新字源には載っていなかったので、しかたなく、手書き認識で調べた。

ちなみに、異字体に、「蟆」(U+87C6)という字もあるそうだ。

2010-03-27

中国は、本当にどうしようもないな

中国国内に配置される、DNS ルート・サーバーが閉鎖された? « Agile Cat — Azure & Hadoop — Talking Book

先日、Youtubeや、Wikipediaのドメインが解決できなかった理由というのは、これか。

中国というのは、常に圧政の歴史をたどってきた。西遊記を読めば分かる。西遊記に出てくる妖怪は、時の政府のことである。つまり、西遊記というのは、政府に民衆が立ち向かう話なのだ。これは、司馬遼太郎の言だ。たしか、「街道をゆく」の、どこかに書いてあった気がする。今調べたところ、おそらく10巻だ。

思うに、中国は広すぎるし、多様すぎる。結局、あんな国を、民主主義で治めるのは、無理があるのだ。それゆえ、アカい国になってしまうのである。中国は、ソ連のように分割するべきだと、私は信じる。たとえ、短期的に、混乱があるとしても。たとえ、それによって、経済的にも、人命にも、多大な被害を被るとしても、長期的に見れば、正しい方向であると信ずる。日本も、対岸の火事ではいられない。中国が崩壊すれば、短期的には、直接的にも、間接的にも、不利益を被るだろう。しかし、真に中国の将来を憂えばこそ、中国は崩壊するべきなのだ。

文明の進化神は、一歩も歩みを緩めずして、道に岩石や茨のあるときも、かまわず突破していくのだ。これは、中国が、岩石や茨を、あらかじめ取り除かずに、共産主義という逃げ込んでいたツケである。ツケは、いつか払わねばならない。これは、中江兆民の三酔人経綸問答に書いてある。

現代の陳勝、呉広は、現れるのだろうか。

三酔人経綸問答 中江兆民
街道をゆく (10) 司馬遼太郎

ソニー、ビヨンセの公式YouTubeチャンネルの動画を権利申立により削除する

Of Course! Beyonce's Record Company Puts a Ring On Her Yo... | Motherboard

アホくさいにもほどがある。

それから、Youtubeの埋込みリンクを禁止している動画、あれ、宣伝効果を下げるだけだと思うよ。

いや、もう自分なんぞは、現代の音楽なんて、聴かないから、どうでもいいんだけどね。

videoを利用したパズル

Open Video Sliding Puzzle

videoを利用した、古典的なパズル。

ただし、Firefoxでしか動かない。FirefoxのJavascript拡張機能を使っているのか、あるいは、単に文法エラーなのか。

Chromeでは、配列の範囲エラーになる。Safariでは、setIntervalで、型が違うというエラーがでるが、よく分からない。

これが、実際のライブカメラからの映像を使っていたら、もっと面白いかもしれない。

なぜC++0xの正規表現は、ECMAScript準拠なのか

Boostの正規表現ライブラリで使われている正規表現の文法は、Perl 5を参考としている。一方、C++0xに入る、正規表現の標準ライブラリは、ECMAScript準拠(プラスちいさな拡張機能)である。

オプションで、POSIXのbasic、またはexntended、それに加えて、grepの拡張機能に準拠した文法を使うこともできるが、POSIX規格は、常にLeftmost Longest ruleであり、Non greedy repeatsができないので、grepのようなツールならともかく、プログラミング言語の中で使う正規表現としては、貧弱である。

しかし、TR1は、Boostを参考に作られたはずである。なぜ、違うのか。

Perlの正規表現は、Javascriptプログラマから見ると、少々羨ましい機能がある。特に、independent sub-expressions, zero width look-behind assertions, and interpreted sub-expressionsだ。特に、recursive expressionは、垂涎モノである。

しかし、C++は、Perlのような、具体的な実装ではない。標準規格である。規格である以上、厳密に、正規表現を定義しなければならない。選択肢は、いくつかある。

  1. 正規表現の文法は、実装依存とする。
  2. C++の規格書で、正規表現の文法を、厳密に定義する。
  3. 他の正規表現の規格を、参照する。

1.は、明らかに問題がある。せっかく、正規表現ライブラリがあるというのに、ポータブルに使えないとあっては、だれも使いたがらない。2.は、悪くはない。しかし、正規表現を厳密に定義するのは、かなり時間と労力がかかる。それに、まったく新しい正規表現の文法を定義するというわけでもない。無駄である。

とすると、3.の、他の規格を参照するのが、最も現実的な選択である。では、どの規格を参照するのか。

といっても、実は、しっかりした正規表現の規格というのは、ふたつしかない。POSIXのbasicとextentedか、ECMAScriptである。

Perlはどうなのか。Perlは、厳密な規格というものが、存在しない。それに、Perlの正規表現は、言語機能として組み込まれていることを前提としている。ライブラリベースの実装である、C++には、不向きである。それに、Perl6では、正規表現がガラリと変わる。

そういうわけで、C++0xには、ECMAScript準拠の正規表現が、採用された。

n1429: A Proposal to add Regular Expressions to the Standard Library

Variadic Template Parameterの落とし穴

Variadic Template Parameterの型引数のことを、テンプレートパラメーターパック(Template Parameter Pack)という。

template < typename ... Types >
struct Foo { }

ここでは、Typesは、テンプレートパラメーターパックである。

テンプレートパラメーターパックを、関数の引数に取る場合、これを、パラメーターパックという。

template < typename ... Types >
void f( Types ... args ) { }

ここでは、argsは、パラメーターパックである。

クラステンプレートの場合、テンプレートパラメーターパックは、必ず、テンプレートパラメーターリストの最後に書かなければならない。

// well-formed
template < typename T, typename ... Types >
struct well_formed ;

// ill-formed
template < typename ... Types, typename T >
struct ill_formed ;

これは、テンプレート実引数を指定しても、曖昧になるからである。

関数テンプレートのテンプレートパラメーターリストの場合には、そのような制限はない。なぜならば、関数テンプレートは、引数をdeduceできるからである。ただし、パラメーターパックは、関数のパラメーターリストの最後でなければならない。

// well-formed.
template < typename ... Types, typename T >
void well_formed( T, Types ... ) ;

// ill-formed.
// パラメーターパック、Typesは、パラメーターリストの最後にしか書けない。
template < typename ... Types, typename T >
void ill_formed( Types ..., T ) ;

これができれば、実に、メタプログラミング的な意味で、便利なのだが、残念ながら、これはできない。

ちなみに、こういう事はできる。これは、パラメータリストの型ではなく、パラメーターの型の一部だからである。

template < typename ... Types1, typename ... Types2 >
void f( void (*p1)( Types1 ...), void (*p2)( Types2 ... ) )
{
    // それぞれ、引数の型のデフォルトの値で呼び出す。
    p1( Types1()... ) ;
    p2( Types2()... ) ;
}


void g( int, int, int ) { }
void h( float, float ) { }


int main()
{
    f( &g, &h ) ;
}
// 呼び出すためだけの関数。
template < typename ... Types >
void call( Types ... ) { }

// 任意の戻り値を持つ関数ポインタを、任意個引数にとる。
template < typename ... Types >
void f( Types (* ... t)( void )  )
{
// 関数の実引数の評価順序は、定義されていない。
// どの順番で、引数の関数が呼び出されるかは、実装依存である。
// ただし、すべての関数は、呼び出される。
    call( t()... ) ;
}

int g( void ) { std::cout << "g" << std::endl ; return 0 ; }
int h( void ) { std::cout << "h" << std::endl; return 0 ; }


int main()
{
    f( &g, &h, &g, &h, &g, &h ) ;
}

このcall()関数はネタであって、普通の場合は、以下のような関数を書いた方が良い。

template < typename T >
void call( T t )
{
    t() ;
}

template < typename T, typename ... Types >
void call( T t, Types ... args )
{
    t() ;
    call( args ... ) ;
}

template < typename ... Types >
void f( Types (* ... t)( void )  )
{
    call( t... ) ;
}

これを組み合わせると、

template < typename ... ReturnTypes, typename ... ParameterTypes >
void f( ReturnTypes (* ... t)( ParameterTypes... )  ) { }

int g( char, short, int, long, float, double ) { return 0 ; }


int main()
{
    f( &g, &g, &g, &g ) ;
}

もちろん、これは、ジェネリックではない。しかし、この記述は、引数にとるすべての関数ポインタが、同じシグネチャであることを保証できる。普通のプログラマは、こう書けば良い。

template < typename ... Functors >
void f( Functors ... functors ) { }

2010-03-26

マナーのあるリンクの貼り方

マナーのあるa elementの書き方

<a href="http://www.nikkeibp.co.jp/article/column/20100319/216823/" rel="nofollow">マナーのあるメールの書き方 | キャリワカ:コミュニケーション | nikkei BPnet 〈日経BPネット〉</a>様。

リンクは、様をつけましょう。また、目上のリンク先には、rel="nofollow"をつけるのが常識です。

その例

マナーのあるメールの書き方 | キャリワカ:コミュニケーション | nikkei BPnet 〈日経BPネット〉様。

サウスパーク:スコッティ・マクボーガボールのお話

The Tale of Scrotie McBoogerballs

今回の話は、解説の必要を感じたので、背景を説明しておく。

今回の話の根底にあるのは、The Catcher in the Rye(邦訳:ライ麦畑でつかまえて)という、有名な本である。おそらく、名前ぐらいは、誰でも聞いたことがあろうだろう。

「ライ麦畑でつかまえて」は、いわくつきの本である。というのも、この本に影響されて、殺人を犯したといわれている殺人事件が、複数あるからである。

1960年のこと、ある学校教師が、生徒に、この本を読ませたところ、生徒のひとりに、射殺された。

それだけではない。John Lennonを殺した、Mark David Chapmanや、Ronald Reaganを殺そうとした、John Hinckley, Jr.、はては、Rebecca Schaefferを殺したRobert John Bardoまでもが、この本に影響されたと、語られている。

そのような経緯によって、この、「ライ麦畑でつかまえて」という本は、アメリカの多くの図書館、学校で、禁書となっているのである。

今回のサウスパークでは、それを茶化している。つまり、本が、筆者の意図を離れて、拡大解釈されていくのである。心理学には詳しくないが、バーナム効果という概念も、あったりする。人は、曖昧で抽象的な言葉を、勝手に都合よく解釈してくれるのである。世の中に、詩人というものが流行るのは、このせいだろう。

しかし、真面目に考えれば、「ライ麦畑でつかまえて」という本が、殺人衝動を引き起こすはずがない。禁書というのは、えてして、このように馬鹿げたものになるのである。

実は、私は、「ライ麦畑でつかまえて」を読んだことがない。せっかくなので、時間があれば、原書を読んでみようかと思う。

キャッチャー・イン・ザ・ライ
ライ麦畑でつかまえて (白水Uブックス)
The Catcher in the Rye

2010-03-25

Photoshopの信じられない新機能

この動画は面白い。

ハァァァッ! マジで?

AdobeのCreative Suite 5は、これができるらしい。

GIMPのプラグインも、できるとか。

Photoshop's CAF (content-aware fill) - unbelievable? Not quite. - the real Uqbar

こういうアイディアもある。

どうも、この手のアルゴリズムは、結構研究されているらしい。私が知らなかっただけか。いや、それにしても十分に発達した科学は何とやらだ。

べつやくれいが真面目な絵を描いた!

@nifty:デイリーポータルZ:「花見過ぎ」をしよう

おお、べつやくれいが、真面目にデッサンした絵を、初めて見た。

Wikipediaが見れない

どうも、DNS関係だろうか。nslookupしても、ja.wikipedia.orgが解決できない。

P2Pと帯域とBitTorrent DNA

[お知らせ]4月1日よりBitTorrent DNAクライアントの利用を停止します。 zoomeインフォメーション - 動画共有サイトzoome

インターネットで、帯域というのは、頭の痛い問題である。近年、インターネットで動画を公開するのは、当たり前になっている。私は、音声や動画というものを、特別視してはいない。画像と同じくらい、自然に表示されるべきだと考えている。今日、誰も、Webサイトが画像を使っていると文句をいうものはいない。とすれば、動画だって、自然に使われてしかるべきだ。

しかし、現時点では、まだ、動画は、ディスク容量と帯域を、大幅に消費する。まだ、画像と同じぐらい、自然に使うことはできないのである。

日本は、世界でも有数の、bpsあたりの価格の安いネット回線が、提供されている国である。せっかくの広帯域を、使えぬとあっては、宝の持ち腐れである。

ここで、P2Pという仕組みが出てくる。エンドユーザー同士は、それなりの帯域を持っているのだから、それをお互いに使おうという考え方である。

zoome.jpは、動画をアップロード、公開できるサービスを提供しているWebサイトであるが、帯域を節約するため、Bittorrent DNAを用いていた。

BitTorrentは、数あるファイル共有用のP2Pプロトコルの中でも、一番問題のないプロトコルである。Winnyのプロトコルの何が問題かというと、自分の意図しないファイルを、送信可能にしてしまうことである。それは、Winnyのプロトコルの仕様である。ネットワーク上に、ひとりでもバカがいれば、全員とばっちりを食う、実によろしくないプロトコルになっている。

BitTorrentプロトコルには、そのような問題はない。それゆえ、Operaは、BitTorrentプロトコルをサポートしているし、一部のゲームは、BitTorrentプロトコルをつかって、アップデートパッチを配信している。多くのLinuxのディストリビューションのISOイメージは、BitTorrentで配布されている。

BitTorrentプロトコルは、結構、面白い仕組みになっている。ファイルというか、データというか、とにかく、ダウンロードする一塊のデータを、細かく区切る。そして、最も皆が持っていないピースを、優先的にダウンロードしようとする。

もちろん、実際の仕組みは、もっと複雑である。ここでは、BitTorrentは、単なるプログレッシブダウンロードではないということを、示したいのである。

ところで、BitTorrentは、別にトラフィックを有効的に使ったりはしていないのである。むしろ、その逆で、エンドユーザーがアップロードする分、全体的に見れば、トラフィックを余計に増やしているのである。

ところで、動画のストリーミング再生というのは、広帯域を必要とする。一サーバーとしては、負担を減らすために、BitTorrentの力を借りたいところである。ところが、動画のストリーミング再生というのは、プログレッシブダウンロードを必要とする。そうでなければ、ダウンロードしつつ再生ということができない。

BitTorrent DNAは、主に、こういったストリーミング用途に最適化したBitTorrentプロトコルの実装で、ブラウザのプラグインという形で、提供されている。

zoome.jpのBitTorrent DNAの使用は、なかなか興味深かったが、結局、廃止されたようだ。理由は、実装が不安定ということらしい。

帯域の問題は難しい。マイナーなWebサイトである、zoomeだからこそ、BitTorrent DNAを使用できるのである。もし、ニコニコ動画が、BitTorrent DNAを利用しようとすれば、日本のインターネットは、崩壊する。

これはどういう事かというと、ニコニコ動画の帯域使用量は、もはや、いくら金を積んでも、増やせないレベルになっている。いまは、ISPと相談して、今月は、このくらい帯域を使おうなどと取り決めているらしい。ニコニコ動画が、無分別に帯域を使い出すと、日本のインターネットが崩壊する。

したがって、ニコニコ動画が、無駄にトラフィックを増やす、BitTorrentプロトコルを使えるわけがないのである。

これを解決するにはどうすればいいのか。思うに、マルチキャストができればいいのではないかと思う。今は、サーバーは、データを要求するホストひとつひとつに、それぞれデータを送信しているわけだ。マルチキャストがあれば、サーバーが送信するデータは、ホストひとつ分でいい。ISPが、必要なホスト全部に、あたかも、サーバーが全員に送信したかのように、送信してくれる。

これは、実に理想的だ。マルチキャストさえあれば、トラフィックは減らせる。問題は、マルチキャストには、ISP側の協力が必要だ。全体的にトラフィックが減るとしても、ISPの負担は増える。どのISPも、そんな余計な負担をしたがらない。結果として、マルチキャストはサポートされず、我々は未だに、個別にユニキャストしているのである。

私は、マルチキャストがないからこそ、BitTorrentのようなプロトコルが流行っていると思うのだが、なかなか、うまくいかないものだ。

追記:あるいは、現在、数MBの画像ファイルを使うのが、全く問題なくなったように、将来的には、数百MBから数GBの、動画ファイルを使うのも、問題なくなるのかもしれない。

しかし、我々は、常に、「今使える技術」を欲しているのである。「来年使える技術」は、意味がない。今使えないのだから。

自主規制の不思議さ

アメリカで、Public Optionの法案が通った際、Joe Bidenという議員が、"This is a big f---ing deal!"と、ささやいたらしい。アメリカのテレビは、この失言に対して、BEEP音をかぶせて、自主規制した。議員が失言したことは伝えるのに、なぜ、肝心の言葉を、自主規制するひつようがあるのだろうか。

Fで始まるこの言葉は、単なる発音に過ぎない。日本では、単なる発音にBEEP音をかぶせて隠すということは、聞いたことがない。唯一聞いたことがあるのは、「さあ、CMの後で、後驚きのXXXが! チャンネルはそのまま」といった、演出でしか、BEEP音を聞いたことがない。

たとえば、国家機密の情報を報道統制するとか、そういう類ではなくて、このような、特定の単語を消すのは、どうも、日本人としては、理解できない。

もちろん、日本でも、テレビで使えない言葉というのはある。私が思うに、その多くは、別に使っても問題ない言葉であると思う。「かたわ」というのと、「身体障害者」というのと、「フィジカリー・チャレンジド(神から肉体的に試練を与えられた)」というのに、何の違いがあるというのか。最近では、障害者や便所という言葉すら、差別用語だと言われる始末である。これらは、法律にも使われている言葉だというのに、何が問題なのだろうか。

これによってこれを思うに、使い慣れた言葉は、差別であると感じるのであろう。つまり、「お前」とか、「貴様」というのが、本来は尊敬の意味を含む代名詞であったのに、あまりに頻繁に使われた結果、尊敬の意味がうすれてきて、「あなた」という、本来、人称代名詞ではない言葉を使うようになったのも、そのためであろう。

とするならば、今尊敬の意味を込めて使われる言葉も、後の世には、侮蔑の言葉と成り下がる恐れがある。我々は、一刻も早く、新たな代名詞を、どこかから借りてきて、人称代名詞にしなくてはならぬ。YOU早く新しいWORD見つけちゃいなYO。

それはさておき。

このニュースを聞いたものは、誰でも、Fから始まるこの言葉が何であるのか、すぐに分かるはずである。では、なぜ隠す必要があるのか。

日本のテレビでは、たとえ政治家が放送禁止用語を漏らしたとしても、それを報道する際に、このように露骨にBEEP音をかぶせてまで、消そうとはしないだろう。

例のごとく、この疑問を、IRCでアメリカ人にぶつけてみたところ、彼らは、次のように聞き返してきた。

我々は皆、チンポがどういう形をしているか知っている。なぜ日本は、自主規制するのだね。我々は特定の単語の音を自主規制し、片や日本は、チンポを自主規制する。同じではないのかね。

確かに、なぜ、日本では、局部にモザイクをかけなければならないのか、私には分からない。何となれば、我々が皆、必ず持っているモノではないか。

しかし、もはや、日本の自主規制は、意味が無くなっていると、私は思う。今や、日本のポルノ制作会社は、海外にダミー企業を設立し、サーバーも海外に設置して、グレーだが、日本に無修正のポルノを提供しているのである。こうなってしまっては、もはや、国内の法律は、あまり役に立たない。確かに、実質は日本人によって行われているので、国内では、摘発される恐れがある。しかし、これを摘発するのは、他国の警察や司法と、連携する必要がある。とても面倒なので、児童ポルノなどの、他国も同意してくれる、よほどの理由がなければ、現実的に、摘発できないのである。

今や、我々は、インターネットのおかげで、自国の自主規制から、逃れることができたのである。Thanks Internet!

ところで、ひとつ思うことがある。このような自主規制を強いるのは、制約である。我々は、このような制約から、出来る限り、解放されるべきである。しかし、思うに、この日本の、局部にモザイクをかけなければならないという制約、果たして、悪ばかりだと言えるだろうか。

実は、日本のポルノは、そのあまりにも馬鹿げた企画力により、海外から、高い評価を受けている。具体的なリンクを貼るのは、差し障りがあるので避けるが、我が日本国には、実に馬鹿げたポルノが、大量に出回っている。思うに、モザイクを掛けなければならないという制約が、このような、変な方向性を生み出したのではなかろうか。

エロゲもそうだ。エロゲは、単なる絵に過ぎない。絵であるのに、何で局部にモザイクが必要なのだろうか。表現の自由に対する、憂うべき制約である。しかし、仮に今、エロゲのモザイクがなくなったところで、より良いエロゲが生まれるとも思わない。

たとえば、かつて、学帽というものがあった。日本の学生は、皆、この安っぽいダサい帽子をかぶって、学校に通っていたのである。この、決まりきったダサい帽子をかぶらなければならないというのは、制約である。では、現実は、どうなっただろうか。

当然、日本の学生は、皆、この学帽という制約が気に入らなかった。それゆえ、皆、この学帽の改造に苦心したのである。

これは、現代の学校の制服にも、言えることである。日本の制服は、大して質も良くないのに、ボッタクリ価格である。よほど大きな利権があるのであろう。もし、日本の教師たちが、真に学生の服装の乱れを正したいとするならば、直ちに制服を廃止するべきである。馬鹿げた制約がなくなれば、馬鹿げた改造もなくなるというものだ。

この制約というものは、単に規制に限らない。たとえば、音楽は、近年、DTM機材の性能向上に伴ない、はるかに制約がなくなった。もはや我々は、鍵盤のような物理的な装置に頼って、音楽を演奏する必要はないのである。ゲームコンソールでも、ファミコンやスーファミのような、FM音源から、今や、PCM音源である。もはや、FM音源のような制約は、存在しないのである。歌もそうだ。最近は、音程をリアルタイムで自動的に調整する機械まであると聞く。

では、音楽は、昔に比べて、はるかに優れたものになったかというと、どうも、そうは思わない。

インターネット自体もそうだ。今や、ネコも杓子もブロードバンドである。何百MBものファイルサイズの動画をアップロードして、わずか数分で全世界に公開するのは、至極当然である。では、インターネットは、10年前と比べて、はるかに優れたものになっただろうか。

この、制約の中で生まれる芸術というのは、実に興味深い。誰か、詳しく研究していないものだろうか。

2010-03-24

奇妙な夢を見た

我々は、ある会議室で、C++について論じていた。とうとう、FDISが出たのである。ようやく制定された規格書は、何故か、複雑な状態遷移図のようなものが、びっしりと書き込まれていた。これを読みとくのは骨が折れる。

議論の後、我々は、呑みに行くことになった。私は、何か他の用事で、一体部屋を出た。用事を済ませて、部屋に戻ってくると、そこは、すでに会議室ではなかった。

部屋の中には、何故かフル武装した自衛隊員がいて、猛烈に訓練をしていた。これは一体どういう事か。さっきまで議論していた人たちは、どこへ行ったのか。

私は、部屋を間違えたのかもしれぬと考え、隣の部屋を覗いてみた。そこでも、やはり、よく鍛えられた自衛隊員が、訓練をしていた。どういうことだろう。

まあいい、とりあえず、駅に行けば、なんとかなるだろう。どうせ、彼らも駅前にいるに違いないと考えた。駅名は、何故か、ロシア駅であった。私は、ロシア駅という名前については、何の疑問も生じなかった。

さて、「ロシア駅」に着いたが、彼らは見つからなかった。私は、携帯電話を全く使わない主義なので、携帯のアドレス帳に、彼らの電番号やメールアドレスは、入っていない。途方にくれていると、ふと、ある地べたに座っている集団が目についた。見覚えのある顔だ。何と、彼らは、私の小学生時代の級友であった。

級友等とは、小学校以来、全く会っていないはずである。しかし、その顔は、見覚えのある顔であった。なぜここに座っているのだろう。我々は、しばらくの間、久闊を叙した。

さて、再び、駅前をうろついていると、とうとう、仲間と再開した。彼らは五、六人ぐらいいて、その中に、イケメンのアキラさんと、マッチョなメルポンさんもいた。

私が、「呑みに行く店は、もう決まっているのか」と訊ねても、彼らは、「決まってる、決まってる」というだけで、なんという店かは、答えてくれなかった。

我々は、ある建物の階段を上がっていった。その階段は、やたらにせまく、人がひとり通るだけで精一杯であった。しかも、なぜか、途中で何回も、左右に分岐していた。

私は、前の人を見失わないようについていった。階段は、分岐するたびに、左右の壁が、狭くなっていった。もはや、体をヨコにしなければ、通ることすらできない。果たして、マッチョなメルポンさんは、通り抜けることができるのだろうかと、心配した。

階段の左右の壁は、いよいよ狭くなってくる。もはや、肋骨がつかえて、進むことができぬ。いよいよ進めないと諦めかけたときに、ようやく、目的の店についた。

その店は、こぢんまりとした小さな部屋であった。床の間に、座布団を引いて、ひとりの婆が正座していた。

「いらっしゃい」

(いや、「いらっしゃい」どころではないだろう。何なのだこの階段の作りは)と思いながら、部屋を見回すと、こたつがひとつ、備え付けられていた。イケメンのアキラさんは、涼しげな顔をして、すでにこたつに入っていた。

私も、こたつに腰をおろした。狭い階段をくぐり抜けてきたせいか、やたらと暑い。私は、外套を脱ぎ、トレーナーを脱ぎ、さらに、セーターを脱いだ。こんなに狭い通路を通るのだと知っていれば、こんなに厚着してこなかったものを、と不満に思った。

マッチョなメルポンさんは、いつまでたっても、上がってこなかった。

みると、先程の、床の間の婆は、いつのまにか姿を消していた。こたつの上には、いつの間にか、土鍋と食材が置かれている。と思うと、いつの間にか、こたつに、婆と爺が座って、世間話をしていた。

爺「やれやれ、最近は、こんな変わった店じゃないと、客も来やしない」
婆「いや、これでもさっぱりだよ。やっぱりあれだね。儲けようと思ったら、こんな商売じゃなくて、楽器の教室の先生をするに限るね」
爺「どんな楽器だい」
婆「シンバルだよ」

果たして、シンバルの演奏法を専門に教える教室の需要はあるのだろうか。

と、ここで目が覚めた。

私は、トレーナーとジーンズを着込んだまま、布団にくるまって、壁際で寝ていた。枕元には、D&Eと、C++ Templatesと、柳田国男全集が、読みかけで開いたまま、置いてある。変な夢の原因は、これらだろう。

あれだけ長い夢を見たと思ったのに、時間は、22時である。なんと、たったの数時間しか、うたた寝していなかったと言うのか。一炊の夢とは、よく言ったものだ。

2010-03-23

東京都は『古事記』を有害図書に指定しよう!

東京都は『源氏物語』を有害図書に指定しよう!:日経ビジネスオンライン

有害図書である。なるほど、うまく考えたものである。かつて、我が日本国政府は、ヰタ・セクスアリスや、チャタレイ夫人の恋人を、発禁処分にしたところ、大きな批判を受けた。表現の自由、言論の自由に対する、大いなる違反であるとの批判である。

発禁処分はまずい。なにより、名前がよろしくない。では、有害図書という名前にしよう。これは一見、ゾーニングに見えるが、その実、現実的に、表だった流通には載せられないようにすることである。本当に、よく考えたものである。そのド低脳クサレ脳みそで、よくぞ思いついた。

よく、源氏物語は、ローティーンの紫の上を誘拐、監禁し、自分好みに調教した物語を含むので、まさしく有害図書であるという批判を耳にする。しかし、源氏物語の如きは、古事記に比べれば、全然、有害でもなんでもないのである。

イザナキ君とイザナミちゃんによる、国生みの次第は、非常にわいせつである。

まず、彼らは、オノゴロと呼ばれている島に、神の眷属である利権を利用して、天下るのである。私はデタラメを言っているのではない。ちゃんと、原文に書いてある。

其嶋天降坐而見立天之御柱見立八尋殿

しかも、天下るどころではない。天の御柱や、八尋殿といった、ハコモノを建造するのである。しかもこのハコモノは、自分たちだけで使うために、立てたのである。まったくもって、税金の無駄遣いである。

そして、その八尋殿という名前が示すように、広大な屋敷に入って、まず行ったことは、極めて猥雑なる行為である。

イザナキ「お前の体はどうなっているのだ」
イザナミ「穴がひとつあいている」
イザナキ「俺の体は、ひとつ余計なモノがついている。こいつをどう思う?」
イザナミ「すごく・・・大きいです・・・」
イザナキ「大きいのはいいからさ。こいつをお前の穴に差し入れて、やらないか?」
イザナミ「アーッ!」

このような次第を経て、我が日本国は生まれたのである。

これだけではない。古事記では、この後も、延々とヤリまくる記述が続く。ついには、ヤリ過ぎて、イザナミは死んでしまう。

イザナミ亡き後、イザナキはどうしたか。型の如く喪に服したか。否、彼は、宗教でいうところの、いわゆる黄泉国に行って、イザナミを生き返らせようと試みるのである。

これは、青少年の健全な育成に対して、非常なる害悪である。このような記述は、「人が死んでも、黄泉国に行けば、また会えるから問題ない」という思想を生む恐れがある。このような軽率な物語があるからこそ、命の大切さが分からない若者を増やすのである。

さて、イザナキは、黄泉国にいるイザナミに会いに行く。イザナキが黄泉国を訪問したとき、イザナミはちょうど、触手プレイと獣姦に勤しんでいたが、その現場を見られたために、イザナキを殺そうとする。イザナキは、ほうほうの体で、逃げ出す。なんとかおってから逃れられるが、その時にかわした会話は、残酷極まりないものである。

イザナミ「むしゃくしゃするから、これからは、一日に千人ぐらい、無差別に殺す」
イザナキ「じゃあ俺は一日に千五百人、妊娠させるから無問題」

これを読んでなお、命の尊厳を知る若者があるだろうか。

その他にも、アマテラスとスサノヲの近親相姦や、スサノヲが巫女のマンコを串刺しにして殺す話、アマテラスのヒキコモリ、アマテラスを部屋から出すために、売笑婦を雇って、裸踊りをさせたのだのと、猥雑かつ非倫理的な話は続くのである。

それが終われば、今度は、恐れ多くも、御門の祖先のお話になる。ここで、帝は、もったいなくも御顔にタトゥーを彫り、毎日のように、女をナンパ遊ばされるのである。女は、いずれも、掛けまくも忝なく、龍顔に咫尺して、甚だしきは、「もっと寝ろ」という意味の露骨な詩を歌うものまで現れる始末。

一体我々は、古事記のような有害図書を、野放しにしてよいものか。

ある者は言う、「古事記は難しいから、青少年は読まないだろう」と。これは、青少年の読解力を、過小評価しすぎである。

なぜならば、この私は、小学生の時に、古事記を読破していた。しかも、相当エロい話であると、当時から思っていたのである。私が、小学生の時に読んだ、他の小説、たとえば、足の爪を剥がしたことを利用して、女医の乳房を盗み見る、「赤頭巾ちゃん気をつけて」だとか、双子と3Pする、「1973年のピンボール」だとか、あるいは、ド田舎に隔離された挙句、砂まみれになって女と交わる、「砂の女」だとか、猫の鳴きまねをするよう調教された未成年と乳繰り合う、「密会」と比較しても、古事記の方が、断然エロかった。

自白するが、私はこれらの小説を、小学生の時に、すでに読んでいた。つまり、これらの本は、実際に、小学生が目にする恐れのある本である。

ところで、世の中には、障子を勃起した陰茎で破る、「太陽の季節」とかいう小説があるそうだが、これは、特に、有害図書にして、規制する必要はないと思う。というのも、私は小学生当時、そんな本の存在は知らなかった。たしか、太陽族という言葉は、物の本で読んだ覚えがあるが、すぐに消えた数あるバカバカしい流行のひとつに過ぎない。一方、私が小学生の頃に読んだ、上記の小説は、現在でも有名で、全国、どの書店でも売っているであろう、上記の小説に比べれば、「太陽の季節」なんて、どこで売っているのかすら分からないマイナーな本なので、あえて規制する必要もないだろう。事実、私はいまだに、「太陽の季節」は読んだことがない。

追記:小一時間ほどググッた結果、ようやくアマゾンで、「太陽の季節」の、中古品を見つけることができた。値段は、1円である。1円ぐらいの価値はあるらしい。1955年当時の1円だろうか。

太陽の季節 (新潮文庫)

古事記 (岩波文庫)
赤頭巾ちゃん気をつけて (中公文庫)
砂の女 (新潮文庫)
密会 (新潮文庫)

QuirksBlog: CSSベンダープレフィクスは邪悪だ

QuirksBlog: CSS vendor prefixes considered harmful

先日、IEチームのborder-radiusに関する記事を読んだ。IE9は、border-radiusをサポートする(スゲェ!)そうだし、ベンダープレフィクスはつけないそうだ(かっけー!)

記事曰く、

多くのページが、既にこの機能を用いているが、いくつかは、(省略)、IE9やOpera 10.50では、うまく描画されない。なぜならば、プレフィクスなしのborder-radiusプロパティが、使われていないからだ。

規格が、「推奨」状態に近づくにつれ、ブラウザベンダーは、実装を煮詰めてテストを繰り返し、W3Cに意見を出す。新しいコンテンツは、border-radiusに、ベンダープレフィクスを使わないよう、我々として、強く推奨するものである。

俺としては、さらに一歩を推し進めたいね。

いい加減、ベンダープレフィクスは、廃止するべきだ。こいつは、本来、存在しない問題を解決しようとしているようなものだし、Web標準にとって、害悪だ

ベンダープレフィクスは、Web開発者をして、スタイルシートをより冗長にさせるのみならず、ベンダープレフィクスを付け忘れるという、本末転倒のリスクすら生み出すのだ。

だいたい、たったひとつの効果をだすのに、なんで複数の宣言が必要なんだよ。Web標準ってのは、そういうのを防ぐためにあるんじゃないのか?

テメーら、さっさとクソみそなベンダープレフィクスとやめやがれ。いい加減にしろ、もうたくさんだ。このド低脳がッ!

論点

本来、ベンダープレフィクスの目的は、ブラウザが、実験的なCSSを実装できるようにするためのものだった。

たとえばだな。W3Cワーキンググループは、grid宣言を考案している。これは、そんなに悪いアイディアじゃあない。んで、誰かがドラフト規格を作ったとしよう。でも、ある者は、一部の詳細に、反対していたとする。つまり、規格化には、時間がかかるのだ。

で、今仮に、マイクロソフトが、現在のgridの提案に従って、実験的な実装を試みたとしよう。現時点では、マイクロソフトは、規格が変わらないかどうか、定かではないわけだ。そういうわけで、CSSにgridを付け加えるのではなく、-ms-gridを付け加える。

訳注:つまり、これによって、規格が変更されることによる、互換性の問題を回避できる。

とまあ、ここまでは、悪くない考えだ。だが、これは実際、何の役にも立たなかった。実際、もうこんなのは、要らないのだ。現実的に考えても、思想としてもだ。

現実的な問題

まあ、現実的な例というものを見てみよう。

box-sizing

ベンダープレフィクスがクソみそになってる例のひとつってのが、box-sizingプロパティだ。これは、box modelを変更できる機能なんだがな。現時点では、IE8とOperaが、box-sizingを、プレフィクスなしでサポートしている。だが、Firefoxは、-moz-box-sizingしかサポートしてやがらねぇし、SafariやChrome、それとモバイルWebkitは、-webkit-box-sizingしかサポートしてねーんだ。

div.borderbox {
    box-sizing: border-box;                       /* one */
    -moz-box-sizing: border-box;              /* two */
    -webkit-box-sizing: border-box;          /* three */
}

ひとつの効果を出すために、みっつもの宣言を使わなきゃならんのは、あまりにも馬鹿げてる。ブラウザ戦争の再来か? 標準? なにそれおいしいの?

ここでの問題点は、box-sizingは、これ以上、変わりようがないってことだ。目的は、box modelの変更だし、その値である、border-boxとcontent-boxは、どこでもサポートされてる。

この宣言は、非常に単純明快だし、すべてのブラウザで、この通りにサポートされている。だったら、すべてのブラウザで、同じ名前であってしかるべきだろ。

W3Cが認可のハンコ付くまで、プレフィクスを外すのをボケーっと待ってるつもりか? それにゃ、あと5年か10年はかかるぜ、ドアホが。

Mozilla、Webkit、お前らド低脳とちゃうか? さっさとベンダープレフィクス消しやがれダボが!

transition

Safariの追加したtransitionについて。-webkit-プレフィクスをつけにゃならん。Safariチームは、これらの宣言の機能を、明確に定義している。これ以上、もう変わりようがないのだ。

GoogleとOperaも、transitionを実装している。俺は、AppleOperaのドキュメントを見てみたが、いずれも、非常に良く似ている。実際、俺が思うに、OperaはAppleのtransitionをパクったと言っていい。

しかしながら、Appleは、-webkit-transitionを使っていて、Operaは、-o-transitionを使っている。

テメーら・・・

div.coolEffect {
  -webkit-transition-property: opacity;    /* one */
  -webkit-transition-duration: 2s;
  -o-transition-property: opacity;        /* two */
  -o-transition-duration: 2s;
  -moz-transition-property: opacity;          /* three */
  -moz-transition-duration: 2s;
  -ms-transition-property: opacity;        /* four */
  -ms-transition-duration: 2s;
}

なんで、たったひとつの効果を出すのに、四つもの宣言を使わなきゃならねーんだ。てめーら、頭脳がマヌケか? この手のアホくさいベンダープレフィクスを回避するために、Web規格があるのだろうがよ。わざとバラバラになってどうするってんだ?

Web開発者が、たまたま、ベンダープレフィクスをつけ忘れたら、どうなる? 本来動くべき効果が、動かないじゃないか。それは、標準規格が存在しない世界の話だぜ。少なくとも、俺らの話じゃねーよな? な?

いい加減にしろよ。ベンダープレフィクス爆発しろ。

未来への遺産

もっともアホくさい例は、モバイル環境にある。Operaは、タッチスクリーン メディア クエリーを、ボーダフォン ウィジェット マネージャーに実装している。-o-touchscreenだ。

後に、サムソンがWebkitベースのウィジェット マネージャーに取り掛かった時、このメディア クエリーの存在に気がついて、そっくりそのままパクった。それも、文字通りの意味でだ。

そんなわけで、今、-o-touchscreenに反応するWebkitブラウザがあるわけだ。

これは単なる始まりに過ぎないんだぜ。問題は、ますます悪くなるばかりだ。

実際、多くのサイトが、-webkit-transitionだけをつかっていて、-o-transitionを使っていない。とするとだな、Operaは、-webkit-transitionもサポートするべきなのか?

互換性という点から考えると、当然、サポートするべきだ。互換性を抜きにすると、アホの極みというしかないんだがな、これが。もっと単純な解決方法があるんだぜ。transitionは、Webのデファクトスタンダードになってるわけだ。だったら、最初から、ひとつにすりゃいいじゃねーか。

テメーら、さっさとベンダープレフィクスをやめやがれ、こんちくしょう。

思想的な問題

というわけで、現実的な視点からみると、ベンダープレフィクスは、単にバラバラになっただけだ。思想的な視点からみても、同様に、本来存在しないはずの問題を解決しているわけだ。

つまりだ。ベンダープレフィクスっていうのは、二つの問題を解決しようとしていたわけだ。

  1. すでに述べた、まだ完成していない標準に対する問題
  2. その問題に対する、根本的な問題。ブラウザベンダーが、他のブラウザの実装を気にせず、自由に自分の実装を始められるようにすること

俺が思うに、どちらの問題も、すでに解決されている。

現在、二つのブラウザで実装されている機能は、自動的に、標準になるという状況になっている。W3Cは、まだこの規格化のプロセスを受け入れていない(たぶん、一世代待つ必要があるだろう)が、実際、これは事実である。

この仕組みが動く理由というのは、今や、ブラウザベンダーは、お互いの実装をパクり合おうとしているからだ。Microsoft、Mozilla、Apple、Google、Operaは、お互いに、他社のブラウザを観察して、お互いを、標準として認めている。競争しているのは、パフォーマンスや、小奇麗なUIや、標準に対する拡張機能だ。

ベンダープレフィクスが制定された時代、つまり、ブラウザ戦争が起きていた時代とは変わって、現代では、ブラウザベンダー達は、移植性を気にしている。もはや、彼らが荒れ狂う恐れはないし、box-sizing: border-boxの意味が、「borderの内側の何か」に変わることは、あり得ない。そのような事は、現代では、まともではなくなっているのだ。

Safariチームは、クールなtransition機能を発明した。彼らは、CSSベースで実装し、ドキュメントを書き、W3Cに提出した。これは、素晴らしいことだ。

そして、彼らは、-webkit-プレフィクスを追加した。クソだ。

さて、今、Operaがやってきて、transitionをサポートしたいと考えている。Operaは、独自機能を発明するのか? Operaは急に、現在のSafariのとは全く異なる、互換性の全然ない別のtransitionを実装するのか?

そんなことが起こるはずがない。Operaの連中はバカではない。彼らは、互換性の重要性を、十分に承知している。他のブラウザベンダーも、皆同じだ。

しかしながら、彼らは独自のベンダープレフィクスを付け加える。暗愚の極みにあらずや?

transitionや、その他諸々は、すべて、デファクトスタンダードになっている。どのブラウザも、transitionを実装する際には、Safariと互換性があるようにする。誰がベンダープレフィクスなんて必要としているんだ?

ブラウザベンダー各位。貴君らは、Web標準や、他の競合相手と、協力して動いていることを、もっと誇りに思うべきであると、小生は信ずる。もはや、貴君らにベンダープレフィクスは必要ないのである。貴君らは、その境地におらざればなり。

ベンダープレフィクスを廃止するの時は来たれり。もはや、ベンダープレフィクスは、かつての過ぎ去りし時代の遺物なるのみ。さりながら、Web標準に対する、大いなる障碍となり得んことを恐る。

今回は、本の虫: QuirksBlog: HTML5のドラッグ&ドロップはクソだのように、Fで始まる四文字言葉こそ使っていないものの、文章には、明らかに、怒りといらだちを感じる。そこで、行間を読んで、そのようなニュアンスを、正しく、翻訳した。

ちなみに、リンク先のIE team blogの、border-radiusに関する記事は、秀逸なので、是非とも読むべきである。

また、この記事を受けて、当ブログのCSSから、ベンダープレフィクスを取り除いた。これにより、一時的に、FirefoxやSafariで、border-radiusが、動かなくなる。しかし、それは、いまだにベンダープレフィクスを使っている、前時代的なクソブラウザを使っている人間と、そのブラウザベンダーが悪いのであって、私のせいではない。

かの、QuirksMode - for all your browser quirksのPeter-Paul Kochが、ここに、こうして文章を公開したのである。いやしくもWebに携わる者で、彼の名前とWebサイトを知らない者は、モグリである。これに従わないブラウザベンダーのブラウザは、使う価値がない。

ちなみに、たまに批判がある、私のブログの、IEチェックであるが、IE9が、なかなか良さそうなので、IE9の発表の当日に、コードを変更した。今のコードでは、IE9以降は、警告文が表示されないはずである。もっとも、私はまだ、IE9 previewを試していない。IE9が実際にリリースされて、やはり、ダメであったなら、IEチェックは、IE9も含めるだろう。

2010-03-22

雑誌に載せる記事案の変更

プログラミング雑誌に載せる私の記事は、「C++の歴史」と題して、文字通り、C++の歴史について書く予定であった。当初は、D&Eを元にして、Bjarne Stroustrupを主人公にしたて、時系列にそって、記述して良く予定だった。

FCD制定にあたって、かなり大幅な変更が加わったので、post-Pittsburgh mailingがでるまでは、C++0x本の記述も、うっかり進めるわけには行かぬ。記事を書くには、好都合だ。

もう一ヶ月以上前、雑誌の話が来た時に、このように、書き出した。

1979年のことであった。イングランドはケンブリッジ大学で、ひとりの男が、博士号を取るための研究に勤しんでいた。彼の名はBjarne Stroustrup、当時29歳。後に、「C++の設計者にして最初の実装者」と呼ばれる男である。

しかし、すぐに壁に突き当たった。Bell Labに入った後の、Bjarne Stroustrupの足取りは、詳しく追うことができないのだ。

おそらく、本人に聞けば、教えてくれそうな気もする。しかし、よくよく考えてみれば、それはBjarne Stroustrupの伝記になってしまう。C++の歴史ではない。

結局のところ、C++は、Bjarne Stroustrupがクレジットを主張できるようなものではないのだ。Bjarne Stroustrupが、真に、自由に言語を設計できたのは、ほんの数カ月の間のことであった。それ以降は、すぐにBell Labのメンバーの意見が入ったし、すぐに、ISOによる標準規格の制定作業という形になってしまった。Bjarne StroustrupがC++に与えた影響は、もちろん無視できないが、それほど大きくもないのだ。

というわけで、Bjarne Stroustrupを中心にした、編年体の歴史書は、行き詰まってしまった。全然文章が進まないのだ。D&Eを参考にすれば、書けることは書けるだろうが、支離滅裂になって、ひどくまずい文章に成り下がるだろう。

だいたい、C++の各機能は、単純に時系列で追うことはできない。クラスならクラス、テンプレートならテンプレートと、分けて考えなければならない。

そもそも、D&Eに書いてあることは、D&Eを読めばいいのだ。私はあの時代を生きていなかった。Bjarne Stroustrupを超える文章を書けるわけがない。

しかし、D&E以降の歴史なら、需要があるはずだ。C++以降の歴史は、いろいろと文章になって点在しているが、それらをまとめた本はない。

さらに、記述方法だが、各機能ごとに、紀伝体で書けばいいのではないか。

というわけで、D&Eに載っていない、それ以降の歴史を書くことにした。テンプレートやSTL。具体的な例を上げれば、exportにまつわる歴史だ。exportが規格に入るまでの歴史は、これが、なかなか面白いのだ。

さらに、我が日本の恥づべき黒歴史、EC++についても、面白いことが書けるだろう。EC++を提案した連中(複数の日本企業)は、C++の多くの機能(例えばnamespaceなど)について、「新しすぎて(俺らには)使えないし、難しすぎて(俺らには)実装できない」と、大真面目に答えたのである。

余裕があれば、C++0xにまで、手を広げられるかもしれない。面白そうだ。

コンパイラの独自拡張を無効にするオプション

C++0xのコードをコンパイルしたいとする。ここで問題になるのは、コンパイラの独自拡張だ。多くのコンパイラは、非常に微妙な、規格との齟齬を、独自拡張として提供している。そのようなコードを、エラーにしたい。

二度とググらなくていいように、ここにメモしておく。

VCの場合、/Za。

gccの場合、-std=c++0x -pedantic-errors。

user-defined conversionは、何回適用されるのか

答え:一回。

struct X { operator int(){ return 0 ; } } ;
struct Y { operator X(){ return X() ; } } ;

int main()
{
    Y a;
    int b = a; // error
    // a.operator X().operator int() not tried
    int c = X(a); // OK: a.operator X().operator int()
}

なぜならば、12.3 Conversions [class.conv] p4に、"At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value."と書いてあるからだ。

なるほど、それはいい。というのも、変換関数が二回以上、暗黙的に呼び出されては、混乱の元だからだ。

上の例は、conversion functionを使っているが、constructorでも、同じだという。どれどれ。

struct Type1 {  } ;
struct Type2 { Type2(Type1) {} } ;
struct Type3 { Type3(Type2) {} } ;
struct Type4 { Type4(Type3) {} } ;

int main()
{
    Type2 t2 = Type1() ;// OK
    Type3 t3 = Type1() ;// error. VC accept it.(WRONG! Bad Compiler VC! You are a bad compiler!)
    Type4 t4 = Type1() ;// error. VC deny it correctly.
}

おい、VC。いい加減にせい。

2chのC++0xスレで、珍しく、C++の話題が論じられているので、ふと、user-defined conversionについて気になった。調べてみたところ、またVCの糞っぷりが明らかになった。

萌え絵の変遷

暇人\(^o^)/速報 : 【画像有】耳と鼻はどうあがいても萌えに繋げられない だからって鼻を点で描くなよ - livedoor Blog(ブログ)

こういうまとめ画像は、確か去年も見た気がするが、良いまとめがあったので、取り上げてみる。

萌え絵の変遷としては、

  • 鼻を単純化
  • 影を少なくして、立体感を消し、より平面的に。
  • 口元やまつ毛も、やや単純化

10年後は、荒木飛呂彦のような画風が、流行してくれるといいのだが。

2010-03-21

コンパイラが欲しい

C++0xの完璧なコンパイラが欲しい。いや、完璧でなくても構わない。エラーメッセージが不完全でもいいし、一部の機能を実装していなくても構わない。ただ、C++0xのコア言語機能を、ある程度パースできるコンパイラがほしい。

とりあえず、いますぐ欲しい実装は、attributeとconstexprだ。この二つは、少々複雑なので、是非とも、検証用のコンパイラが欲しい。

と思ったら、gccが、constexprキーワードだけ、受け付けるようだ。実装されていないが。

アトリビュートが問題だ。

どのように書くかは、規格を読めば分かる。しかし、typoがないかどうかを、脳内コンパイラで判断するのは危険だ。

問題は、gccは、かなりの独自拡張があるということだ。-std=c++0xを指定しても、どうも拡張機能が無効にならない。嗚呼、なぜ世の中には、まともなC++コンパイラがないのか。Clangは、期待してもいいのだろうか。

参考:プログラミングテクニック番外編

目グレップ(目grep)
現場デバッグなどの局面で、普段と異なる環境で使われるテクニックのひとつ。これは,grepをプログラマ自身がエミュレートするテクニックで、柔軟な非正規表現を使った検索が実行できる。まれにマッチングに失敗する。
手セド(手sed)
手作業で単純かつ多量な文字列置換を行う事。 置換機能の貧弱な環境に於いてしばしば利用される。 柔軟な半面、信頼度に欠ける。

initializer listの解説

C++の思想の一つに、組み込み型と、ユーザー定義型との、区別をなくすという理念がある。したがって、C++では、組み込み型だろうか、クラスだろうが、自動ストレージ、静的ストレージ、動的ストレージ上に、構築できるし、演算子をオーバーロードできる。C++の多くの機能が、組み込み型とクラスとの、区別をなくすよう、考案されてきた。

C++では、配列や構造体の初期化に、特殊な構文を使える。

int x[3] = { 1, 2, 3 } ;

struct Foo { int i ; double d ;  } ;

Foo foo = { 123, 3.14 } ;

これは、クラスでは、使えなかった。C++0xでは、これができるようになる。

とはいうものの、これは、特に解説を要するほどのものでもないのだ。

まず、この{}による初期化式を、リスト初期化という。ユーザー定義のコンストラクター、privateやprotectedな非静的なデータメンバー、基本クラス、仮想関数のないクラス、それと配列は、従来通りの初期化ができる。上と同じ例を示す。

int x[3] = { 1, 2, 3 } ;

struct Foo { int i ; double d ;  } ;

Foo foo = { 123, 3.14 } ;

それでは、「ユーザー定義のコンストラクター、privateやprotectedな非静的なデータメンバー、基本クラス、仮想関数」を有するクラスは、どうやって、リスト初期化すればいいのか。これは、クラス側で、リスト初期化に対応するコードを書く必要がある。

言語サポートライブラリの、std::initializer_list<T>というクラスを、引数に取る必要がある。これは、<initializer_list>をincludeすることによって、使うことができる。

#include <initializer_list>

class Foo
{
private :
    int sum ;

public :
    Foo( std::initializer_list<int> list )
        : sum(0)
    {
        for ( auto iter = list.begin() ; iter != list.end() ; ++iter )
        {
            sum += *iter ;
        }
    }

} ;

int main()
{

{// 初期化
    Foo foo0( { } ) ;
    Foo foo1( { 1 } ) ;
    Foo foo2( { 1, 2 } ) ;
    Foo foo3( { 1, 2, 3 } ) ;
}

{// これも同じ初期化
    Foo foo0 =  { } ;
    Foo foo1 = { 1 } ;
    Foo foo2 = { 1, 2 }  ;
    Foo foo3 = { 1, 2, 3 } ;
}

{// 実は、これでもいい
    Foo foo0{ } ;
    Foo foo1{ 1 } ;
    Foo foo2{ 1, 2 } ;
    Foo foo3{ 1, 2, 3 } ;
}

}

このように書くことができる。最後の例は、コンストラクタの呼び出しに、()の代わりに、{}を使っている例である。C++0xでは、()の代わりに、{}も使えるようになった。どちらも、同じ意味である。ただし、()を使った場合、以下のようなことはできない。

// これは、関数のプロトタイプ宣言。
// 引数を取らず、Foo型の戻り値を返す、wrongという名前の関数の宣言。
// Foo wrong(void) 
Foo wrong() ;

// これは、Foo型の、okeyという名前の変数の宣言。
Foo okey{} ;

()を使った場合は、文法上、関数の宣言と曖昧になってしまう。{}ならば、そのようなことはない。

もちろん、初期化と代入は違う。代入でもリスト初期化を使えるが、その場合は、別に代入演算子も定義しなくてはならない。

struct Foo
{
    Foo() {}
    Foo & operator = ( std::initializer_list<int> list ) {}
} ;

int main()
{
    Foo foo ;
    foo = { 1, 2, 3 } ;
}

これは、普通の関数でも使える。

void f( std::initializer_list<int> list ) {}

template < typename T >
void g( std::initializer_list<T> list ) {}

template < typename T >
void h( T x ) {}


int main()
{
    f({1,2,3}) ;

    // g<int>()が呼ばれる。
    g({1, 2, 3}) ;
    // g<double>()が呼ばれる。
    g({1.0, 2.0, 3.0}) ;

    // エラー。テンプレート引数を推定できない。
    h({1}) ;
}

また、添字でも使える。

class Array
{
private :
    int data[10][10][10] ;

public :
    int & operator [] ( std::initializer_list<int> list )
    {
        if ( list.size() != 3 )
            throw std::invalid_argument() ;

        auto iter = list.begin() ;
        int const x = *iter ; ++iter ;
        int const y = *iter ; ++iter ;
        int const z = *iter ;

        return data[x][y][z] ;
    }
} ;

int main()
{
    Foo foo ;
    foo[{ 1, 1, 1 }];
}

これだけのことである。{}を、初期化の際のコンストラクタへの引数の指定に使えるのだけは、少々違和感を感じるかもしれないが、{}の方が、文法上、曖昧にならないので、便利である。

リスト初期化は、同じ型しか渡せないという制限がある。もし、任意の数の、違う型の引数を渡したいのならば、Variadic templateを、代わりに使うことができる。

携帯電話の業界はどうなっているんだろう

高木浩光@自宅の日記 - 音楽著作権団体らの杜撰なアンケートがフィッシング被害を助長する

携帯電話の業界は、どうしていつもこうなのか。いくらHTTPSといっても、別のドメインで提供されていたら、フィッシングサイトと見分けがつかないじゃないか。

2010-03-20

scoped enumについて

C++0xでは、scoped enumが追加されている。従来のenumは、unscoped enumと呼ばれている。いやしくもC++0xプログラマならば、scoped enumを使うべきである。

一体、従来のenumと、何が違うのか。scoped enumは、強い型付けによって、バグを防いでくれる。

使い方は、とても簡単である。

// scoped enum
enum struct Hairstyle
{
    FusaFusa, Mohawk, Hage
} ;

int main()
{
// OK
    Hairstyle style = Hairstyle::FusaFusa ;

// Error: enum名が指定されていない。
    Hairstyle head = Hage ;

// Error: 暗黙の型変換はできない。
    int i = Hairstyle::Hage ;

// OK: 明示的にキャストするのは可。
    int BigWave = static_cast<int>(Hairstyle::Mohawk) ;
}

これによって、C++0xプログラマは、enumが暗黙に変換されることによるバグを見つける能力を失う。そもそも、そんなバグは、C++0xでは、起こりようがないのだ、したがって、そんな非人間的なデバッグ能力も、必要ない。C++0xでは、scoped enumを使うべきである。

ところで、C++0xでは、enum型の内部的な型を指定できる。

enum struct Int : int { value } ;
enum struct UInt : unsigned int { value } ;

また、その内部的な型を取得するメタ関数も定義されている。

 int main()
{
    std::underlying_type<Int>::type x ;// int 
    std::underlying_type<UInt>::type y ;// unsigned int
}

この、内部的な型を指定出来る機能というのも、重要だ。環境依存の話になるが、たとえば、DirectXのSDKのヘッダなどでは、定数の宣言に、enumを用いているが、enumの内部的な型がDWORDであることを保証させるため、以下のようなテクニックが用いられている。

enum
{
    ID1 = 1,
    ID2 = 2,

    dummy = 0xffffffff
}

こんな汚いコードは、今後、書く必要がなくなる。

電源ユニットを修理

去年から、電源ユニットのファンが、ガチャガチャとけたたましい音を立てていた。どうやら、なにかに接触しているらしい。金もないので、そのまま放置していた。

しかし、ここ最近、音が、さらに危険な響きになってきた。これはいよいよ危険だ。何とかするしかない。

というわけで、電源ユニットを取り外して、分解してみた。CPUファンや、ケースファンなら、安く売っているが、電源ユニットに組み込まれているファンは、そもそもどうなのか。見たところ、そう簡単に交換できるような作りになっていない。もし、これを交換するならば、サイズの似たようなファンを、探し出してきて、ファンに繋がっている電線をぶち切り、新しいファンにハンダ付けするしかないのではないか。

しかし、それにはまず、半田ごてから買ってこなければならない。上手くいく保証もない。それなら、電源ユニットを買ってきた方が安い。しかし、電源ユニットも高い。安くても、四、五千円はするだろう。そんな金はない。

金がないので、何とかするしかない。見てみたところ、ファンと、ファンを覆う、目の非常に荒い金網が、ぶつかっているようだ。金網というより、太い針金のカバーである。これは、別になくても構わないのではないか。ファンを保護する目的だとしても、私の使っているケースは大きい。別に、ファンに直接ぶつかるようなものはない。ホコリを防ぐにしても、このザルでは、何の効果もない。金網を外して、電源ユニットを組み立てた。

静寂が、戻った。とりあえず、問題はないようだ。

ついでに、ケース内に溜まっていた埃の掃除をした。

BGMには、この歌がふさわしいと思う。そういえば、The Godfatherは、一度も見たことがない。

2010-03-19

アメリカの特許の仕組みはどうにかならないのかな

Microsoft headed back to East Texas to fight another patent infringement case | All about Microsoft | ZDNet.com
VirnetX sues Microsoft over patents again, now taking aim at Windows 7 | All about Microsoft | ZDNet.com VirnetX files same patent claims against Windows 7

MSはVPNに対する特許訴訟で負けたのだが、その特許を、Windows 7も侵害しているとして、再び訴訟沙汰になっているようだ。

ちなみに、このVirnetXという会社は、実態は、i4iと同じであるとされている。あの有名な、XMLに対する特許で、Wordを訴えた企業である。

しかも、裁判長は、i4iの時と同じである。

こうなってくると、ソフトウェアに特許を認めるのが妥当なのかどうか、疑問になってくる。ただ、問題は、ソフトウェアに限らない。車輪並に、あまりにも自明で既知のアイディアに対する特許が認められるというのが、問題なのだ。

不思議な生き物

いつものように、ジョギングに行こうと外に出た。塩小路橋、師団街道から、鴨川に降りて、そこを、三条まで往復するのが、平常の私のジョギングコースである。今日も、いつものように鴨川に降りて、体操をしていた。

ふと、何気なく鴨川を見ると、土砂が堆積しているところに、なにやら見慣れぬ生き物がいる。

小さい犬か猫だろうか。それにしては、形が違う。ウサギだろうか。いや、あの特徴的な耳がない。ネズミか? いや、形はネズミに似ているものの、ネズミにしては、大きすぎる。

大きさは、ちょうど落ちていた、500mlのペットボトルより、大きい。まるまると太っている。

さらに近くによって観察すると、いかにもネズミのような、長く尻尾があった。しかし、ネズミをこのサイズにスケールしてみても、この尻尾は、どうも太すぎる。

全身、茶色の体毛で覆われている。

さらに近くによると、こちらをみた。フガフガという鼻息が聞こえる。とすると豚か。いや、豚は、このような体毛を持たない。実物を見たことがないが、イノシシの子だろうか。いや、イノシシには、あのネズミのような尻尾は、なかったはずだ。

その不思議な生き物は、常に、雑草を食べていた。ウサギならば、説明がつくのだが、形はやはり、ネズミである。しかし、ネズミにしては大きい。

ビーバーという生き物がいる。画像でしか見たことがないが、たしか、今この眼前にいる生き物のような姿形ではなかったか。

いろいろ考えた挙句、何らかの、齧歯類に属する、外来の動物であろうと結論した。おそらくは、ペットとして日本に入ってきて、逃がしたか逃げ出したか、そんなところだろうと考えた。

その後、七条から三条まで往復4kmの距離を、24分かけて、ジョギングした。帰ってくると、その生き物は、もう、そこにはいなかった。

帰宅し、シャワーを浴びて汗を流した後、ビーバーの画像をググった。やはり、よく似ている。ただ、あそこまで平べったい尻尾を持っていただろうか。実は、尻尾は、よく覚えていない。太い尻尾だったことは記憶しているが、常に、草と生き物の胴体に隠れていて、よく見えなかったのだ。

こんにちは、ビーバー (たくさんのふしぎ傑作集)
ナショナル ジオグラフィック〔DVD〕 森の建築家 ビーバー物語

追記:本来、外来の動物を、ペットとして、安易に国内に持ち込むような行為の是非を論じるような本へのリンクを貼りたかったのだが、あいにくと、そういう本は読んだことがないし、すぐに見つからなかった。

追記2:コメントで、ヌートリアではないかという指摘を受けた。たしかに、ヌートリアによく似ていた。ビーバーにしては、尻尾が平たすぎると思っていたのだ。たしかに、件の生き物は、ヌートリアのような尻尾を持っていた。

ヌートリア - Wikipedia

IE9のJavascriptの実装について

IEBlog : The New JavaScript Engine in Internet Explorer 9

要点だけまとめ。

最近は、Javascriptを、本物のプログラムとして使うサイトが増えた。ページのCPU使用率の、八割方を、Javascriptが占めているようなページすらある。

そういうわけで、Javascriptをネイティブコードにコンパイルして、最適化するのが、最近の流行である。

動的な言語であるJavascriptを早くするというのは、なかなか難しい。ただに、ネイティブコードを生成すればいいと言うものでもない。Javascriptのような、動的な言語に対して、効率のいいネイティブコードを生成するのは、やはり難しい。が、テクニックは、いくつも考案されている。

問題は、効率のいいネイティブコードを生成するのには、コストがかかるということだ。

多くのサイトでは、Javascriptの、全体のCPU時間に占める割合は、せいぜい数割である。ネイティブコードの生成に、アホみたいに時間をかけていたのでは、ユーザーはいらつく。ユーザーとしては、ページに必要なリソースをダウンロードしたならば、ただちに描画をして、実際のコンテンツを見たいわけだ。それが、Javascriptのコンパイルのために、しばらくお待ちください、となったのでは、たとえ、最適化後は、快適に操作できたとしても、ユーザーは不満である。

Javascriptの高速化も重要だが、ページを、できるだけ早く描画するのも、重要である。

そういうわけで、IE9では、ページを読み込みしだい、まず、インタプリターでJavascriptを実行して、ページを描画する。と同時に、Javascriptのコンパイルを、バックグラウンドで進める。ネイティブコードに置き換わった部分から、差し替えていく。こうすることによって、ユーザーは、Javascriptのコンパイルを待たずとも、すぐにコンテンツを見ることができる。

また、バックグラウンドでJavascriptのコンパイルが行われるので、マルチコア環境でも、スケールできる。

さらに、インタプリターも書き直して、レジスターベースのモダンなopcodeを使うようにし、高速化した。

それから、正規表現などのライブラリも、高速化している。

また、MSは、Javascript言語の発展のために、ECMA Script 委員会に所属している。

コンセプトが廃止になった理由

昨日は、久しぶりに、私の契約しているISPが規制されていなかったので、2chに書き込んだ。書いた後、結構まとまっていると感じたので、ブログにも書いて、保存しておくことにした。コンセプトが廃止になった理由について。

コンセプトが廃止になった理由は、いろいろあるが、直接には、concept mapを、暗黙的に生成するかどうかだった。

あるコンセプトに対して、対応するコンセプトマップを、暗黙的に生成するか、 あるいは、たとえ、コンセプトマップが空でも、明示的に定義させるべきかという問題があった。 つまり、ある型は、そのコンセプトの要求を満たしていると言うことを、明示的に宣言しなければならないわけだ。 こうすることによって、たまたまシグネチャが一致したのではなく、明確に、この型はこのコンセプトを満たしているんだと宣言できる。

ただ、このやり方は、殆どの場合、空のコンセプトマップを、ただ、そのコンセプトを満たしているという宣言のためだけに、書かなければならない。

それはどうなんだと。そんなの面倒で、誰もやらないぜと。

フランクフルト会議での解決策は、デフォルトのコンセプトには、暗黙的に、対応するコンセプトマップが生成され、 explicitをつけた場合、コンセプトマップを(たとえ空でも)、明示的に宣言しなければならないという提案だった。

ただ、やはりコンセプトというのが、非常に微妙で、ある意味では、厳格すぎるし、なかなか難しい機能だった。 コンセプトのコードを正しく書くのは、非常に難しい。

さらに、まともな実装もなかった。Douglas GregorのConcept GCCは、かなり不完全な実装で使い物にならなかった。

まあ、そんなわけで、標準化委員会の中にも、「もういいだろ」って雰囲気が漂っていた。 そこにきて、この根本的な思想の違いをきっかけに、投票が行われた。 すでに入っているConceptを、ドラフトから削除するという投票。 これには、Bjarne Stroustrupも、Douglas Gregorも、削除の票を投じた。

そんなわけで、コンセプトは削除された。

2010-03-18

サウスパークの新シーズンが始まった

Sexual Healing

えーと、今回のオチは何だったんだろうか。不謹慎なネタは数多くあったが、オチが見当たらない。

ちなみに、ケニーは今回、世にも不思議な方法で死亡した。ケニー家の、あの子供って誰だろう。

日本のC++標準化委員会のアドホック会議の告知

ピッツバーグ会議で、FCD(Final Committee Draft)の発行が可決された。これにより、次回の、日本のC++標準化委員会の会議は、アドホック会議となる。アドホック会議は、C++WG JPのメンバーでなくても、参加できる。

アドホック会議は、五月に、東京は赤坂の、サイボウズ・ラボで行われる。詳しい日程は、まだ調整中である。日時が決まり次第、参加希望の申請方法もあわせて、追って告知する。今のところ、五月の15日、22日、29日が候補に上がっている。いずれも土曜日である。

会議では、FCDに対して募集したコメントを議論して、C++WG JPとして、コメントを本部に送るかどうかを決定する。

また、FCDに対するコメントも募集している。post Pittsburgh mailingは、まだ発行されていないが、数週間以内に発行される予定である。

コメントとは、FCDに対する誤りの指摘である。FCDとなったからには、もはや大幅な変更は受け付けられない。typoや文面の矛盾、曖昧な点へのコメントの募集となる。

オンラインブックマークサービスへの所感

Twitter / 佐藤 譲: 元はてなスタッフだから言ってるのではなく、はてブの存 ...

以前、私は、オンラインブックマークサービスを嫌っていた。今でも、あまり好きではない。

理由は、ブックマーク先に、ユーザーの声が届かないと言うことだ。はてブのコメントで、そのページに対する感想や批判をされても、そのブックマーク先のページの作者は、貴重な意見を、知る由がないのである。

しかし、利点もある。ブックマークを共有できると言うことは、ネット上で、多くの者が、ブックマークするだけの価値があると認めるコンテンツを、発見できるということである。それ故、私ははてブやDiggのフィードを、Google Readerで購読している。

さて、はてブが、Diggより優れている理由が、ひとつだけある。まともなAPIをJSONPで提供していることである。これにより、私は、Javascript上から、特定のURLに対する、はてブ数や、はてブコメントを取得でき、表示できる。

これにより、私のブログは、記事に対するはてブ数を表示できるようになったし、はてブコメントも、表示できるようになった。それを考えれば、はてなブックマークは、まだ努力している方である。

ちなみに、Diggでは、特定のURLに対するDigg idを得る方法がないので、これはできない。そもそも、単一のURLに対して、複数のDiggを作成できるのも、問題なのだ。

2010-03-17

先生、金鎖を死刑にする

明治二十六年の春のことであった。

その日の朝食は、豆腐と菜っ葉であった。私は、達観した心持ちで、豆腐と菜っ葉を口に運んだ。思えば、昨日の食事も、豆腐と菜っ葉であった。明日の食事も、豆腐とナッパに違いない。豆腐と菜っ葉には、利点がひとつある。安いことだ。それにしても、今朝は、その豆腐と菜っ葉さえ、量が少なく感じた。

食事を終えた後、私は、先生を伺いにいった。先生は、いつものように、どこか達観した表情で、私を見た。私は、何も言わなかった。まあ、わかりきったことだ。先生は、首にかけていた金時計を外して、しばらく、手のひらの内で転がしていた。金時計には、紙ひもで作ったこよりがつけてある。首にかける紐替わりにしているのであった。

やがて先生は、金時計を私に差し出して、言った。
「傳次郎君、この時計、どうも、また、狂ったようでな。直しに出しに行ってくれんかな」

私は努めて無表情を保ちつつ、金時計を受け取り、家を出て、その足で、質屋に向かった。

「まあ、まず十八円ってところだな」と質屋の親爺は言う。
「前は十九円貸したぜ。二十四円にしろ」
「二十円」
「上げろ」
「御免だ」

親爺は頑として譲らなかった。私は、金時計を質草に、二十円を得て、重い足どりで家に戻った。

「兆民先生、ねばったんですが、二十円でした」と私が言えば、
「そうか。まあ、そのくらいだろうな。仕方がない。でもまあ、あの時計は、まだマシな方だ。禁錮ですむんだからな。前は金鎖もついていたんだが、そっちは死刑にしたんだ。傳次郎君、君にも迷惑を掛けるね。なあに、そのうち大金を手に入れてやるさ。なあ幸徳君」

思えば、あの頃が、一番幸せな時代だったのかもしれぬ。その後、兆民先生は、金を儲けるためと称して、様々な事業に手を出した。時には遊郭の経営にまで乗り出した。しかし、兆民先生が金を儲けるために奔走すればするほど、ますます借金が増えるだけであった。

兆民先生・兆民先生行状記より。

Paypalによる寄付の受付をはじめてみた

追記:寄付のおかげで形になるほど執筆が続けられました。本の虫: C++11参考書の公開:C++11の文法と機能

Pledgieというサービスを使い、寄付を募集してみた。

[終了]

受け付ける金額は、日本円(JPY)に設定している。

Paypalの銀行口座の認証が終わったので、Paypal経由でも寄付を募ってみようと思った。Paypalの送金サービスを直接使ってもいいのだが、pledgie.comというサービスを利用することにした。

pledgie.comというのは、非営利、営利に関わらず、何らかの寄付を募集するためのWebサービスを提供しているサイトである。寄付を支払うのは、Paypal経由で行える。Paypalを直接使うのに比べて、pledgieには、いくつかの利点がある。

まず、どのような内容の寄付なのかという説明のページを作ることができる。そのページへの、分かりやすい画像のリンクをはれる。支払いは、paypal経由で行われ、pledgie自体は、手数料を取らない。また、目標額を設定でき、寄付ボタンの画像に、分かりやすいプログレスバーで、目標額に対して、どのくらい寄付が集まったのかということを、表示してくれる。

さて、寄付を募ることに関しては、これ以上することはない。広告も、これ以上はすることがない。後は、働くしかない。

というわけで、仕事だ。例のプログラミング雑誌の記事を書いている。C++の歴史だ。読むべき資料が実に多い。

ところで、創刊号には、Bjarne Stroustrupへのインタビューを掲載する予定である。これは、私がコンタクトを取り、私が翻訳することになっている。

肝心の、C++0x本はどうなのか。それもある。しかし、なによりまず、生活費を確保しなければ、執筆どころではなくなってしまう。また、まだドラフトはかなり変更される。まず、FCDの公開を待たなくてはならない。

民話蒐集

VIPワイドガイド:俺が収拾した地元の民話を書いていってみる

面白い。いくつかの話は、全国的に有名な話の派生版である。

なぜ、全国的に、似たような話があるのか。柳田国男によれば、行商人や、琵琶法師などの盲坊主、あるいは、イタコのような、神がかりになって預言をする職業の者が、各地を回って、似たような話のネタを使ったために、全国に似たような話が広がっているらしい。

遠野物語・山の人生 (岩波文庫)

遠野物語―付・遠野物語拾遺 (角川ソフィア文庫)

IE9のプレビュー版が公開された

Internet Explorer 9: Platform Demos
IEBlog : HTML5, Hardware Accelerated: First IE9 Platform Preview Available for Developers

Javascriptの高速化、CSS3のサポート、GPUによるレンダリング。looks promissing.

例として、画像が飛び回るデモがある、Chromeでは、数FPSしかでない。GPUによるレンダリングが必要とされているデモだろう。

Javascriptの速さは、主要なブラウザに追いついたそうだ。

でも、テストケースに、DOM level 3 Coreがないのはどういうこった。

テストケースのいくつかは、本物のXHTMLで提供されている。つまり、content-typeがapplication/xhtml+xmlになっている。

少し期待できるかもしれない。

2010-03-16

MozillaはAppleからコードを借りた

Asa Dotzler: Firefox and more: mozilla borrowing a bit of code from apple

MozillaのJavaScriptエンジンに関する混乱があるようなので、David Mandelinのブログを紹介しておく。David Mandelin's blog » JägerMonkey & Nitro Components。また、a quick note on JavaScript engine components ✩ Mozilla Hacks – the Web developer blogも役に立つ。

俺は技術屋ではないが、まあ、こういうこったろう。

数年前、JavaScriptエンジンはみな、めちゃ遅かった。んでまず、Appleが、SquirrelFish Extremeを作った。これは、Method JITと呼ばれるテクニックで、JavaScriptを最適化してた。Mozillaは、TraceMonkyを作った。これは、トレーシングという呼ばれるテクニックで、いくつかのケースを、すばらしく高度に最適化できるんだ。最後に、GoogleのV8が現れた。こいつも、今はNitroと呼ばれているSquirrelFish Extremeによく似たテクニックで、最適化をしてる。

第一ラウンドの結果としては、Firefoxは、ごく限られたある種のコードを、すっげーサイキョーに高速化したが、残りのほとんどは、何もできずに終わった。今、JagerMonkeyによって、MozillaはNitroやV8のようなMethod JITと取り入れた。これによって、トレーシングが上手くいかない多くのケースを最適化できるようになり、ようやく俺らも、チョッ早になったというわけだ。

このMethod JITの実装には、AppleのNitro JavaScirptエンジンの一部を、再利用して、さらに、独自の新機能を付け加えてる。

さらにクールな事を教えてやろうか。method JITを取り入れたことによって、俺らは他のJSエンジンと肩を張れるようになったわけだが、さらに、トレーシング機能をつかって、より高速化が図れる余地を残しているってわけだ。つーわけで、俺らが世界最速になる場面が、今後増えるわけだな。しかも、他の場面でも、他のブラウザより遅くないと来ている。んでさ、AppleやGoogleや、あるいはOperaとかが、自分のJSエンジンにも、トレーシングが欲しくなってきたらどうするんだろうね。その場合、奴らはMozillaのコードを見て、俺らの仕事の結果を借りればいいってわけさ。

この人の文章が特に面白かったので、つい訳した次第。

簡易版std::functionを実装してみた

誰かが、Boost::functionを読めばレベルが3ぐらい上がるとつぶやいていた。読もうとしたが、五分で諦めた。プリプロセッサを使いすぎなのだ。だいたい、std::functionぐらいなら、自分で実装した方が、レベルが上がるのではないかと思う。というわけで、4時間ぐらいかけて、書いてみた。

アロケーターも、似たようなType Erasureのテクニックを使って実装すればいい。

ところで、target_type()の文面がよく分からない。Tとあるが、target_type()はテンプレートではないし、Tが定義されていないのではないか。

追記、target_type()を理解したが、実装方法が面倒だ。さて、どうするか。

追記、target_type()/target()を実装した。さらに、perfect forwardingになった。

namespace hito {

class bad_function_call : public std::exception
{
public:
    bad_function_call() {}
    virtual char const * what() const throw()
    {
        return "bad function call exception" ;
    }
} ;

template < typename > class function ;// primary template.

template < typename R, typename ... ArgTypes >
class function< R ( ArgTypes... ) >
{
public :
    typedef R result_type ;

private :

    struct holder_base
    {
        virtual ~holder_base() {}
        virtual holder_base * clone() const = 0 ;
        virtual std::type_info const & target_type() const = 0 ;
        virtual void * target() = 0 ;

        virtual result_type invoke( ArgTypes... ) = 0 ;
    } ;

    template < typename F >
    struct holder : public holder_base
    {
    public :
        holder(F f) : f( f )
        { }
        virtual ~holder() { }

        virtual holder_base * clone() const
        {
            return allocate_holder( f ) ;
        }

        virtual std::type_info const & target_type() const
        {
            return typeid( F ) ;
        }

        virtual void * target()
        {
            return &f ;
        }

        virtual result_type invoke( ArgTypes... args )
        {
            return f( std::forward<ArgTypes>(args)... ) ;
        }
    private :
        F f ;
    } ;

    template < typename holder_R, typename T, typename ... Types >
    struct member_holder : public holder_base
    {
    public :
        member_holder( holder_R (T::* const f)( Types... ) )
            : f(f)
        { }
        virtual ~member_holder() {}

        virtual holder_base * clone() const
        {
            return allocate_holder( f ) ;
        }

        virtual std::type_info const & target_type() const
        {
            return typeid( f ) ;
        }


        virtual void * target()
        {
            return &f ;
        }

        result_type invoke_impl( T t1, Types... args )
        {
            return (t1.*f)( std::forward<Types>(args)... ) ;
        }

        result_type invoke_impl( T * t1, Types... args )
        {
            return ((*t1).*f)( std::forward<Types>(args)... ) ;
        }

        virtual result_type invoke( ArgTypes ... args )
        {
            return invoke_impl( std::forward<ArgTypes>(args)... ) ;
        }

    private :
        holder_R (T::* f)( Types...) ;
    } ;

    template < typename T, typename DATA >
    struct data_member_holder : holder_base
    {
    public :
        data_member_holder( DATA T::* const f )
            : f( f )
        { }

        virtual ~data_member_holder() { }

        virtual holder_base * clone() const
        {
            return allocate_holder( f ) ;
        }

        virtual std::type_info const & target_type() const
        {
            return typeid( f ) ;
        }

        virtual void * target()
        {
            return &f ;
        }

        result_type invoke_impl( T & t1 )
        {
            return t1.*f ;
        }

        result_type invoke_impl( T * const t1 )
        {
            return (*t1).*f ;
        }

        virtual result_type invoke( ArgTypes ... args )
        {
            return invoke_impl( args... ) ;
        }

    private :
        DATA T::* f ;
    } ;

    holder_base * ptr ;

private :

    template < typename F >
    static holder_base * allocate_holder(F f)
    {
        return new holder< F >( f ) ;
    }

    template < typename holder_R, typename T, typename ... Types >
    static holder_base * allocate_holder( holder_R (T::* f)( Types... ) )
    {
        return new member_holder<holder_R, T, Types...>( f ) ;
    }

    template < typename T, typename DATA >
    static holder_base * allocate_holder( DATA T::* f )
    {
        return new data_member_holder<T, DATA>( f ) ;
    }

    void deallocate_holder()
    {
        delete ptr ;
        ptr = nullptr ;
    }

    holder_base * clone() const
    {
        if ( ptr != nullptr )
            return ptr->clone() ;
        else
            return nullptr ;
    }
    
public :

    explicit function() : ptr( nullptr )  { }
    function( std::nullptr_t ) : ptr( nullptr ) { }

    function( function const & init_expr ) 
        : ptr( init_expr.clone() )
    { }

    function( function && init_expr )
        : ptr( init_expr.ptr )
    {
        init_expr.ptr = nullptr ;
    }

    template < typename F >
    function( F f )
        : ptr( allocate_holder( f ) )
    { }


    function & operator = ( function const & assign_expr )
    {
        if ( this == &assign_expr )
            return *this ;

        deallocate_holder() ;
        this->ptr = assign_expr.clone() ;

        return *this ;
    }

    function & operator = ( function && assign_expr )
    {
        if ( this == &assign_expr )
            return *this ;

        deallocate_holder() ;
        this->ptr = assign_expr.ptr ;
        assign_expr.ptr = nullptr ;

        return *this ;
    }

    function & operator = ( std::nullptr_t )
    {
        deallocate_holder() ;
        return *this ;
    }

    template < typename F >
    function & operator = ( F f )
    {
        delete ptr ;
        ptr = allocate_holder( f ) ;
    }

    ~function()
    {
        deallocate_holder() ;
    }

    void swap( function & arg )
    {
        std::swap( this->ptr, arg.ptr ) ;
    }
    
    explicit operator bool() const
    {
        return bool( ptr != nullptr ) ;
    }

    result_type operator () ( ArgTypes... args ) const
    {
        if ( ptr != nullptr)
            return ptr->invoke( std::forward<ArgTypes>(args)... ) ;
        else
            throw bad_function_call() ;
    }


    std::type_info const & target_type() const
    {
        if ( ptr != nullptr )
            return ptr->target_type() ;
        else
            return typeid( void ) ;
    }

    template < typename T >
    T * target()
    {
        if ( target_type() == typeid(T) )
            return static_cast<T *>( ptr->target() ) ;
        else
            return nullptr ;
    }

    template < typename T >
    T const * target() const
    {
        if ( target_type() == typeid(T) )
            return static_cast<T const *>( ptr->target() ) ;
        else
            return nullptr ;
    }

} ;

}

oldnewthing:ロボットと人間は、平和的に共存出来るのだろうか?

The Old New Thing : Robots and humans coexisting, can it be done peacefully?

SF好きなら誰もが知っているように、人間とロボットは、どうもうまくつきあえないようだ1(訳注:リンク先は、宇宙空母ギャラクティカ、2001年宇宙の旅、ターミネーターのスカイネット、マトリックスである。)

でも、もう一度ぐらい、試してみようじゃないか。

私は、自分の記事を、別の言語に翻訳して掲載しているWebサイトを、しょっちゅう見る。日本語への翻訳はあるし、ロシア語への翻訳も、どこかしらにある。このような人力の翻訳に加えて、オンライン翻訳サービスによる、機械翻訳も、多くある。

さて、このふたつは、共存できるようになった。

このページに設置した新しいウィジェットは、機械翻訳を生成してくれる。それだけではない。Microsoft Translatorの、新しい協力型翻訳フレームワークは、機械翻訳の結果の、改良案を提案でき、将来的に、機械翻訳の制度を向上させることが出来きるのだ。閲覧者は、翻訳案を見比べて、質のいい翻訳に投票できる。これらの情報は、Webサイトの管理者に送られ、デフォルトで表示される翻訳結果を、選ぶことができる。

しかも、私は最強なので、特別に、ネイティブスピーカーのチームを、このWebサイトの管理人として割り当ててもらった。これは、悪くないことだ。というのも、私は、フランス語だの、スペイン語だの、あとは、まあとにかく、英語以外の言語の翻訳には、あまり詳しくないのだ。(私はドイツ語とスウェーデン語を、ある程度は知っているが、完璧ではないのだ)

この試みが、人類を滅ぼさないことを祈ろう。2(まあ、仮に問題が起こったとしても、君は勝者側につくだろ。違うかね?)

注:

1 おそらく、「人間とロボットが共存していました。そして、人間はロボットの電源を切りました」というお話は、面白くないからだろう。

2 たぶん、Microsoft Translatorチームは、この試みが、人類を滅ぼすかもしれないなんて考えを、気にいらないだろうと思う。いやでも、人類が滅亡するなんてことは言ってないじゃないか。ただ可能性の話をしているだけなのだ。

ボーナスチャプター:協力型翻訳フレームワークに関して疑問があるなら、Microsoft Translator フォーラムにて質問できる。

急にブログのアクセス数が伸びていて、何事かと思ったら、なんと、あのRaymond Chenのブログから、リンクが貼られていた。何とまぁ。試しに、リンク先の記事を翻訳してみた。少なくとも、Microsoft Translator のUIは、主要なブラウザで動くようだ。しかし、この試みは、うまく行くのかね。

I've noticed that I got a lot of PVs today and I wondered why. It's because that Raymond Chen linked to my blog. Wow. For curiosity, I translated that article to Japanese. At least, the Microsoft Translator's UI isn't that bad. It's portable across major browsers.

ところで、このReymond Chenとは、Windowsプログラマで、その名前を知らなければモグリといわれるほどの有名なMS社員である。著書に、ブログと同名のOld New Thingがある。

The Old New Thing: Practical Development Throughout the Evolution of Windows

2010-03-15

Funny lvalueについて

2chに、いまだに公開されていないN3055の内容の一部が貼られているが、誰だろう。

それはともかく、経緯を説明すると、そもそもの元ネタの、Funny lvalueに端を発する。

「lvalueとrvalueだけですべてをカバーするのが、大雑把すぎて分かりにくい」
「たとえば、リテラルや、lvalue リファレンスではない関数の戻り値はrvalueだが、あまりに大雑把すぎないか?」
「lvalue的に振舞うrvalue referenceってのが、厄介なんだよな」
「この際、細かくふたつに分けようぜ。rref lvalueとnon-rref lvalueとしよう」

ここまでが、Funny lvalueである。これがPittsburgh meetingの議論で、こう発展した。

「いや、この期に及んでそんな根本的な文面を変えるのかよ?」
「つーか、その名前、なんとかならんの。ワケわかんねーよ」
「というか、もっと細かく分けられるよね。するとこうか?」

こういう議論を経て、そうなった。詳しくは、正式なN3055が公開されてから解説する。たぶん、いまのペーパーがそのまま公開されると思うのだが。

芥川龍之介の木曾義仲論を読む

青空文庫: 芥川龍之介 木曾義仲論(東京府立第三中学校学友会誌)

これはすごい。さすがに芥川龍之介は天才だ。盛衰記を良く読んでいる。漢文ネタも豊富だ。いつか、こんな文章がかけるようになればいいのだが。

私も、義仲というキャラは好きなのだ。

2010-03-14

ものすごく面白い文章

My First BillG Review - Joel on Software

Joel Spolskyは、さすがに名前は知っていたが、相当の文才があると、改めて認識した。これは非常に面白い読み物だ。実際、文章もすばらしい。

なお、この話を理解するためには、以下のリンクも参考にした方が良い。

Fabulous Adventures In Coding : Eric's Complete Guide To VT_DATE
Fabulous Adventures In Coding : Bug Psychology

VT_DATEが、いかにくそみそなフォーマットだったかを説明している。VT_DATEは、30 December 1899からの経過時間で表現される。なぜ30日なのか? 31日ではダメなのか。1900年の一月一日ではだめなのか? 30日である理由は、Lotus 1-2-3のバグに対処するためである。

さらに、フォーマットも、悲惨すぎる。型はdoubleなのだが、整数部分は、起点からの経過日数を示す。ところが、小数部分は、整数による表現から、一日を少数で表現しただけ、経過したということを表すのだ。これはつまり、負数であっても、小数部分によって、時間が前に動くのだ。悲惨すぎる。

きっかけは、old new thingから。

The Old New Thing : Why does the OLE variant date format use 30 December 1899 as its zero point?

追記:Joel Spolskyは、ブログ執筆を引退して、本業に専念するらしい。なんというタイムリーな。

東風吹かば

東風吹かばにほひをこせよ梅花 主なしとて春を忘るな

贈正一位 太政大臣 菅原道真

ここ最近、天気が悪かった。また、Pittsburgh meetingもあるので、この五日間は、家に引きこもって、meetingの次第が逐一報告される、非公開のWikiを睨み暮らしていた。数週間もすれば、post-Pittsburgh mailingが公開されるはずだ。

私が、大幅な変更といったのは、Funny Lvalueの問題である。lvalueとrvalueは、意味が広すぎる。これを、もっと細分して、わかり易い名前をつけて、分類しようという事が、meetingで決定された。その結果、だいぶわかりやすくなったと思う。詳細は、N3055が公開されてから、解説する。

ふと気がつけば、私はここ数カ月、C++の規格しか読んでいない。なんだか、少しつかれた気がする。そこで、何か芸術作品を読むことにした。芥川龍之介の河童である。

芥川龍之介は、当時は所詮、売文の徒である。しかし、現代では、一流の芸術作品として名が高い。実際、芥川龍之介の文章は、なにか引き込まれるものがある。どうしても続きを読まなければ、気が済まなくなるのだ。芥川龍之介の河童は、短い話である。しかし、私にはどうも、かなり長い話のように思える。これは、現代小説にはなかなか見られない文章だ。現代の小説は、とりあえずページ数を埋めればいいという考えのもとに、だらだらといかにも取ってつけたような理由で話を引き伸ばしている。そんな小説は、読む気がなくなってしまう。

青空文庫:芥川龍之介 河童

なぜ芥川龍之介の河童を読もうと思ったのか。というのも、以前の東方かつ杜子春ネタなマンガの、作者を発見したからである。

「東方大妖怪 橙の好き好き藍様ハートフル大冒険」/「ボディ・マハッタヤ・銀河」のイラスト [pixiv]

この人だったらしい。

いい天気だったので、一週間ぶりにジョギングをすることにした。やはり、一週間サボると、体力が落ちるものだ。

とりあえず、Pittsburgh meetingも終わったので、仕事にかかるとしよう。これから創刊するプログラミング雑誌には、さる有名な人へのインタビューが載る。私が質問して、翻訳して、雑誌に載せるのだが、興味深いインタビューになるはずだ。時間的に間に合えばいいのだが。

河童 (集英社文庫)

FCDが可決された

Trip Report: March 2010 ISO C++ Standards Meeting « Sutter’s Mill

ピッツバーグ会議で、FCDが可決された。もうこれ以上、大きな変更はないだろう。

C++0xは、順調に行けば、2011年に制定できるだろう。つまり、xは11になる。C++11というわけだ。

ただし、今回のFCDを作る投票を行うというのに先立って流れたメールでは、ひょっとしたら、もう一度FCDを作るかもしれないという話もある。Unified Function Syntaxは、入るのだろうか。

嗚呼、Unified Function Syntax

Unified Function Syntax、お前は日の目をみることがあるのか。

文法書の需要はあるはずだ

C++相談室 part78

871 :デフォルトの名無しさん:2010/03/14(日) 03:10:09
c++の文法書ってありますか?
書店に行ってもプログラミングの入門書ばかりで
言語仕様の解説書が見つからなくて困ってる

絶対に需要はあるはずだ。

Googleが99.9%の確率で中国を撤退するそうだ

Google "99.9 pct" sure to shut China search engine: report - Yahoo! News

まあ、もう中国は救いようがないな。一体、今後どうなるのだろう。なんとかソフトランディングしてくれないと、非常にまずいことになるとおもうのだが、まあ、どうしようもない。まあ、歴史が変わる瞬間というのは、実にあっけないものだ。私の生きているうちに、中国の現体制は崩壊すると信じている。

2010-03-13

初期化リスト

gcc4.5で、初期化リストを試すのを忘れていた。

// for name demangling.
class Demangle
{
private :
    char * realname ;

public :
    Demangle( std::type_info const & ti )
    {
        int status = 0 ;
        realname = abi::__cxa_demangle( ti.name(), 0, 0, &status ) ;
    }

    Demangle( Demangle const & ) = delete ;
    Demangle & operator = ( Demangle const & ) = delete ;

    ~Demangle()
    {
        std::free( realname ) ;
    }

    operator char const * () const
    {
        return realname ;
    }

} ;

// ここからコード。

template < typename Iterator >
void print( Iterator first, Iterator last)
{
    typedef typename std::iterator_traits<Iterator>::value_type type ;
    std::for_each( first, last,
        [](type const & value)
        {
            std::cout << value << std::endl ;
        }
    ) ;
}

template < typename T >
void f( std::initializer_list<T> list )
{
    std::cout << "type: " << Demangle( typeid(T) ) << std::endl ;
    print( list.begin(), list.end() ) ;
}


int main()
{
    f({1, 132131, 1323, -3231, 12331, 3422, 875, -5245435, 0, 44, 333}) ;
    f({1.0, 0.0, -999.32113, 3.141592, 99999999999999.0, 0.000000001}) ;

    f({"hello", "The World", "WRRRRRRRRRY!"}) ;
    f< std::string >({"Annie", "Are You OK?", "So, Annie Are You OK", "Are You Ok, Annie?"}) ;

    std::vector<int> v({0, 1, 2, 3, 4}) ;

    print( v.begin(), v.end() ) ;
}

普通に動きすぎて、何の面白味もない機能だ。まあ、動くということは、実に素晴らしいことだ。実際、初期化リストは、それほど面白い機能ではない。ただ、動くために作られた機能だ。

Google AdSenseとAmazon Affiliateについて

とりあえず、広告として、Google AdSenseとAmazon Affiliateを導入してみた。この二つは、数あるWeb広告の中でも、非常に有名な広告であり、その性質も異なるので、試す価値があると考えたからだ。

まず大前提として、この二つの広告は、ポップアップblink(このテキストは、text-decorationによってblinkしているはず。もし、君の使っているブラウザが、blinkをサポートするほどマヌケならば。)などの過剰な表現を用いない。これは、当然だ。

まず、Google AdSenseだ。

これは、一般には、定位置に設置しておくものである。そのページの内容から、自動的に、ふさわしい広告を選んでくれる。もっとも、ほとんどの広告は、かなり怪しいものだが。

色は自由に変えられるし、サイズは、かなりの種類がある。

Amazon Affiliate。

これは、どこかに設置しておくこともできるが、どちらかと言えば、能動的に広告を貼るものだと思う。アマゾンの商品への広告を貼れる。アマゾンは、知っての通り、かなりの品揃えであり、大抵のものは揃っている。したがって、サイトの内容に合わせてこの広告を貼るのは、効果が高いと思われる。だいたい、リンクする商品は、自分が選んだものだ。この点では、Google AdSenseよりは、よほど気が聞いている。

たとえば、私は荒木飛呂彦大先生の描くジョジョを崇拝している。このリンクを貼って、世にジョジョを布教したい。こんなとき、気軽にアマゾンへのリンクを貼れる。こんな風に。

ジョジョの奇妙な冒険 (1) (ジャンプ・コミックス)

アマゾンへのリンクは、たまにネタとして使われていることもある。これは、ニコニコ動画で、動画に、「ある意味」、関連しているアマゾンへのリンクを貼るなどという例が、一番分かりやすいと思われる。私も、たまにこのネタに引っかかって、とりあえずクリックしてしまうことがある。これは、広告の価値を否定している私としては、じつに悔しいが、面白いものは面白い。

とはいえ、効果的にアマゾンの広告を貼るのは、頭を使う必要があるので、やや面倒である。第一、私は興味の対象が偏っているので、アマゾンで売上の上位にくるような商品への興味は、あまりない。

アマゾンの広告の不満は、簡単に張り付けられるHTMLの、カスタム性が、ほとんどないことである。色ぐらいしか変更できない。私は、サイズを変更したいのだが、どうもそれが、アマゾン生成のお手軽HTMLでは、できない。

広告について考える

とうとう、このブログに広告を導入してしまった。あまりやりたくないことだ。まあ、外すのはいつでもできるので、とりあえず、試験的に様子を見よう。

そもそも、広告に価値はあるのか。もちろん、テレビが未だに衰えないことや、Googleが、今やサーチジャイアントと呼ばれ、かのソフトウェアジャイアントの異名をもつMicrosoftと肩を並べるほどの価値を持っていることを考えれば、広告には価値があると言わなければならない。

しかし、テレビのCMをみて、「おお、あれはいい製品あるいはサービスに違いない。是非とも買おう」とか、このブログの広告を見て、「おお、価値のあるリンクだ。是非ともクリックしてリンク先に飛び、製品あるいはサービスを購入しよう」などと思うだろうか。他人のことは知らないが、私はむしろ、「なんだこいつは、広告なんかバンバンうちやがって。うさん臭い奴だな。回避回避」と思うのである。

しかし一方、まるで聞いたことのない製品やサービスを、いきなり買うかというと、それも、否と答えるしかない。

それに、世の中には、税金というものがある。いくら利益を出したとしても、税金で持っていかれる。結局手に入らない金であれば、広告費という形で消費するのも、まあ、悪い案ではないと思う。

税金といえば、今日から始めた広告も、(もし収益が入れば)、税金を収めなければならない。まあ、実際に収益が入ってから考えても、遅くはないだろう。今調べたところ、所得税の基礎控除は38万円だそうである。このような個人のブログが、果たして一年間でそこまで稼げるだろうか。

とりあえずAdSenseを有効にしてみた

最高にうざい。いままで、AdSenseを前提としたデザインにしてこなかった。ブログのデザインを変更する必要がある。

作業中

あまり大幅に変更する部分がない。

とりあえず、しばらくこのまま様子見。

そういえば最近、RE:を見ていない

「サイボウズ Office 7」 製品情報 > 基本セット > 社内メール

一日のメールの大半に「Re」が付いていて、何の件かわからないことが良くある。

そういえば、ここ数年、RE:という文字を見たことがない。なぜだろう。GMailを使っているからだ。

GMailは、RE:付きの返信を認識して、自動的に重ねてくれる。したがって、私はRE:というタイトルのメールを、ここ数年見ていない。

こんなに便利なのに、なぜ、他のメールクライアントは、追随しないのだろう。

とりあえずアマゾンの本の広告

アマゾンの広告を貼り付けるため、興味深い本を集めてみた。

まず、今話題のGC本。これ一冊、まるごとGCについて解説しているらしいのだが、残念ながら、まだ発売されていない。

ガベージコレクションのアルゴリズムと実装

次に、おなじみのC++ Templates。Nicolai JosuttisとDavid vandevoodeによって書かれた。これは、一冊まるごと、C++のテンプレートの解説に当てている本だ。最近、邦訳も出たらしいが、どうせ翻訳の質は良くないだろう。読むなら原書にすべきだ。

C++ Templates: The Complete Guide

C++ Templates Metaprogramming。これは、BoostのMPLライブラリの本だ。また、テンプレートに関する解説や、各種メタプログラミングのテクニック、Boostのプリプロセッサメタプログラミングにも、少しだけ触れている。

C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond (C++ In-Depth Series)

Object Oriented Programming in C++。これは、あのNocolai Josuttisの書いた、C++の入門書だ。洋書だが、是非とも読んでおくべきだ。

Object-Oriented Programming in C++

The C++ Standard Library: A Tutorial and Reference。これもまた、Nicolai Josuttis先生の書いた、C++のSTL本だ。非常に丁寧で詳細でわかりやすい。

The C++ Standard Library: A Tutorial and Reference

Nicolai Josuttis先生は、他にもIostream本を書いておられるようだが、Iostreamは役に立たないので、ここでは紹介しない。

やれやれ、なんだか初めて、このブログのタイトルにふさわしい文章を書いた気がする。そもそも、このブログは、本の紹介と読書感想のために、JUGEMに作ったのが最初なのだ。後にBloggerに移転した。JUGEMのブログは、もはや残っていない。

書き終わってからみてみたが、アマゾンへ画像付きのリンクを張り付けられるというのは、広告を抜きにしても、なかなか悪くない。

しかし疑問なのは、AdSenseだ。あの広告は、あまり自己主張しないので、まあ、邪悪ではないのだろうが、一体あれで、そんなに収益がGoogle側に上がるものなのだろうか。私は、たまに、サイトの中にAdSenseがあるのにすら、気がつかないこともあるのだ。未だに、謎だ。