2014-08-21

ファイルシステムの破損?、付記using宣言とusingディレクティブの違い

ここ最近、筆者の使っているコンピューターは不可解な挙動に見舞われてきた。再現性なく機能停止に陥るのだ。

機能停止、というのはなんとも大雑把な言葉だが、そうとしか表現しようのない状態になる。

何の前触れもなく、急に画面が真っ暗、あるいは単色になり、そのまま止まってしまう。ターミナルに切り替えることもできず、SysRqすらきかない。

しかし、Ubuntuのバグ報告をみても、それらしき現象はない。こんなにも頻繁に遭遇しているのに何故だろうか。ハードウェアの故障であろうか。

ところで、今日、不思議な現象に出くわした。bashのglob上からみると存在するはずのファイルが、なぜか実際には存在していないという現象である。つまり、echo *とlsで表示されるファイルが異なる。globからしか見えないファイルがある。不思議だ。例に再起動してみたが、やはりglobでしか見えないファイルがある。

はて・・・、これはいったい。

fsckでもかけてみようか。GNU/Linuxで起動時にfsckをかけるには、ルートディレクトリにforcefsckというファイルを作成すればよい。

sudo touch /forcefsck
shutdown -r now

fsckは一瞬で終わった。再起動後、glob経由でしか見えないファイルはなくなっていた。

いったい何だったのだろうか。さて、再現性なく発生する機能停止はなくなるだろうか、しばらく様子を見よう。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今、N4064のPerfect Initializationを理解するのに手間取っている。

ドワンゴ社内の近所の席から、GCCでusing宣言が動かないという声を耳にして、そんなバカなとコードをみたところ、

using namespace std::vector ;

なるコードが書かれていた。これはusing directiveだ。

usingディレクティブ

using directiveとは、書かれたスコープに、指定された名前空間スコープ内の名前を持ち込むものである。

// usingディレクティブ
namespace NS { int x ; }

void f()
{
    using namespace NS ;
    x ; // well-formed, NS::x
}

当然、usingディレクティブで指定する名前は、名前空間名である。stdは名前空間名である。std::vectorは名前空間名ではない。

using宣言

using declarationとは、書かれたスコープに、指定された名前を持ち込むものである。

// using宣言
namespace NS
{
    int x ;
    int y ;
}

void f()
{
    using NS::x ;
    x ; // well-formed, NS::x
    y ; // ill-formed. 名前yは見つからない
}

当然、using宣言で指定する名前は、名前空間名であってはならない。

確かに、多くのプログラマは言語を表面的な理解だけで使っているし、それでいい。普通のプログラマーは規格の細部に関わるよりも、動くコードを書くことに注力するべきである。

実際、usingディレクティブとusing宣言は、どちらもusingキーワードを使うし、その意味も、スコープに名前を持ち込むという似通った性質を持つので、混同されやすいのだろう。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

fork()は失敗するんだぜ、覚えときな

fork() can fail: this is important

あー、fork()のことね。プロセスがもっとプロセス作るためのやつな。いや、他にもプロセス作る方法はあるけどな。ま、面白い話がもうひとつあるから聞かせてやるよ。

forkは失敗するんだぜ。分かってるか? マジで分かってるか? マジだぜ。forkは失敗するもんだ。mallocと同じさ。失敗することもある。そんなに頻繁にってわけじゃないけどさ、でも失敗したら、無視できっこないぜ。ちっとは脳みそ働かせなきゃならん。

forkが0を返したら、そいつは子プロセスで、親なら正数を返すってことは、みんな知ってるよな。その値は子のpidだ。こいつを保存しといて、あとで使うってわけだ。

失敗を確認しない場合どうなるか知ってるか? そうだよ。お前多分、"-1"(forkのエラー通知)をpidとして扱ってるんだろ。

さて、問題の始まりだ。本当の問題は、シグナルを送るときにやってくるんだ。たとえば、お前、子プロセスを終了させたいとするだろ。

おまえkill(pid, signal)してるか? いや、kill(pid, 9)してるかな。

お前、pidが-1だったときどうなるか知ってるか? マジで知ってるべきだぜ。ヤバイからな。マジモンにヤバイぜ。

...

...

...

ほら、俺のLinux機からkill(2)のmanページをコピペしてやるよ。

もし、pidが-1と等しい場合、呼び出したプロセスがシグナルを送る権限を持つすべてのプロセスにsigが送られる。ただし、process 1(init)を除く

お分かりか? "pid -1"をkillするってのは、シグナル送れるすべてのプロセスを虐殺するってことだぜ。お前がrootなら、ほとんどすべてだ。お前は生き残るし、initも生き残る。だがそれだけだ。他は全部死ぬ。

お前、プロセスを管理するコード書いてるか? お前、テキストコンソールのgetty/login(initによって再起動される)とプロセスマネージャー以外ぜんぶ死んだ経験はないか? お前カーネルのoomkillerの責任だと思ったか?

そいつぁ濡れ衣かもしれないぜ。kill -1してないか今すぐ確認しろ。

Unix: この業界を飽きさせないために十分な数の落とし穴とトラバサミが仕掛けられている

ドワンゴ広告

この記事はドワンゴ出勤前に自宅で書いた。やはり作業はL字型の広い机で行うに限る。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-08-20

Sparc上のNetBSDでejectするとパニックに陷る問題の修正

CVS commit: src/sys/arch/sparc/dev

Modified Files:

src/sys/arch/sparc/dev: fd.c

Log Message:

fd(4)をオープンすることによるpanicを修正。違うポインターをmemset()に渡していたことが原因。

なんでこの18年もののバグがこれ以前に問題を引き起こさなかったのか謎だが(少なくとも、オレの昔の5.99.23カーネルでは動く)、おそらくはgcc 4.8がメモリ確保をよりアグレッシブに行うために表面化したのではなかろうか。

この問題はNobuyoshi Satoがfd(4)にeject(1)を試みた結果、発見された。

2014-08-19

Haskellの入門書を読んだ

先週、一週間丸々有給とリフレッシュ休暇を取って、都合9日間の休暇を作り出し、京都の吉田寮に遊びに行った。まだまだ読むべき論文がたまっているが、たまにはプログラミングもネットも一切忘れて息抜きをしてもよいだろう。吉田寮でだらだらと過ごすうちに、ふと、吉田寮に転がっていたHaskell入門書を読んでみた。

その結果、Haskellは、なかなか興味深い言語であることがわかった。

ここ数年、C++に提案されている新機能の多くに、Haskellにすでに存在する機能を強く連想させるものがある。なるほど、知り合いのC++プログラマーが、数年前にHaskellに手を出していたのは、そういう理由があったのか。

Haskellという言語に対する感想であるが、あまりに理想的すぎる印象を持った。なるほど、確かにコンパイラーの最適化が究極に賢ければ、Haskellのパフォーマンスは素晴らしい物になるだろう。しかし、現実にはコンパイラーがそこまで賢くなることは、近い将来には期待できない。

かつ、Haskellの入門書にかかれているサンプルコードは、極めて簡潔で理論的で言語的に美しいものであるが、その処理方法をよく考えてみれば、極めて効率が悪い処理である。

プログラミングの世界は、理論が数十年先行している。理論的には決着がついているものを、メモリやアドレスやキャッシュやパイプラインや同期といった制約のある現実のハードウェアに落としこむ必要がある。かつては、オブジェクト指向もそのような理論の一つだった。

Haskellの実用度は疑問ながら、その理論には痛く感心した私に、吉田寮にいる生物博士が言うのである。「次はCommon Lispの番だよ。遅かれ早かれC++はマクロを取り入れなければならないから、Common Lispはやらなければならない」と。C++風にまともなマクロを取り入れるのであれば、静的リフレクション機能として入るだろう。

完全にプログラミングから離れて遊ぶための休暇だったが、何の制約もない時間を確保できたことによって、かえって普段は手を出すことのない分野を学ぶことができた。やはり休暇は重要だ。

さて、Haskellの入門書を一冊読んだものの、まだ実際にコードを書いてはいない。やはりコードも書かねばなるまい。しかし、GNU/Linux環境でのx86-64アセンブリも書いてみたいし、C++の論文もたまっているし、C++の入門書も執筆してみたい。そういえば、勉強会のスライド資料作成もしなければならない。やることは多いが、とりあえず論文を片付けよう。

ドワンゴ広告

この記事はドワンゴの仕事をサボるために書いた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-08-18

2014-07 post Rapperswil mailingのレビュー: N4052-N4059

>2014-07 post Rapperswil mailingをレビューしていく。次の論文集の発表までに終わらせたいものだ。

N4052: WG21 2014-06-06 Telecon Minutes

2014年6月6日に行われた電話会議の議事録。

N4053: WG21 2014-06 Rapperswil Minutes
[PDF?] N4054: PL22.16 2014-06 Rapperswil Minutes

2014年6月の16日から21日にかけて行われたRapperswil会議の議事録。二つの議事録の内容はほぼ同一のようだ。

N4055: Ruminations on (node-based) containers and noexcept

vectorを、ムーブコンストラクターがnoexceptな要素と、そうでない要素でパフォーマンスを比較したところ、極端な違いがある。これは、vectorは強い例外保証のために、内部のストレージのサイズを拡大するときに、要素の移動にstd::move_if_noexceptを使ってムーブを試み、noexceptではないムーブコンストラクターを持つ要素の場合は、コピーにフォールバックするからである。

これは、std::vector< std::list<int> > のようなネストされたコンテナーの場合、より極端になる。

なぜlistのようなノードベースのコンテナーのムーブはnoexceptではないのか。listはその設計上、要素の最後に番兵が必要だ。なぜならば、end()はデクリメントできなければならず、デクリメントできるだけの何かを指していなければならないからだ。

さて、この番兵用のノードをどのように確保するかという問題がある。動的に確保するのは普通の方法だ。しかし、どうせ一つしか必要なく、またlistクラスのオブジェクトの生存期間中、常に必要になるので、クラスのオブジェクトのデータメンバーに含めてしまうというのはどうか。これにより、番兵用のノードを動的確保する必要がなくなる。

しかしその場合、listをムーブやswapした時に、番兵用のノードまでムーブやswapできなくなってしまう。つまり、番兵をオブジェクトに含める自走では、listのend()が絡むイテレーターのペアが、ムーブやswap時に無効化されてしまう。listの素晴らしい点は、イテレーターが無効化しないという強い保証にあるというのに。

実は、当初から、listをswapすると、end()イテレーターが無効になるかもしれないと、規格上は定義されていた。そのため、swapした結果、end()イテレーターが無効になっても、規格準拠の標準ライブラリの実装である。問題は、既存の主要なSTLの実装に、swapでend()が無効化しない実装があり、利用者はその挙動に依存してしまっている。それに、先程もいったように、いくら原稿規格が許しているからといって、listでイテレーターが無効になるというのは、listの強いイテレーター保証に対して違和感がある。

結局これは、ムーブ後の標準ライブラリのオブジェクトの状態は、そのオブジェクトは規定されているように使い続けられるという保証があるためにおこる。vectorのストレージ拡大の場合は、そもそもムーブ後のオブジェクトは即座に破棄するので、そもそも必要ない。

論文では、いくつかの改善案を示しているが、どれも根本的に問題を解決するものではないように思われる。

[PDF注意] N4034の破壊的ムーブも、この問題を解決するために提案されたのであろう。

N4056: Minimal incomplete type support for standard containers

STLのコンテナーを再帰的なデータ構造で使えるようにする提案。

// N4056提案
struct X
{
    std::vector<X> vec ;
} ;

のようなコードが書けるようになる。具体的には、コンテナーの要素型として、不完全型を認める制限緩和の提案になる。クラスは定義終了である}をもって初めて定義されたとみなされるので、クラス定義の中では、クラス名は不完全型なのだ。

既存の主要なSTLの実装は、かなりのコンテナーで要素型に不完全型を認めている。不完全型でも問題がないかどうかは、実装次第なのだ。Clangのlibc++の実装は、他の実装ならば認めているコンテナーでも、不完全型を認めていないコンテナーがある。

この論文の初版では、すべてのコンテナーに不完全型を認めようという提案であったが、Rapperswil会議で、ひとまず手始めにvectorとlistとforward_listに対しては不完全型を認める制限緩和をしようというコンセンサスが得られたらしいので、そのような提案になっている。

libc++の実装は、この提案を受けて変更が入っている。

[PDFを伝播する必要はない] N4057: A Proposal to Add a Const-Propagating Wrapper to the Standard Library

constメンバー関数は、ポインター風データメンバーの非constメンバー関数を呼び出すことができてしまう。

struct A
{
    void bar() const { } // #1
    void bar() { } // #2
} ;

struct B
{
    B() : ptr( std::make_unique<A>() ) { }

    void foo() const { } // #3
    void foo() { } // #4

    std::unique_ptr<A> ptr ;
} ;

int main()
{
    B b ;
    b.foo() ; // #4, #2

    B const cb ;
    cb.foo() ; // #3, #2
}

つまり、メンバー関数のconst性は、ポインターやポインター風のデータメンバーに伝播しない。

これは、C++の文法上、当然のことなのだが、論理的にはひっかかるところもある。そのために、論文では、const性を伝播させるライブラリ、propagate_constを提案している。


struct B
{
// ...

    std::propagate_const< std::unique_ptr<A> > ptr ;
} ;

このようにpropagate_constライブラリを使うことで、メンバー関数のconst性を正しく伝播させることができる。

[PDFを使うのは賢くない] N4058: Atomic Smart Pointers

アトミックに操作できる、atomic<shared_ptr<T>>, atomic<weak_ptr<T>>, atomic<unique_ptr<T>>の提案。

これらのスマートポインターに対して、特別にアトミックな特殊化の実装が使われる。

C++では、もはや生のポインターを扱うのはバカのやることである。unique_ptrは生のポインターを扱うのと同等のパフォーマンスと安全性を提供してくれるし、unique_ptrが対応できないような状況にも、shared_ptrは対応できる。しかし、現在のC++で、依然として生のポインターを扱わなければならない分野が存在する。アトミック操作を使ってロックフリーな処理を実装する場合である。このため、atomicに既存のスマートポインター用の特殊化を追加して、アトミックに操作できるようにする提案。

すでに、shared_ptrにはアトミックに操作する関数があるが、クラス外の関数で非常に使いづらい。

なかなかいい提案ではないかと思う。

N4059: Spring 2015 C++ Standards Committee Meeting

2015年4月の4日か9日にかけてに開かれるC++国際会議の案内パンフレット。

Perceptive Softwareがホスト、場所はミズーリ州カンザスシティ。

ドワンゴ広告

先週、土日と有給と、ドワンゴ独自のリフレッシュ休暇を組み合わせて9連休を作り出して、京都に遊びに行った。

休暇中に、なんとなしに吉田寮に転がっていたHaskell入門書を読んでみると、C++にここ数年提案されている新機能は、かなりHaskellの影響を受けているようであった。そろそろ理論を現実に落としこむ時期に来ているのだろう。

ちなみに、あるいかにも研究者らしい生物博士と雑談したところ、次はCommon Lispの番だという。いずれはLispのマクロを導入しなければならず、当然我々はLispをやるべきなのだという。

Cプリプロセッサーのような単なるトークン列によらない、文法やスコープを尊重するマクロは、入るとするならば、おそらく静的リフレクション機能の一つとして入るだろう。コード情報をコンパイル時に扱うことができ、またコンパイル時にコード生成を行えるような機能だ。

完全に遊ぶつもりの休暇であったが、色々と面白いことがあった。その次第は近日中に書く。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-08-08

2014-05-pre-Rapperswil-mailingのレビュー: N4040-N4051

[PDFとはお先真っ暗] N4040: Working Draft, C++ Extensions for Concepts

軽量コンセプトのドラフト文面案

Concerns with changing existing types in Technical Specifications

Issaquah会議で、TSはstd名前空間のライブラリを変更してよいと決定された。つまり、std::experimentalなどの実験的な別の名前空間の中にそっくりライブラリをコピーして変更し、またTSの文面もすべてをコピーした上で変更ではなく、TS文面は差分だけで良くなったし、std名前空間を直接書き換えてよくなった。

これは、色々と懸念事項もある。

ある実装がTSの実験的実装をしたとして、コンパイラーオプションなどで有効にできるようにしていたとする。TS機能を有効にした場合、ライブラリがABI互換性を静かに壊してしまう可能性がある。

また、std名前空間は標準ライブラリの実装にしか使う権利がないので、TSに完全準拠したサードパーティ実装ができなくなる。

TSの機能は、実際に実装されて、現実の利用者による利用経験が積まれなければ、規格に正式に取り入れるかどうかの判断ができない。

論文では、この懸念に対する明確な結論を出していない。

[PDFからまともなフォーマットへの安全な変換が望まれる] N4042: Safe conversions in unique_ptr<T[]>

現在、提案されているunique_ptr<T[]>は、派生クラスへのポインターから基本クラスへのポインターの変換は、危険なので禁止している。

struct base { } ;
struct derived { } ;

int main()
{
    // ill-formed
    std::unique_ptr<base[]> p( new derived[10] ) ;
}

しかし、この制限は強すぎて、以下のような安全な型変換も禁止してしまう。


unique_ptr< Foo const [] > ptr1( new Foo[10] ) ; // ill-formed
unique_ptr< Foo [] > ptr2( new Foo[10] ) ;
unique_ptr< Foo const [] > ptr3 = move( ptr2 ) ; // ill-formed
unique_ptr< Foo const [] > ptr4 ;
ptr4.reset( new Foo[10] ) ; // ill-formed

これは明らかに安全であるので、これは認めようという提案。

このような細かい条件でill-formedにするかどうかを切り替える方法には、static_assertを使う方法と、SFINAEを使う方法がある。static_assertはエラーメッセージも読みやすくはなるのだが、ハードエラーになってしまうという問題がある。そのため、論文では、規格の他の場面でもよく使われている、SFINAEによる方法を提案している。

この制限緩和は然るべきであると思う。

N4043: Dynarray Allocation Context

dynarrayで問題になったように、明示的なデストラクターの呼び出しとplacement newは問題になる。この論文はその問題に対処するために、デストラクター呼び出しとplacement newで再構築されない自動ストレージに関しては、実装依存の最適化を許す文面を追加することで解決しようとしている。

そういうここからここまでは実装依存と定義するだけの簡単な問題ではないと思うのだが。

N4044: A Three-Class IP Address Proposal, Revision 1

IPアドレスを表現するライブラリの提案

前回の論文からの変更点で、特にある人物の興味を引きそうな変更:「多くの関数がnoeceptと指定された」

[またPDFだ] N4045: Library Foundations for Asynchronous Operations, Revision 2

コールバックとfutureの両モデルをサポートする設計の紹介論文。

[PDFで書かれた論文の価値は低い] N4046: Executors and Asynchronous Operations

タスク単位を自動的に並列実行してくれる並列実行ライブラリの論文。

[暗い未来を予感させるPDFフォーマット] N4047: A Module System for C++

#includeの代替機能、モジュールの提案。

C++にはライブラリをコンポーネント化する近代的な機能が欠けている。C++にあるのは、Cから受け継いた#includeである。#includeとは単なるテキストデータをその位置に挿入するものである。コンパイラーからしてみればコピペだ。

#includeはC++の長いビルド時間の原因にもなっている。#includeされるソースコードの意味は、すでに定義されているマクロによって変わるし、#includeの後に続くソースコードの意味も、#includeされるソースコードで定義されているマクロによって変わる。

C++には、もっと近代的なライブラリの分離のための機能が必要だ。その機能はモジュールと名付けられ、設計が進んでいる。

この論文の提案は、既存のプリプロセッサー自体には何も変更を加えない。過去に、プリプロセッサーに付け焼刃的な変更を加えて害悪を軽減しようという提案はいくつもあったが、どれも失敗に終わっている。ぷりプロセッサーには長い歴史があり、短期的に廃止できるものではない。したがって、新しい機能は、プリプロセッサーと共存しなければならない。

提案では、新しいキーワードとして、moduleとimportのふたつを追加する。

モジュールを使うソースコードは、モジュールをimportする。

// N4047提案
import std.vector ;

int main()
{
    std::vector<int> v ;
}

モジュールは、最初の宣言でモジュール名を宣言する

// N4047提案
module std.vector ;

export
{
// 外部に見せる名前の宣言
}

export { }で囲まない名前は、外部に公開されない。ローカルな定義になり、他の翻訳単位でその名前を使った定義があったとしても、ODR違反にはならない。

// 1.cpp
module one ;

export { void f() { } }

void g() { }
// 2.cpp
module two ;

export { void g() { } }

void f() { }
// main.cpp
import one ;
import two ;

int main()
{
    f() ; // oneのf
    g() ; // twoのg
}

この三つの翻訳単位からなるプログラムをコンパイルしてもODR違反とはならない。モジュールでは、export { ... } で囲んだ名前のみが外部に公開され、それ以外の名前は外部に公開されず、ODR違反にもならないようになるからだ。

モジュールは相互の参照もヘンテコな前方宣言なしに書くことができる。

// A.cpp
module A ;

export {

import B ;

class A
{
    B * ptr ;
} ;
}
// B.cpp
module B ;

export {
import A ;

class B
{
    A * ptr ;
} ;

}

早くモジュールが実用化されて欲しい。

[PDFも改良してほしい] N4048: More Improvements to std::future<T> - Revision 1

N3865の改訂版。optionalのより汎用なライブラリ、expectedに対応した変更があるようだ。

[無PDF原則も提案したいところ] N4049: 0-overhead-principle violations in exception handling

例外において、ゼロオーバーヘッドの原則が尊重されていない例の提示。

例外にはオーバーヘッドがある。標準ライブラリは例外に強く依存しているので、例外を使ったコードを吐く。また、生成されるコードも、例外に対応するためのバッファーなどを持っている。これらはたとえ例外を使わなかったとしてもメモリ使用量を増加させる。そして、既存のリンク時コード除去やLTOは、これらのコードやバッファーを取り除くほど賢くない。

GCCには例外を使わないオプション-fno-exceptionsがある。しかし、これはフロントエンドで例外を使わないという指定だけであって、ライブラリは依然として例外を使うし、バックエンドが吐くコードも、例外のコードを吐くし、例外をサポートするためのコードや、例外が緊急時に使うバッファーなども確保する。これらはメモリ使用料を増加させる。

これらのオーバーヘッドを取り除くにはツールチェインに手を入れて、本当に例外を使わないようにするしかない。

論文は、現時点でのGCCの実装を示して、問題提起をするだけで、何も結論を出していない。

N4050: Dynarray Semi-Editorial Issues

dynarrayに対する文面上の些細な修正。とはいっても、単なる文法ミスや誤字脱字よりはすこし真面目な問題を修正している。

N4051: Allow typename in a template template parameter

テンプレートテンプレートパラメーターにtypenameキーワードを利用できるようにする提案。

今までは、

// 現状
template < 
    template < typename T >
    class U // classキーワードが必要
    >
class C ;

このように、テンプレートテンプレートパラメーターは、文法上の制約でclassキーワードを使わなければならなかったが、この提案では、typenameキーワードも使えるようになる。

// N4051提案
template < 
    template < typename T >
    typename U // typenameキーワードが使える
    >
class C ;

些細な変更だが、プログラマーの無用の混乱を防ぐために、入って欲しい変更だ。

ちなみに、Clangが-std=c++1zでN4051提案の実験的実装をしている。

Clang - C++1z, C++14, C++11 and C++98 Status

これで、2014年5月分の論文集が終わった。次は7月分だ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

来週は遠慮無く有給休暇を取ったので丸々休みだ。久しぶりに京都に帰省する。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-08-07

2014-05-pre-Rapperswil-mailingのレビュー: N4030-N4039

さて、5月分の論文集も残すところ後わずか。

N4030: Feature-testing recommendations for C++

C++の新機能が実装によってサポートされているかどうかを確かめる標準のCプリプロセッサーマクロの提案。具体的なマクロ名などは論文を参照。

// N4030提案
#if __cpp_binary_literals
int const packed_zero_to_three = 0b00011011;
#else
int const packed_zero_to_three = 0x1B;
#endif

__cpp_binary_literalsは、実装が二進数リテラルに対応しているかどうかを調べるマクロである。

筆者はCプリプロセッサーを使ういかなる機能にも反対の立場である。

N4031: make_array, revision 1

make_tupleやmake_pairのようなインターフェースで、std::arrayを返すmake_arrayの提案。

これにより、arrayのテンプレート実引数を推定でき、わざわざ手書きする必要がなくなる。

// 面倒
std::array< int, 5 > a = { 1, 2, 3, 4, 5 } 

// 簡単
auto a = std::make_array( 1, 2, 3, 4, 5 ) ;

// 型を明示することもできる
auto b = std::make_array<int>( 1 ) ; 

// array<char const *, 1>
auto c = std::make_array("hello") ;

// array<char, 6> d = { 'h', "e", 'l', 'l', 'o', '\n' } ;
auto d = std::to_array("hello") ;

narrowing conversionは禁止されている。

// エラー、narrwoing conversion
auto a = std::make_array(2, 3U)

なかなか悪くない小粒なライブラリだ。

N4032: Comments on continuations and executors

Anthony Williams本人が自ら、現在提案中の並列処理ライブラリを実装したところ、文面に様々な不備が見つかったとのことで、その不備を列挙して、然るべき修正案などを書いている論文。

executorがabstractクラスなのは不便だ。executorコンセプトを用意して、実行時ポリモーフィックな振る舞いには、別途generic_executor_refのようなtype erasureを使ったラッパーを容易すべきだ。

Scheduled Executorがタイムアウト指定にstd::chrono::system_clockを使うのはいかにもおかしい。std::chrono::steady_cloxkを使うべきだ。そもそも、タイムアウト指定にタイムスタンプを使うというのは、利用例の一部しかカバーできないので、やはり標準のabstract基本クラスと仮想関数を用意して様々な利用例に対応できるようにすべきである。

executorの種類が少なすぎる。executor *で返されるより、generic_executor_refで返すべきだ。その記述も不十分だ。

そのほか、futureに対する拡張案へのコメントが並んでいる。設計の不備、文面の不備を指摘するものが多い。

N4033: synchronized_value<T> for associating a mutex with a value

これもあの有名なAnthony Williamsの論文。T型を自動的にmutexでロックするライブラリ、synchronized_value<T>の提案

値に排他的なロックをかけるにはmutexを使うが、mutexをそのまま使うのは、甚だ面倒である。

int value1 ;
std::mutex m1 ; // value1用のmutex
int value2 ;
std::mutex m2 ; // value2用のmutex

void f()
{
    std::lock_guard<std::mutex> guard(m2) ; // おっと
    value1 = 123 ; // おおっと
} 

上記のコードは、ロックすべきmutexオブジェクトを間違えているのだが、残念ながら、コンパイラーはこれを警告してくれない。

この問題は、ある型のオブジェクトとそのオブジェクトを守るmutexを管理するライブラリがあればいいのだ。そこで、そのようなライブラリを論文著者はすでにDr. Dobb'sの記事として執筆していたが、その設計を手直しして正式に提案している。


std::synchronized_value value ;

void f()
{
    *valule = 123 ;
    int x = *value ;
}

仕組みとしては、synchronized_valueは、T型とmutexをメンバーとして持っている。operator *は、未規定の型を返す。この型は生成時に元のsynchronized_valueのオブジェクトのmutexをロックし、破棄されるときにmutexをアンロックする。また、T型へのリファレンスを返す。その結果、安全に自動的にロック、アンロックした上に、値の読み書きもできる。

これは、値の単発の読み書きをするにはいいが、複数の操作を一括して行うには効率が悪い。そのため、オブジェクトの生存期間の間だけロックし続ける、公に公開されているインターフェースもある。

std::syncronized_value<std::string> value ;

void f()
{
    std::update_guard< std::string > guard(value) ;

    *guard += "hello" ;
    *guard += "hello" ;

// guardのデストラクターでアンロックされる
}

N4034: Destructive Move

より制約が厳しい、保証された破壊的ムーブをするためのライブラリの提案。

現在のムーブというのは、ムーブ後のオブジェクトを、未規定だが有効な状態にするように義務付けている。つまり、ムーブ後のオブジェクトの状態は定められていないが、通常使えるように使えなければならないということだ。

しかし、クラスの実装によっては、これを無例外保証のまま行うのは難しい。そこで、破壊的ムーブの提案となる。

破壊的ムーブ(destructive move)とは、ムーブ後のオブジェクトは破棄された後であり、利用も、もう一度破棄することも出気ない状態になる。こ無例外ムーブが提供できないクラスでも、無例外破壊的ムーブは提供できるクラスは多い。また、ムーブされた後のオブジェクトはどうせ破棄する場合もある(vectorがその内部バッファーを増やす場合など)

また、破壊的ムーブというのは、単にバイト列のコピーで済ませられる場合もある。そのような条件を満たす型を、trivially destructive movable typeと名付ける。

具体的な提案としては、

template <class T>
void destructive_move(T* to, T* from) noexcept( /* see below */ );

という破壊的ムーブのための関数テンプレートの追加と、is_trivially_destructive_movable<T>という、trivially destructive movableな型かどうかを調べられるtraitsを追加する。destructive_moveは、is_trivially_destructive_movableがtrueの場合、バイト列コピーを行う。また、destructive_moveが特定の型に対してオーバーロードされていた場合は、ADLによって発見され、そちらが呼ばれるようになっている。

また、この配列版、destructive_move_arrayもある。

template <class T>
void destructive_move_array(T* to, T* from, size_t sz)
noexcept(is_nothrow_destructive_movable<T>::value);

リファレンス実装はhttp://halpernwightsoftware.com/WG21/destructive_move.tgzにある。これはBloomberg LPのBDEライブラリで5年以上使われていて、vector操作を劇的に高速化させたとのことである。

[論文フォーマットは暗黙にPDF以外のまともなフォーマットが使われるべき] N4035: Implicit Evaluation of "auto" Variables and Arguments

N3748の改訂版。

以下のようなコードを考える。

matrix A, B ;

auto C = A * B ;

上記のコードで、変数Cの型がなんであるかはわからない。matrix型かもしれないし、違うかもしれない。たとえば、matrixクラスの作者は、最適化のために、計算が実際に必要になるまで遅延させるため、内部的なラッパー型や、Expression Templateの技法を使った複雑な型を返しているかもしれない。

しかし、ここでmatrix型が欲しい場合、いったいどうすればいいのだろうか。

そのため、この論文では、autoを初期化するときに暗黙に型変換される型を、ライブラリ側で指定できる機能と、ユーザー側でその指定された暗黙の型変換を無効にする機能を追加しようと提案している。そのためには、できるだけわかりやすい文法を考えなければならない。

たとえば、matrixクラスは、operator *(Matrix const &, Matrix const &)の結果として、product_exprというラッパークラスを返しているとする。

論文では、いくつかの文法案が提案されている。

using宣言

class product_expr
{
public :
    using auto = matrix ;
} ;

このように記述すれば、auto specifierでは、暗黙にproduct_exprからmatrixに型変換される。型変換は通常通り、product_exprを引数として受け取るmatrixのコンストラクターとか、product_exprからmatrixへの変換関数として実装すればよい。

operator記法


class product_expr
{
public :
    matrix operator auto() { ... }
} ;

この文法の利点は、通常のコンストラクターや変換関数とは独立して、auto specifierのためだけの型変換処理が書けることである。ただし、そういう需要はあまりないのではないかとも思うし、戻り値の型を推定させた場合、何やらわかりにくい。

auto operator auto() { ... }

他にも、decayを特殊化してそれを特別に扱おうという提案もあるが、これは筆者は気に入らないので、わざわざここで紹介しない。

ユーザー側でこの余計なお世話を無効化する方法としては、explicitキーワードを使う文法が提案されている。

explicit auto C = A * B ;

David Vandevordeは、ライブラリで無効化することも可能であるという例を提示した。

auto C = noeval(A * B) ;

noevalの実装は以下の通り


template <typename T>
struct noeval type
{
    const T& ref;
    noeval type(const T& ref) : ref(ref) {}
    operator T const&() { return ref; }
    using auto= T const&;
} ;

template <typename T>
auto noeval(const T& ref)
{
    return noeval type(ref);
}

ライブラリの無効化のために、まさに提案されているこの機能をもう一度使うとはにくいコードだ。さすがはDavid Vandevorde。

[論文からPDFフォーマットの廃止に向けて] N4036: Towards Implementation and Use of memory_order_consume

2014年2月に、Linus Torvaldsが、GCCのML上で暴れていた。この論文著者とも殺伐とやりあっていた。

gcc archive, author index for February, 2014

Linusの主張はこうだ。

C11/C++11に入ったアトミック操作は使い物にならない。規格がクソすぎるためである。よってLinuxカーネルでは使わない。

規格化されたアトミック操作は保証が弱すぎる。したがって、Linuxカーネルのアトミック操作のすべてを置き換えることはできない。また、Speculative storeのような問題ある最適化を抑制することもできない。そもそもspeculative storeなんて許されるべきではないだろ。コンパイラー屋は、規格を指さして、「でもほら、規格上許されちゃってるんだよねーん」とかほざいているが、規格がぶっ壊れてる。ぶっ壊れたコード生成を正当化するためにクソぶっ壊れた規格を使っている。現実のハードウェアに基づかない規格などクソだ。

結局、問題に対処するために、Linuxカーネルではvolatileを使っている。アトミック操作ではすべての問題ある最適化を抑制できない。すると、volatileかつアトミック型を使わければならない。じゃあ、最初っからvolatileだけでいいじゃねーか。なんでわざわざアトミック型まで使わなきゃなんねーんだよ。

アトミック操作はまだひとつかふたつのプラットフォーム向けにしか実装されていないし、まだ実装経験が浅すぎてどうせバグだらけだ。結局、Linuxカーネルの今のやり方(volatile+インラインアセンブリ)は維持しなければならない。その上で、ひとつかふたつのプラットフォーム向けに標準規格のアトミック操作もつかってみよーかなーなんてなるわけねーだろドアホ。なんでそんなに複雑にしなきゃならねーんだよボケ。

そもそもmemory_order_consumeってクソすぎるだろ。なんだよこのcarries dependencyって概念はよ。コンパイラーが依存順序を完璧に解析できるわけねーだろ。で、明示的にkill_dependency()で依存を断ち切れって? ふざけんじゃねぇぞ。

そもそも、グローバルな最適化なんて糞食らえだ。ソースコードの解析だけですべてが分かると思うな。ソースコードに記述されていない、ハードウェアやモジュールなどの外部の別言語で書かれたライブラリがメモリを操作することだってあるだろうが。ローカルな最適化だけにしておけ。

標準規格はクソ使えないので我々Linuxカーネルではゼッテー使わねー。馬鹿げた机上の空論を捨てて、規格をさっさと直しやがれ。

論文著者は、規格化されたアトミック操作が現実の需要と乖離している理由を、コンパイラーの最適化手法が、7年前の規格化していた時と比べて、格段にアグレッシブになっていること、当時より長い依存チェインが現実に使われていることなどを上げている。

論文では、Linus Torvaldsでも満足する機能を提案しようと、型ベースの制限付き依存チェインとして、value_dep_preserving型指定子を提案している。

この論文を読むのはつかれた。アカデミックバリバリの2カラムのクソレイアウトを利用したクソみたいなtexで書かれたものをPDFで出力した論文で、しかも元のtexのソースコードは公開しないときているので、最高に読みづらかった。仕方がないので紙に印刷して読んだ。そして、背景事情を調べるためにLinusのGCC MLでの発言を追う必要があったので、これまた時間がかかった。

[非PDFドキュメントが欲しい] N4037: Non-Transactional Implementation of Atomic Tree Move

トランザクショナルメモリーを使わずに、lock contentioもできるだけおこさず、要素をあるツリーから別のツリーにムーブするアルゴリズムの考察。2014年のIssaquah会議でそういう課題が出たので考察したらしい。

論文では、バランスも何もないバイナリツリーのみを考察している。

論文自体は、あまりC++らしくない。ただ、C++会議でそのような条件を満たすアルゴリズムが現在存在しないので今後の課題として設定されたので、その道の専門家であるPaul McKenneyが考察したようだ。

N4038: Proposal for Unbounded-Precision Integer Types

C++の標準ライブラリに無限精度整数型の提案。

プログラミングにおいて、C++の基本型の整数型が表現しきれないほど大きな数値を扱う需要はよくある。特に、暗号用途には必須だ。C++用のそのようなライブラリは、多数ある。Javaはそのようなライブラリを標準で持っている。C++にも無限精度整数型が必要だ。

無限精度整数型(Unbounded-Precision Integer Type)とは言うものの、現実的には、有限のコンピューターリソース上に実装される以上、当然、有限の精度を持つ。ここでいう無限精度とは、ハードコードされた上限がなく、システムのリソース以外に桁数に制限を加えるものがないことを言う。

提案では、無限精度整数型であるstd::integer型と、無限精度ビット列型であるstd::bitsが提案されている。

std::integer型は、既存の組み込みの整数型と組み合わせて使うことができ、また組み込みの整数型がサポートしている演算はすべて同じ文法でサポートする。また、その他にも無限精度整数型を必要とする分野で需要ある演算をサポートする。需要あるすべての演算を網羅することはできないので、必要な演算を実装できる基本的な演算を提供する。abs, sqr, sqrt, pow, mod, mulmod powmod, gcd, lcmあたりだ。is_zero, is_oddがあるのも興味深い

また、integer型のメンバー関数のsizeとcapacityは、内部ストレージを再確保せずに表現できる10進桁数の上限を返す。reserveも桁数を取る。

現在表現している値を表現できる規模に内部ストレージを縮小するshrink_to_fitもある。

get_data_proxyというメンバー関数もあり、これは内部ストレージを直接見たり操作したりできる。

ちなみに、ドワンゴ社内では、競技プログラミングに使えるとの意見が多かった。

N4039: Default executor

現在提案中の並列実行ライブラリには、デフォルトのexecutorがない。デフォルトのexecutorはあるべきである。しかし、何をデフォルトにすればいいのか議論は付きない。タスクごとにスレッドを作るexecutorはわかりやすいが、一般的に、スレッドプールよりコストがかかる、しかし、スレッドプールでは、タスクがブロックされてしまうことがある。

論文は結論を出さず、それぞれのexecutorの利点、欠点を挙げるだけにとどまっている。

ドワンゴ広告

最近、ドワンゴのオフィスが入っている歌舞伎座タワーの7FのコンビニがICE BOXを置くようになったので、食べ過ぎないように鋼鉄の意思を要求されてつらい。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

妖怪ハウスのイベント予定

今月の妖怪ハウスで筆者が予定しているイベント一覧

8月7日夜、ドライフルーツヨーグルト試食会、焼き肉

8月8日夜、Monty Python鑑賞会、多分焼き肉

8月23日、ボードゲーム会、スイーツ(笑)会

2014-08-05

何でWindowsは俺のワイヤレスキーボードをトースターだと認識するんだ?

device manager - Why does Windows think that my wireless keyboard is a toaster? - Super User

俺は彼女の父親から古いPCを相続したんだが、プリンターを設定していると、ちょっとおどろきのものが現れた。

画像

さて、二つの疑問がある。

  1. なんでWindowsは俺のワイヤレスキーボードをトースターだと認識するんだ?
  2. なんでWindowsはデバイスメニューにトースターのアイコンを持っているんだ?

なぜか、質問者のワイヤレスキーボードに、トースターのアイコンが表示されている。Windowsはなぜそんなアイコンを用意しているのだろうか。

答えは。

理由1

Microsoftはトースター用ドライバーというサンプルを作っている。このサンプルでは、<DeviceIconFile>Toaster.ico</DeviceIconFile>という行があり、おそらく、お前のキーボードの製造業者は、このサンプルをそのまま使ったのだろう。

理由2

キーボードの裏に、食パンを差し込む口は見当たらないか?

どうやら、Microsoftがサンプル用に作ったトースター用のドライバーのデバイス情報のXMLファイルをそのまま使ったずぼらなキーボードメーカーがいるらしい。サンプルのアイコンがトースターなのは、Microsoftのユーモア精神なのか、そのままコピペして使うずぼらなハードウェア製造業者を防ぐためなのか。それでもコピペはされる。

それにしても、USBトースターはあまり実用になりそうにない。一般的なトースターの消費電力は1000Wはある。一方、USBは3.0でもせいぜい100W程度の電力しか供給できない。USB3.0ポートを制御用に1ポート、電力供給用に9ポート必要とするトースターだろうか。電源ユニットも相当によい物を使う必要がありそうだ。

2014-08-04

ループカウンタを64bitにしたり、 バッファのサイズを定数にしたらパフォーマンス激落ちなんだけど何で?

c++ - Replacing 32bit loop count variable with 64bit introduces crazy performance deviations - Stack Overflow

stackoverflowで、興味深い質問が行われている。

簡単にまとめるとこうだ。std::uint64_t型の配列の各要素にx86-64のpopcnt(1になっているビット数を数える命令)を適用したい。

コードの肝心の部分を書くと、以下のようになる。

for (unsigned i=0;i<size/8;i+=4) {
    count+=_mm_popcnt_u64(buffer[i]);
    count+=_mm_popcnt_u64(buffer[i+1]);
    count+=_mm_popcnt_u64(buffer[i+2]);
    count+=_mm_popcnt_u64(buffer[i+3]);
}

ループの中で、バッファーの要素を4個づつ、Compiler Intrinsicに渡して、popcntを実行している。

さて、ここで奇妙な事実がある。Sandy/Ivy BridgeやHaswellで、ループカウンター用の変数であるiの型をunsigned int型とstd::uint64_t型とでベンチマークを取ってみると、質問者の環境で、unsigned int型の処理速度は26GB/sだが、std::uint64_t型では、13GB/sと、速度が激減するのだ。

これはGCCのバグなのだろうか。しかし、Clangで実験してみても、やはりunsigned intが26GB/sに対し、uint64_t型は15GB/sと、明らかに処理速度が違う。

更に良くわからないことがある。バッファーのサイズを保持するsize変数であるが、バッファーサイズは実行時の入力により決定されるため、定数ではない。しかし、バッファーサイズを決め打ちにしてsizeを定数にしてみると、なんと性能はunsignt intもuint64_tも共に20GB/sになる。Clangでは、どちらも15GB/sになる。

size変数をstaticにしてみると、uint64_t型でも、20GB/sにまで速度が改善する。

いったい何なのだ。

最も投票数の多い回答が興味深い。

この不思議なパフォーマンスの変化の理由は、IntelのSnady/Ivy Bridge, Haswellのpopcnt命令の、不必要なデータ依存によるものだという。

popcnt src, dest

とあったとき、なぜかIntelのCPUは、結果を出力する先のレジスターにデータ依存が発生するのだという。そのため、destに指定されたレジスターの値が定まるまで、後続のpopcntを並列実行できず、スループットが落ちるのだという。しかし、destはどうせ上書きしてしまい、直前の値は何の意味も持たないので、データ依存もクソもないはずなのだが。

現時点で、GCCはこのIntelのCPUの奇妙な挙動をまだ把握していない。コンパイラーはCPUごとのこのような特性を把握して、事前にxor reg, regなどしてデータ依存をそぎ落としておくべきなのだという。

AMDのCPUにはこのような不必要なデータ依存はないそうだ。

なぜループカウンター用の変数の型を64bitにしたり、バッファーサイズを保持する変数を定数にしたりするだけで結果が劇的に変わるかというと、コンパイラーのレジスタ割り当てが変わるためだという。

一体、何故こんな不必要なデータ依存が発生するのかという疑問であるが、回答者は、IntelのCPUはオペランドを二つ取る似通った命令を共通の方法で処理していて、popcntと何らかの命令を同じ枠組みで処理しているためではないかとしている。このようにすることで、プロセッサーの設計を簡単にできるのだとか。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-08-03

momonga.vim #6 in ドワンゴ

2014年8月2日の土曜日、momonga.vim #6が、ドワンゴのセミナールームで開催された。

momonga.vim #6 in ドワンゴ(あきらかに) - connpass

momonga.vimとは、もくもく会だ。もくもく会とは、一人では集中して作業できない人間が、皆で集まるという強力な理由付けの元に、何らかの作業をするという会だ。もくもくはいったいどこから始まったのかという疑問であるが、おそらくphaさんが始めたのではないかと思う。

今回、ドワンゴのセミナールームでVimのもくもく会が開催された理由というのは、momonga.vimの主催、@supermomongaさんが、勉強会に使える会場を探していたからだ。何でも、最初は自宅でやっていたらしいが、指数関数的に参加に人数が増えていき、このままでは年末には武道館が必要になる増加率であるという。ドワンゴのセミナールームは煩悩の数と同じ108人入り、マイク、プロジェクター、WiFi、椅子と机、ホワイトボードなどの、勉強会に必要な設備はひと通り揃っているので、勉強会に最適である。

さて、人数自体は108人入るのだが、あまりに大勢を入れ過ぎると、もくもく会の趣旨に反するとのことで、募集人数は40人に設定された。

さて、当日の筆者は、場所を提供するスタッフとして12時半頃に会場に行った。

懸念事項としては、当日にももんがさんが来るかどうかという究極の問題がある。ももんがさんというのは、極めて億劫な人であり、家から出るのが億劫で来ないということは十分に考えられるからだ。とはいっても、さすがに今回は自分で主催した勉強会であるので、十分に家から出てくる理由がある。

幸い、そういうことはなく、本人は早めに会場に到着した。しかし、8月1日の21時に起床したとのことで、若干の違和感は残った。

さて、今回の勉強会には、あの暗黒美夢王(Dark Vim Master)が来た。暗黒美夢王には、開始と締めくくりに、かの有名なエディ歌を披露していただいた。エディ歌とは、編集王(エディットキング) バトルエディターズに使われている歌である。

さて、もくもく会は、もくもく会であるから、特に特筆すべきこともなく各人が黙々と作業していた。

さて、最後に進捗のある人の発表が行われた。なにしろ、Vimに関連する作業である。Vimとはテキストエディターである。テキストエディターである以上、人目を引く見た目にわかりやすい何か動きのある発表などあろうはずもない。

ところが、なんとVimうさぎさん(C++力ないよー) (rbtnn)が、Vim上でマリオのようなものを実装しかけていた。

さて、もくもく会のあとは、妖怪ハウスで懇親会を行った。懇親会では、もう何度目かわからないピザを焼いた。ピザはだいぶ慣れてしまった。今後は別の具に挑戦したいところだ。

さて、日曜日はのんびりするとしよう。

ドワンゴ広告

この記事は日曜日ののんびりした気分で書かれた。

ところで、ドワンゴで筆者が企画して開く勉強会は、私は出勤扱いになる。そのためこの勉強会で筆者、なんと社畜らしく休日出勤してしまった。休日出勤した以上、代休を取らねばならない。

ところで、ドワンゴ社内のテキストディター利用率の統計が取られたことはないが、おそらくEmacsよりVim勢のほうが多数派ではないかと思われる。ドワンゴでは社員が各自好きなテキストエディターを使っている。なぜならば、テキストエディターはソースコードの読み書きをする極めて重要なツールであるので、プログラマーの好みが激しい分野である。テキストエディターの選択はプログラマーに委ねられていなければならないのだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-08-02

任天堂の使っている自由ソフトウェア

任天堂ホームページ:任天堂製品に関連するオープンソースソフトウェアのソースコード配布ページ

任天堂がひっそりと、自社製品で使っている自由ソフトウェアを公開している。

残念ながら、彼らはオープンソースという誤った用語を使っている。オープンソースというのは誤った運動であり、誤解を招きやすい用語だ。自由ソフトウェアという用語を使うべきである。

WiiUや3DSのファイルは相当に大きいので落として確かめていないが、Hacker Newsによれば、改変版Webkitとか、MSVCでコンパイルできるようにしたBluetoothライブラリとかだ。バーチャルコンソールにはMozillaのnanojitが使われているらしい。

WiiUのバーチャルコンソールがサイズも小さいので実際に落として確認してみたところ、nanojitが入っていた。

気になるのは、マリオカート8に使われている、BluetoothのSBCコーデックのライブラリだ。COPYINGをみるとGPLとなっている。ただし、COPYING.LIBをみると、LPGLとなっている。これはどういうことか。

ソースコードの著作権表記によると、どうやらSBCライブラリはLPGLで、そのライブラリを使ったsbcdecとかsbcencとかがGPLらしい。なるほど、sbcdecやsbcencはそのままマリオカート8に使うわけでもないし、任天堂が使っているのはLGPLのSBCライブラリだけなのだろう。

まあ、残念ながら、あまり面白いことはない。少なくとも、任天堂はCとC++を使っているということが明らかになっただけだ。

任天堂の秘密主義は本当に危険だ。私は任天堂のハードウェア用のプログラミング環境について、ほとんど知らない。どんな言語を使っているかすら、推測するしかない。これは、任天堂が馬鹿げたNDAを結んで、情報を公にしていないからである。

しかし、ガラケーの黒歴史で学んだように、我々は公開されていない情報から学ぶことはできない。公開されていない情報は見つからないからだ。公開できない情報は、他人と相談することができない。他人と知識の共有ができない場合、何とかひねり出したクソみたいな方法を、ノウハウだと勘違いしてしまう。

ガラケー時代は、ライブラリのインターフェースすら公開することができなかった。しかし、公にならない情報から人は学べないのだ。

そんな状況で、どうやって優秀なエンジニアを雇うというのか。情報が公開されていない場合、外部の人間は学ぶことができないので、新たにエンジニアを雇おうとしても、任天堂のハードウェア上のプログラミング経験は一切ないド素人を雇わなけばならないわけだ。いかに優れたエンジニアであっても、任天堂のハードウェアに関しては、学ぶ方法がないのだからド素人だ。全く経験したことのないハードウェア、ツール、ライブラリを学ぶのには、時間がかかる。何と無駄なことをしているのだ。

任天堂が落ち目なのも、当然だ。

それに、もはやゲーム専用機の時代は終わった。なぜゲームしかできない機械をわざわざ持たなければならないのか。今や筆者を除く誰もが持っているスマートフォンは、十分な性能を備えていて、クッキークリッカーやハイパーオリンピックぐらいなら余裕で実装できる。ハイパーオリンピックは、当時おおはやりしたゲームである。クッキークリッカーは最高のゲームである。そして、今はソシャゲというクッキークリッカーやハイパーオリンピックが流行っている。そう、ゲームの本質はクッキークリッカーやハイパーオリンピックだったのだ。あれでよかったのだ。自分の行動がゲームに良い成果となって現れるだけでよかったのだ。そこの深い技量など正確で高速な入力だのは、必要なかったのだ。自分の行動には、課金も含まれる。もはやパッケージを売って利益を上げる必要もないのだ。必要なのは継続的な課金するほどの価値の提供であって、高価なパッケージの抱き合わせ商法や品薄商法や限定版商法ではないのだ。

ところで、筆者は最近、ゲームをした。

Xibalba

未来からやってきたオールドスクールなシューターだ。久しぶりにいいゲームをした。

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-27

Linus Torvalds、 GCC 4.9.0のコード生成にブチ切れる

Phoronixで知ったが、Linus TorvaldsがGCC 4.9.0のコード生成にブチ切れている。

問題はLinuxカーネルのload_balance()がランダムにパニックを起こすというもので、その原因は、報告者の使っているコンパイラーであるGCC 4.9.0のコード生成がおかしかったという話だ。

Linus様は御自ら生成されたコードを読み給い、平生と変わらぬ調子で物事の道理を示された。

Linux-Kernel Archive: Re: Random panic in load_balance() with 3.16-rc

From: Linus Torvalds
Date: Thu Jul 24 2014 - 14:47:25 EST

On Wed, Jul 23, 2014 at 6:43 PM, Michel DÃnzer <michel@xxxxxxxxxxx> wrote:

>> マイケル、
>> make kernel/sched/fair.s
>> やった結果のファイルを送ってくれないか?
>
> はいよ。gzipした。これでいいといいんだけど
> ところで、俺のツリーは3.16-rc6だ。

オッケー、コード生成みてるんだが、お前のコンパイラはマジで最高にクソだな。

Jakubをccに追加。gcc-4.9.0は致命的にぶっ壊れてるみたいだぜ。

見ろよコレ。お前のコンパイラーはなんか完全にトチ狂ったもの吐いてるぜ。定数とかな。マジで、このコンパイラーは幼稚園を卒園するのすら認められるべきじゃねーだろオイ。マジで「赤ん坊んときに落っこちて頭を打ったナマケモノ」レベルのアホレベルだぜ、コレは。

movq $load_balance_mask, -136(%rbp) #, %sfp
subq $184, %rsp #,
movq (%rdx), %rax # sd_22(D)->parent, sd_parent
movl %edi, -144(%rbp) # this_cpu, %sfp
movl %ecx, -140(%rbp) # idle, %sfp
movq %r8, -200(%rbp) # continue_balancing, %sfp
movq %rax, -184(%rbp) # sd_parent, %sfp
movq -136(%rbp), %rax # %sfp, tcp_ptr__
#APP
add %gs:this_cpu_off, %rax # this_cpu_off, tcp_ptr__
#NO_APP

定数の-136(%rbp)を見ろよ。マジかよ。コンパイラーが吐いてるのは 即 値 だぜ。

誰かGCCにバグ報告しろよ。こりゃマジでぶっ飛んだクソだからな。

だが、定数を吐くのは「バカすぎて耐えられん」程度のことでしかない。本当のバグはこれだ。

movq $load_balance_mask, -136(%rbp) #, %sfp
subq $184, %rsp #,

gccはスタックフレームを作ってるんだが、すでにスタックフレームの奥底に定数を保存した後でやってやがる。

x86-64 ABIはスタックポインターの後に128バイトのレッドゾーンを規定してて、これはその規程の元ならばセーフだ。どうもよくない気がするが(136 > 128)、だが問題は、フレームポインターを読み込むために、"pushq"を4つ%rspを更新するために使っているので、これはレッドゾーンギリギリのかろうじてセーフだ。

しかし、カーネルは-mno-red-zoneでビルドされている。ここではx86-64 ABIのレッドゾーンには従わない。というのも、カーネルモードでは割り込み不可能だし、スタックはレッドゾーンなしで使う。だから、"-mno-red-zone"は「推奨事項」なんかじゃなくて、カーネルに絶対必要な要件なんだよ。にもかかわらずgcc-4.9はバグだらけの一本グソなので無視しやがる。お前がこのバグにぶち当たった理由は、たまたま一命令を実行中に都合よく割り込みにひっかかったからだ(もしくは、似たようなことがすでに何度か起きていて、カーネルのデータ構造をすでにぶっ壊したか)

さて、俺が思うに、このレッドゾーンバグと、GCCがアホすぎて定数を吐くバグは、なんか関係していると思うね。なんか生存解析(liveness analysis)かなにかで、スタックデクリメントをいつ挿入するのかを決定しているが、定数には生存もクソもあったものじゃねーから無視されるとかさ。つまり二つのバグ(「アホみたいな定数吐くバグ」と「レッドゾーンスタックの不正な利用」)がうまく組み合わさったんじゃないかな。よくわかんねーけど。

とにかく、これはカーネルのバグじゃない。お前のコンパイラーが完全にぶっ壊れたコードを生成してる。gcc-4.9.0で誰かがコンパイルしないように警告すべきだし、Debianの奴らはピカピカの新しいコンパイラーをダウングレードするだろうよ。

Jakub、どう思う?

Linus

そして、Linus様は御自らGCCにバグ報告なされた。

Bug 61904 – Incorrect stack red-zoning on x86-64 code generation

Linus Torvalds 2014-07-25 19:01:36 UTC

(In reply to Andrew Pinski from comment #9)

> 問題のあるコンパイラーのバージョンは4.5.0(debug_insnが使われた時)から4.8.3までと、4.9.0と4.9.1だ。

なるほど、問題のあるコンパイラーのバージョンを避ける方法はないわけだ。4.9.0/1には警告を出せるだろうけどな。まだあまり一般的じゃないから。

やれやれ、コンパイル後にテストパスを追加する提案があるんだよ。だが、今のところ、手のひらをかざす(objdump + perl-script)程度のことだ。あまりイケてない。

問題は、こういうのはめちゃくちゃデバッグしにくいということだ。絶対ありえないはずのkernel oopsや破損を引き起こす。今回の問題はたまたまある二人にとって再現性があって特定箇所だったというだけの話だ。他にもあるのか? それを知る方法はない。

とにかく、素早く対応してくれてありがとよ。ただこの分だと既存のコンパイラーもちょっと心配になってきたんだがな。

さすがはLinus様だ。

2014-07-26

ロスレス圧縮アルゴリズムの歴史

History of Lossless Data Compression Algorithms - GHN: IEEE Global History Network

ロスレス圧縮アルゴリズムの歴史がまとめられている。

かなり長いので、詳細はリンク先を参照。

読み終わった感想を一言だけ言うと、特許のせいでいくつものアルゴリズムが発展せずにそのまま死んだということだ。特許は技術革新を阻害している。

キャンプの計画は難しい

この夏はキャンプにでも行きたい。キャンプに行きたければ、自分で企画するのが確実である。しかし、キャンプの企画は難しそうに思える。

まず、告知して人を募集しなければならない。そして、キャンプ場を予約する必要がある。キャンプ場までの移動手段も確保しなければならない。結構面倒な作業が必要そうだ。

キャンプ場では、ロッジのような出来合いの家を借りるのが一番手っ取り早い。クーラーやキッチンも設置されているし、言うことがない。しかし、それは面白いと言えるのだろうか。かといって、テントを設置するとなると、今の時期はとてつもなく蒸し暑くなるだろう。人が増えれば増えるほど不快になっていく。テントを設置する場合は、春か秋にしたほうがよさそうだ。

費用は、10人から20人ほど入れるロッジで、だいたい一日5,6万円ぐらいのようだ。これを10人から20人で割れば、まあ、費用としてはそれほどかからない。後は食材費や交通費ぐらいだろう。

残念ながら、キャンプ場というのは、かなり早めに予約しておかないと、予約で埋まる。二ヶ月ぐらい余裕をもっておいたほうがいいだろう。

2014-07-25

PHPの次のバージョンはPHP 7かもしれない

PHP: rfc:php6

PHPの次のバージョンは、PHP 6ではなく、PHP 7となる可能性があるとのこと。

敬意を説明すると、PHP 6は、次のPHPのメジャーリリースとして、2005年から盛んに開発されていたが、2010年にUnicode実装の難しさから頓挫した。言語でUnicodeを直接サポートする以外のPHP 6向けの機能は、大方PHP 5.3か5.4に取り込まれた。

この経緯のため、既存の多くのドキュメントや参考書などが、すでにPHP 5.xに存在する機能をPHP 6にやってくる新機能として紹介している。このままPHP 6を出すと、すでにPHP 6であると喧伝されているものとはことなるので、利用者が混乱するのではないか。

そういう理由で、PHPではバージョン番号6をスキップして7に行く議論があるそうだ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

そういえば、今日はある有名なドワンゴ社員が社内IRCにURIエンコードされたJPEG画像を発言していた。ドワンゴ社員ともなると、BASE64の脳内デコードはおろか、JPEGの脳内デコードもできるものらしい。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

Linuxカーネルのバグをgit bisectで特定する話

Odd Bits - Tracking down a kernel bug with git bisect

Linuxカーネルのバージョンを3.15に上げたところ、Docker内でのsuやrunuserが謎のシステムエラーで動かなくなった。カーネルのバージョンを3.14に下げると問題なく動作する。明らかにカーネルが影響を及ぼしている。

よろしい、ならばgit bisectだ。git bisectは良いコミットと悪いコミットの間をバイナリサーチして、問題を引き起こしたコミットを見つけてくれる。

しかし、Linuxカーネル3.14と3.15の間には、約15000件のコミットがあるので、git bisectを手動で回すのは現実的ではない。

git bisectには、自動化のための仕組み、git bisect runがある。これは、コミットをチェックアウトした後に、自動でスクリプトを実行して、現在のコミットが良いか悪いか判断してくれる。したがって、自動化するスクリプトさえ書けば、あとは自動でgit bisectを走らせておけるはずだ。

とはいえ、結構面倒だったという。

まず、コミットが良いか悪いか判断するには、現在のコミットのLinuxカーネルをコンパイルして、実行して、Dockerを実行できるほどには構築されたシステムを立ち上げ、Dockerを実行してその中でテストを実行し、その結果を何とかしてビルド環境まで伝えなければならない。docker pullも行うので、ネットワークも必要だ。

元記事の筆者は、何とかしてその自動化環境を作り上げた。

さて、しばらく実行すると、git bisectは悪いコミットを特定したのだが、残念ながら、そのコミットは多数の変更を含むマージコミットだった。確かに、問題をもたらしたコミットには違いないのだが、まだ本当のコミットを特定できたわけではない。

そんなわけで、そのマージに含まれるコミットに対してさらにgit bisectをかけると、問題のコミットが見つかった。

問題の詳細としては、これはユーザースペースのソフトウェアの挙動に変化をもたらすものではあるが、権限の有無の問題であるので、Docker側を直すほうが望ましいとのことらしい。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

N4036があまりにも読みづらい自己満足レイアウトを利用しているので読む意欲が保てず、気分転換に最近読んで面白かった記事を紹介した次第。

そういえば、Ubuntuにはrunuserがないのだな。suで代用できるか。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-24

Pixivに会社見学に行ってきた

とあるきっかけでpixiv社員と知り合ったので、この機会に、Pixivに会社見学をしてきた。

Pixiv社内は、大変にカラフルな環境であった。レゴブロックの形を模した椅子があり、レゴブロックのように積み重ねることができた。

また、机も変わっていて、すべての板がつながっている不思議な配置になっていた。

また、社内には、大昔のゲーム販売店の展示用の巨大なゲームボーイや、任天堂からゲーム販売店に送られた送り状が貼り付いたままのバーチャルボーイが置いてあった。筆者は、当時バーチャルボーイの店頭デモをプレイしたことがある。当時の感想は、残念、の一言に尽きる。

また、Pixivの入り口は、全面的に絵馬が貼り付けてあり、訪問者による絵やメッセージが並んでいた。これは粋な入り口だ。Pixivが提供するサービスと合致していて、実にいい入り口だ。

絵馬に描かれた絵には様々なものがあったが、いったいどうやってこれを描いたのかと疑問に思うほど技巧的な絵もあった。

あるドワンゴ社員の絵馬もあった。Pixivには日々お世話になっているのであろう。

筆者も、C++ Evangelist 江添亮と書き付けておいた。

技術的な話もしたが、PixivはC++は使っていなかった。

ところで、Pixivといえば、初期は社内の一角にメタルラックにマザボやHDDを無造作においたものがPixivを動かすWebサーバーだったそうだが、今はさすがにそうではない。しかし、メタルラックにマザボやHDDを無造作に置いたサーバーは、今のPixivにも存在していた。何でも社内のサーバーとして使われているそうだ。文化が残っているのは面白いことだ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

なぜ昨日のドワンゴ勤務中にこの記事を書かなかったかというと、メガネを忘れたからである。帰宅してから当日中に書くという手もあったが、しかし、すでにPixiv社内で、ドワンゴ勤務中にPixiv訪問ブログを書くと言った手前、やはりドワンゴ勤務中に書くことにした。

ところで、後でドワンゴ社内で聞いた話によると、Pixivにはドワンゴのポーカー部の絵馬もあるという。なんと、それは気が付かなかった。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-21

最近の動向

どうも、先週の月曜日から火曜日にかけて、午前3時頃まで起きていたのが災いしたのか、体調を崩してしまった。その週は、なぜかすこし疲れやすいぐらいの感覚だったのだが、金曜日には明らかに体調に不調を自覚するほどであった。

しかし、不調とはいえ、わずかな頭痛と熱とノドの痛みだけで、体はだるくないし、特に横になる必要も感じない。なかなか変な体調の崩し方をしたものだ。それでも、体調がよろしくないことは確かなので、この三連休は、運動をせずになるべく寝ていた。

さて、月曜日になって、だいぶ体調がよくなったので、たまには最近の自分のことでも書くことにする。

まず、何故か私宛に足袋が届いた。アマゾン経由ではないようだが、誰かが私に送ってきたらしい。雪駄はすでに持っているので、ちょうどいい。

また、最近、新しい料理に挑戦した。豆料理を作ろうと思い、大豆を1kg買ってきて水煮した。

大豆は主に、トマト煮に使った。トマト煮には、大豆の他にも、玉ねぎと人参をいれた。また、ひき肉も入れるとうまい。

それでもどうしても大豆が余ったので、さいごにひじき煮を作った。大豆とひじきと人参をだし汁で煮詰めると出来上がる。やや味付けが濃かったが、初めてにしては上出来と言えるだろう。油揚げを入れてもよかったかもしれない。

ところで、最近、ミートソースを作る機会が多い。ミートソースは、玉ねぎ、人参、セロリをみじん切りしてそれぞれフライパンで炒める。ひき肉も十分な量を炒める。1kgの大きなホールトマト缶を使い、十分に水分がなくなるまで煮込むと、うまいミートソースになる。十分に煮こむのは重要だ。ミートソースは、普通に作れば普通にうまい。一度自分でミートソースを作ると、出来合いのミートソースが食べられなくなる。それにしても、何故東京にはまともなミートソースを出す店に、未だに巡りあえていないのだろうか。

また、最近作った料理としては、白和えがある。白和えというのは、ほうれん草とか水菜とか人参などの野菜に、潰した豆腐を混ぜて、だし汁で味付けするだけの簡単なものだ。美味しいのだが、どうしても作ると量が多くなってしまう。

今回の三連休は、あいにくと体調を崩していたのであまりはかばかしいことはできなかった。なにか新しい料理にも挑戦したかったし、せっかくなのでどこかに遊びに行きたかったのだが、体調が悪くて終日寝ていた。

2014-07-18

2014-05-pre-Rapperswil-mailingのレビュー: N4021-N4029

5月分の論文集も、これで残すところあと21本だ。ただし、7月分の論文集が69本控えている。

[重量級PDF] N4021: A Proposal to Add 2D Graphics Rendering and Display to C++

C++1yに2Dグラフィックライブラリを入れる提案論文。

グラフィックは今や日常のプログラミングに必要である。グラフィックを描画する方法は、標準で用意されているべきである。

現在の提案では、既存のcairoの設計を元に、C++風の変換をして、またインターフェースを現代的なC++に手直しして使うことになっている。

新規のAPIを設計するのはとても手間がかかる。実験的な実装をして、実際に検証する手間は莫大だ。そこで、既存の、すでに実装されていて、実績もあるcairoライブラリを土台にする。

あらゆるプラットフォーム向けのすべての機能を規格化することはできない。そこで、std::threadと同じ手法を取り、ネイティブなハンドルを取得する方法を規定することにした。これにより、C++利用者は、実行環境に依存する機能も使うことができる。これは、すべてが実行環境に依存するライブラリを使うよりよほどいい。

context型とsurface型を統一することにした。surfaceというのは、描画ターゲットであり、画面とか純粋なメモリ領域とか、あるいはファイルや出力ポートといったたぐいのものだ。surfaceへの描画は、contextを経由して行われる。これは、古典的なグラフィックAPIによくある設計だ。しかし、果たして現代でも理にかなった設計であろうか。

contextは、リソースを共有でき、大昔は、メモリの節約に役立つ設計であっただろう。しかし、今では事情が異なっている。

cairoでは、contextは、既存の別のsurfaceに関連付けることはできない。surfaceからcontextを作成すると、contextの寿命は、その作成元のsurfaceに一生紐付けられる。つまり、利用者の視点からすると、わざわざsurface型とcontext型が分離している意味がない。surface型を直接操作すればいいのだ。

そこで、この論文では、context型とsurface型を統一することを提案している。

論文では、ほとんどの型はムーブしかできず、またimmutableな設計を提案している。これは、土台となるcairoが、Cによる明示的なリファレンスカウントという設計であるためで、しかも、GPUリソースというのは極めてコピーが高くつくので、ディープコピーは推奨できない。このライブラリは初心者でも簡単に使えるようになるべきで、そのためには最初からコピーが禁止されていたほうがよいとしている。

なお、この論文では、提案は現時点ではTSを目指しているとのことだ。

N4022: A proposal to add a generalized callable negator (Revision 2)

Negator、つまり、任意個の実引数を転送して、結果を否定する関数オブジェクトのラッパーである、not_fnの提案。

従来のnegatorであるnot1やnot2は、一個、二個の実引数しか転送できなかった。しかも、予め定められたネストされた型名が必要などの制限が強かった。

// 従来の使いづらいわけのわからない意味不明なコード
struct Yes : std::unary_function< int, bool >
{
    bool operator ()( int ) const
    {
        return true ;
    }
} ;

int main( )
{
    auto f = std::not1( Yes{} ) ;
    std::cout << f(0) << '\n' ;
}

これが、以下のように書ける。

// まともでわかりやすくてモダンなC++風のコード
bool yes( int, int, int, int, int )
{
    return true ;
}


int main( )
{
    auto f = std::not_fn( &yes ) ;
    std::cout << f( 1, 2, 3, 4, 5 ) << '\n' ;
}

ああ、可変引数とムーブセマンティクス万歳。

N4023: C++ Extensions for Library Fundamentals, Working Draft

C++の標準ライブラリに対する拡張的な変更の文面ドラフト。これはTechnical Specificationのようなので、これが規格に直接反映されるよう提案されているわけではない。

[PDFとそれ以外のまともなフォーマットも区別すべき] N4024: Distinguishing coroutines and fibers

コルーチンとファイバーの違いを解説している論文。

これから提案されるファイバーとはなにか。コルーチンとはどう違うのかをわかりやすく簡潔にまとめている。

知っている人にはイマサラ何を初歩的なことを言うかという論文のようにみえるかもしれないが、フルスタックエンジニアなど幻想であり、プログラミングの分野があまりにも広いので、C++WG論文にはよく、提案されている技術の初歩的な解説論文も上がる。とてもわかりやすく書かれているので、読むといい。

ファイバーとは、カーネルスレッドの上に構築されるユーザースペースの実行単位のことで、その設計は、可能な限りstd::threadに似せている。ファイバー用のmutexやcondition variableもある。ひとつのスレッドの上で動く複数のファイバーは、協調的なマルチタスクを実現する。

ファイバーのスレッドに対する優位点は、コンテキストスイッチにカーネルを経由しないので、スレッドより高速に実行できる。

しかも、同じひとつのスレッド上で動く複数のファイバーは、同時に実行されることはないので、お互いに競合しない。これは、ひとつのスレッド上の複数のファイバーで共有するデータをロックしなくてもいいということを意味する。

もちろん、欠点もある。スレッドは規格上、いずれ必ず実行が進むという強い保証を与えられている、ファイバーには、そのような強い保証はない。あるファイバーが実行を握ってしまえば、同じスレッドの他のファイバーは実行できない。また、ファイバーがスレッドをブロックする操作を行った場合も同様だ。

これに比べて、コルーチンとは、関数を拡張したものである。したがってそのインターフェースはスレッドに似ておらず、関数の拡張である。コルーチンは中断した関数の実行を継続させるだけで、ユーザースペースのスケジューラーなどはない。

将来提案される予定のファイバーは、Boost.Fiberを元にしている。これは、Boost.Coroutineを使って実装されている。論文では、ファイバーを使ってコルーチンを実装する形もありだとしている。

[PDFを探求する気はない] N4025: Exploring classes of runtime size

さて、これをどこから解説すればいいものか。

この提案論文は、実行時束縛配列データメンバー(runtime bound array data member)という、クラスのデータメンバーとして実行時にサイズが決まる配列を宣言できるようにする提案である。N3875提案とは異なり、そのようなクラス(実行時サイズ型)は、動的ストレージ上にも確保できる。


struct runtime_size_type
{
    std::size_t const array_bound_size sizeof ;
    char array[ array_bound_size ] ;

    runtime_size_type( std::size_t size )
        : array_bound_size( size ) 
    { }
} ;

int main()
{
    runtime_size_type t1(10) ; // OK
    new runtime_size_type(10) ; // OK
}

動的ストレージにも確保できるようにするためには、実装可能な方法で設計しなければならない。今日のC++では、クラスサイズというのは、固定である。sizeof(T)の結果はコンパイル時に決定でき、実行時に必要な処理は何もない。しかし、クラスのサイズが実行時に決まる場合、この常識は忘れなければならない。

論文では、実行時にサイズがきまる型(runtime-size type)を動的ストレージ上に確保する方法として、三段階の手順を提案している。

  1. オブジェクトが必要とするストレージのサイズを決定する
  2. メモリーを確保する
  3. コンストラクターを呼び出す

提案論文では、コンパイラーがオブジェクトのサイズを返す最小の「size関数」を生成できるようにしている。

実行時にサイズが決まる配列のデータメンバーを、実行時束縛配列データメンバー(runtime bound array data member)という。実行時束縛配列データメンバーの添字に与える式を、束縛式(bound expression)という。実行時束縛配列データメンバーの束縛を決めるために使われるデータメンバーを、配列束縛データメンバー(array bound data member)という。


struct X
{
    const std::size_t a sizeof ; // 配列束縛データメンバー
    char b // 実行時束縛配列データメンバー
    [ a ] // 束縛式
    ;
} ;

配列束縛データメンバー、実行時束縛配列データメンバー、束縛式には、それぞれ厳しい制約がある。

束縛式に使えるデータメンバーは、配列束縛データメンバーしか認められない予定で、配列束縛データメンバーは、配置アドレスの低いほうが高い方にアクセスすると未定義とか、配列束縛データメンバーや束縛式が複数回の評価で結果が変わると未定義とか、とにかく制限が多い。

このような厳しい制限によって、コンパイラーはコンストラクターからオブジェクトのサイズを決定するためだけのsize関数を切り離して生成できる。size関数は未規定の回数呼ばれる。

実行時サイズ型をデータメンバーとすることはできる。実行時サイズ型の実行時束縛配列は違法である。

sizeofは、実行時サイズ型に使うと違法である。実行時サイズ型のオブジェクトに対して使うと、そのオブジェクトの実行時のサイズを返す。

実行時サイズ型へのポインターと整数との間の演算は、単項+演算子を除いて、禁止される。単項+演算子が許されている理由は、特に実装上の問題がなく、また禁止する理由もないためだ。

unionをサポートするべきかどうか議論があるが、std::dynarryの自然な実装には実行時サイズ型であるunionを使うので、サポートされていたほうがいいのではないかとしている。

実行時サイズ型をplacement newすることは、当然可能である。もちろん、利用者は十分なサイズのストレージを提供する責務を追っているわけだから、自己責任だ。ただし、すでにコンパイラーによってsize関数が通常のコンストラクターとは分離して生成されているわけだから、あらかじめ必要なサイズを計算するために、size関数を呼び出す方法が提供されていてしかるべきではないか。たとえば、sizeofに実行時サイズ型の直接初期化式を書けば、実行時にsize関数だけが呼び出されるなどの文法はどうか、と論文は書いている。

グローバル変数に実行時サイズ型は、実装可能であるが、より深い考察が必要であるとしている。

テンプレートの存在は、実行時サイズ型に特に影響しない。ただし、従来、あらゆる型に対して合法であった、sizeof(T)という式が、実行時サイズ型の出現によって、違法になってしまう。そのため、型が実行時サイズ型かどうかを調べるtraitsが必要だろう。なお、このtraitsは、そもそもsizeofが違法になるのだから、コンパイラーマジックを必要とせずに、SFINAEによって容易に書くことができる。

なぜこんなややこしく、明示的に配列束縛データメンバーを書かせるのかというと、配列のサイズを格納するデータメンバーを暗黙に生成すると、ユーザーの自由度が損なわれるからだ。例えば、二つの同じサイズの実行時束縛配列データメンバーが欲しい場合、以下のように書ける。


struct X
{
    const std::size_t bound sizeof ;

    char a[bound] ;
    char b[bound] ;

    X( std::size_t size )
        bound( size )
    { }
} ;

もしコンパイラーが愚直にそれぞれの実行時束縛配列データメンバーに対して、暗黙にboundのようなサイズ情報を格納するデータメンバーを定義してしまうと、このような自由度が損なわれてしまう。

この論文を読み終えた筆者の脳内に思い浮かんだセリフとしては、「C++はエキスパートに優しくなりすぎた」というあのBSの発言だ。

N4026: Nested namespace definition

ネスト名前空間定義の提案。

// N4026提案
namespace A::B::C 
{
// ...
}

このコードは、以下のコードに等しい。

// 現在のC++
namespace A {
    namespace B {
        namespace C {
// ...
        }
    }
}

論文は、既存のC++ユーザーがstack overflowのような質問サイトで、ネストされた名前空間をもっと簡単に書く方法はないのかという質問が複数あることを引用して、この文法は、現実にプログラマーの要求があることを示している。また、大きなプロジェクトでは、名前空間が深くネストするのはよくあることである。

これによく似た文法は、C#に存在して、実際に活用されている。

Using Namespaces (C# Programming Guide)

また論文では、現時点でこれを実装しているコンパイラーは知らないものの、Lazy C++という既存のツールが、この変換を行うとして紹介している。

lzzはなかなか面白そうなツールだが、そのような外部ツールの変換に頼ると、ビルドプロセスが複雑になるため、やはり言語に取り入れることが望ましい。

これは一見小粒にみえるシンタックスシュガーだが、ドワンゴ社内でこの提案を紹介したところ、ドワンゴ社員は欲しいと言っていた。

[やる気をそがれるPDF] N4027: Type Member Property Queries (rev 2)

静的リフレクションとして使えるtraitsの具体的な設計の提案。全部を紹介していてはキリがないが、たとえば、

// N4027提案
enum struct E { hoge, hage, fuga } ;

int main()
{
    // 3
    std::enumerator_list_size<E>::value ;

    // "hoge"
    std::enumerator_identifer<E, 0>::value ;

    // hageの値
    std::enumerator_value<E, 1>::value ; 
}

文字列は、text_constantという、定数式で文字列を返すクラステンプレートによって返される。

他にも、クラスのアクセス指定やメンバーの数や名などを得ることができる。

[PDFは扱いづらい] N4028: Defining a Portable C++ ABI

ポータブルABIを規定しようという提案。

これは・・・微妙。いかにもMicrosoftらしい提案と言える。

C++には安定したABIがない。バイナリから外部に公開するインターフェースとしてC++のコア言語機能や標準ライブラリを使うことは、様々な問題がある。

たとえ同じプラットフォームであっても、同じコンパイラーの同じバージョンの互換性のあるコンパイルオプションでなければ、バイナリに正常にリンクできる保証はないからだ。

このために、未だに公にするAPIとしては、C言語を使うことが一般的である。これは極めて悲惨なことだ。Cは型安全でもメモリ安全でもないため、プログラマーはポインターとサイズのペアなどを直接扱わねばならず、極めて間違いの発生しやすい非人間的な作業を強いられる。

COMやCORBAのようなヘンテコな独自仕様が蔓延しているのも、結局、クラスとかvirtual関数を、なんとか安定したABIで使いたいからである。

そこで、ABI安定なコア言語と標準ライブラリを実装依存として規程しようではないか。ABI互換なコア言語は、extern "abi"{ ... }で囲むことで得られる。また、ABI互換な標準ライブラリは、std::abi下に用意しよう。std::abiはstdとほぼ同じであるが、今後のABI非互換な変更はない。

これは、ひとつのコンパイラーの中にバージョンの異なる二つのコンパイラーを内在させ、またバージョンの異なる二つの標準ライブラリを切り替えられることと、何が違うのか。

今はいい。いまのstd::abiは、現在の最新のスナップショットだから、stdとの差はない。しかし、今後標準ライブラリに変更が加えられるにつれ、どんどん差が開いていく。断絶していく。

この提案は、長期的に見れば、確実に負債になる筋の悪い提案である。昔のバージョンのソフトウェアをそのまま使い続けるのと同じ愚行である。

そもそも、バイナリ互換性などそこまでして必要なものか。ソースコード互換性さえあれば足りるではないか。

GCCは、ABI互換性を重視し過ぎるあまりに、GCCは4.9になってもstd::stringがいまだにCopy On Writeだそうだが、それはGCCの意思決定プロセスの問題に思われる。Microsoftがメジャーアップデートごとに互換性を壊してDLL地獄に陥っているのも、やはり彼らの戦略上の問題だ。

中庸を取れないからと言って、この提案は筋が悪すぎる。このような提案に賛同する者は、Visual C++ 6.0でも使っていればいいのではないだろうか。少なくとも安定したABIは得られるであろう。

筋が悪すぎる。長期的にみれば確実に負債になる。何を考えているんだこの提案は。

[最後までPDF] N4029: Let return Be Direct and explicit

何やら格調高い題名の提案論文。

return文は特別である。return文のオペランドから関数の戻り値の型への変換は、暗黙に明示的変換にしようという提案。

以下のコードが合法になる。


struct X
{
    explicit X( int ) ;
} ;

X f()
{
    // 現在のところill-formed
    // N4029提案ではwell-formed
    return 0 ; 
}

これ以上言うことがない。return文に限り、暗黙に明示的変換される。

論文では、戻り値の型はすでに関数宣言に明示的に記述されているのだし、return expr ; という式は、明らかに、戻り値の型をexprで初期化するものであるので、returnは特別扱いしてもよいとしている。

また、上記のコードのコンパイルエラーは、「俺はお前が何をやりたかったのか知ってるよ。俺のエラーメッセージはほれ、何を書けばよかったのかすら出力してるよ。でも、お前が手で書け」となるので、プログラマーはそんな忌々しいエラーメッセージなど見たくはないだろうと、論文には書かれている。

筆者としては、どうもこれは筋が悪いように思われる。やはり明示的な型変換が必要な場合は、明示的に型変換を書かせるべきであると思う。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

先日、ドワンゴが主催した社内ポーカー大会で、宗教戦争を引き起こす悪意ある目的で、きのこの山とたけのこの里を設置したところ、たけのこの里が多数派であり、実際にたけのこの里の方が先になくなった。これは解せないことである。きのこの山はパリパリ香ばしいクラッカーと塊のチョコレートが魅力的である。一方、たけのこの里はパサパサとした舌触りの悪いクッキーに申し訳程度にコーティングされたチョコレートという始末。どう考えてもきのこの山に圧倒的軍配が上がるべきものであるはずなのだが、世の中は不条理に満ちている。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-16

シンガポールの問題ギャンブル国家委員会のワールドカップサッカーでドイツに息子の貯金を全部賭けた啓蒙広告、コメディに終わる

シンガポールの、問題ギャンブルに対する国家委員会(National Council on Problem Gambling)では、ワールドカップに合わせて、ギャンブルによる不幸を啓蒙するための広告を流していた。この広告はシンガポールの国営放送で流されたので、シンガポール人の大半は見たという。

Hey! Guys! Guys! I really can't wait for the World Cup. Who do you think is gonna win it?

My dad said Brazi will win.

No, no, no!, Argentina's gonna win. Because Messi will dribble past everyone.

I wish Spain will win. My whole family supports them.

How about you Andy?

Andy: I hope Germany will win.

Why?

My dad bet all my savings on them.

[Caption]: Often, the people who suffer from probem gambling aren't the gamblers.

[Caption]: Kick The Habit. Stop Problem Gambling.

おい、お前ら、お前ら。オレ、ワールドカップ楽しみだぜ。どこが勝つと思う?

オレのパパはブラジルが勝つって言ってたもんね。

いや、いや、いや。アルゼンチンが勝つに決まってんだろ。メッシがドリブルで全員抜き去るからよ。

スペインに勝ってほしいな。ボクの家族みんなが応援しているんだ。

アンディはどう?

アンディ「ドイツが勝って欲しい」

なんで?

アンディ「パパがボクの貯金を全部賭けちゃったんだ」

キャプション:問題あるギャンブルで被害を被るのは、ギャンブラー以外の人たちである。

キャプション:悪習を断て。問題あるギャンブルをやめよ。

このNCPGによる啓蒙広告は、ワールドカップの優勝結果が決まる前に放送されたので、結果次第ではコメディになってしまうというコメントがあった。

残念ながら、2014年のFIFAワールドカップの結果は、ドイツの優勝で終わってしまったので、この動画はコメディになってしまった。

YouTubeでは、いい投資をしたとか、パパは賢いとか、ギャンブルを始めてみようかな、とかいった皮肉のこもったコメントがあふれている。

NCPGはワールドカップの結果を受けて、以下のようなバナーを用意した。

「お前のパパ勝ったんだろ。貯金返してもらったか?」

アンディ「ううん、パパはやめてくれないんだ・・・また賭けるんだってさ」

博徒が博打で得た金をまた博打につぎ込むのは、よくあることである。

余談だが、シンガポール英語の聞き取りは難航したので、英語に書き起こしておいた。おそらくあっているはずである。

2014-07-15

ドワンゴポーカー選手権

7月14日の夜に、ドワンゴ社内で、ポーカー選手権が行われた。社外からも人を招き、トロフィーを用意して、最強のポーカープレイヤーを決定する戦いが行われた。

ドワンゴには社内同好会としてポーカー部がある。ポーカー部では、トロフィーを用意して、定期的にポーカー大会を開いて、トロフィーを奪い合っている。ドワンゴのポーカー部員も大勢参加したのだが、残念ながら、皆負けてしまった。

こうして、ドワンゴポーカー部のトロフィーは、あわれにも社外のポーカー強者に掠め取られてしまったのであった。これで社外に流出したトロフィーは2つ目になる。ドワンゴのポーカー部員は奪還を息巻いているが、果たしてどうだろうか。

筆者はポーカーはとても弱いので参加せずに、早々に飛んだ落伍者の暇つぶしのために、ボードゲームをしていた。今回は、キャッスルクラッシュというゲームを行った。これは、積み木を破壊していくゲームであり、とても面白い。

ポーカー大会の後、ドワンゴ社員で人狼を行った。人狼とは、村人と人狼がいて、参加者の中から人狼を探し出すゲームである。人狼はその正体を隠している。毎日、話し合いを行ってから投票して、人狼だと疑わしき参加者を一人、血祭りにあげる。人狼をすべて血祭りに上げられれば、村人側の勝利。人狼と同数まで村人が減ってしまえば、人狼側の勝利となる。

筆者は、このゲームがあまり好きではない。ただ、食わず嫌いもどうかと思い、たまたま機会があったので、参加してみた。人狼であるかどうかは、なかなかわからないものだ。しかし、人狼は全員叩き潰さねばならない。そうしなければ村人は勝利できないからだ。

ところで、ポーカー大会の会場に、忘れ物の服が二着残っていた。ドワンゴ社員のものか、社外の人のものかは、まだわかっていないのだが、服の特徴はそれぞれ、

  • フード付き半袖シャツ
  • 黒と裏地が緑のベスト

だそうだ。心当たりのある方は連絡されたし。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴには、ポーカー部以外にも、ボードゲーム部やカードゲーム部(MTGなど)がある。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-12

雑記

ふと気がつけば、もう東京に出てきてから半年たっている。早いものだ。

今年初めの引越と仕事は、筆者の身の上に大変化をもたらすことは予想していた。変化は好ましいことである一方、悪い影響をももたらす可能性があるものだ。

東京に出てから、筆者はいつも以上に、規則正しい生活を心がけている。早寝早起き、食事、運動、休みの日は休む。健康的な精神を保つためには、まず健康的な肉体を保たねばならない。

現在の環境は、少なくとも数年は継続しなければならないのだ。僅かな短期的な作業のために、徹夜などをして心身を潰してしまってはならぬ。

同時に、日常生活に刺激を与えるために、常に何らかの変化を試みている。料理、テント、ハンモックは、その変化の試みの一部だ。

ところで、昨日、ギークハウス秋葉原で、その場で焙煎して挽いて淹れたコーヒーを飲んだ。コーヒーとはこんなにもうまいものだったのかと感動した。やれやれ、本当にうまいコーヒーごときも知らないとは、まだまだ人生の経験が足りないとみえる。

今日は買い物がてら、12kmほど歩いた。今週は全然歩いていなかったので、いい運動になった。

2014-07-11

momonga.vim #6 ドワンゴ開催の告知

momonga.vim #6 in ドワンゴ(あきらかに) - connpass

@supermomongaの企画するもくもくVim会が、8月2日土曜日の午後に、ドワンゴのセミナールームで開催される。

もくもく会なので、皆でもくもくと何かしらVimに関する作業でもする集まりだ。

今回は、なんとあの暗黒美夢王が現れるとのことで、恐ろしさのあまり震えが止まらない。筆者のVim力では太刀打ちできそうにない。

ドワンゴ広告

この記事はドワンゴ退社後に書かれた。

今日、ドワンゴ社内ではA&Wルートビアが売りさばかれていた。社内にはルートビアがあればコードを書く速度が3倍になると豪語するほどのルートビア好きがいる一方、サロンパスの臭いを訴えて顔をしかめる人も多く、両極端であった。

ところで、ドワンゴ社内のテキストエディターのシェア率は、誰も詳しく統計を取っていないのでわからない。Vim利用者は相当の数がいるはずだが。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-10

2014-05-pre-Rapperswil mailingのレビュー

すでに2014-07 post-Raperswil mailingsが公開されているので、レビューを急ぎたいが、さっと読んで終わりにも出来ぬのが辛いところだ。

C++ Standard Evolution Active Issues List
C++ Standard Evolution Completed Issues List
C++ Standard Evolution Closed Issues List

C++の新機能の議論の場である。C++ Evolution Working Group(EWG)で、現在既知の問題、解決済みの問題、議論の結果問題ではないと結論された問題のリスト。

N4013: Atomic operations on non-atomic data

非アトミック型に対するアトミック操作を可能とする提案。

C++11とC11で標準化されたアトミック操作は、アトミック型のオブジェクトに対してしか行えない。オブジェクトはアトミック型であると明示的に宣言する必要がある。

アトミック操作できるオブジェクトを、型システムで管理するのは理にかなっている。標準規格で厳密に制定された挙動の保証を受けられるし、うっかり非アトミック操作してしまうことをふせぐことができるからだ。また、アトミック操作が不可能な場合をなくせる。例えば、アトミック操作をするオブジェクトは適切にアライメントされていなければならないアーキテクチャで、アトミック型ではないために、アトミック操作に必要な厳格なアライメントがされていない場合、アーキテクチャの制約上、アトミック操作はできない。何らかのロックを使って実装しなければならないが、それではアトミック操作の意味がない。

しかし、現実のコードは、C++11、C11以前から書かれているレガシーコードばかりである。ほとんどの既存のコードは、環境依存の方法(gccの__syncやMSVCのInterlockedなど)でアトミック操作を行っている。アトミック操作するオブジェクトは、宣言時に明示的にアトミック型であると宣言されてはいない。このような既存の莫大なレガシーコードを、すべてC++11やC11のアトミック型に移植するのはいかにも無理だ。

具体的な例としては、Linuxカーネルが挙げられる。リーナスはC11のアトミック操作モデルに対して反感を持っている。

ではどうするか。もちろん、一部の環境では、以下のようなコードが動くかもしれない。


int x;
reinterpret_cast<atomic<int>&>(x).fetch_add(1);

しかし、動くという保証はどこにもない。

そこで、この論文では、非アトミック型Tから、atomic<T>に変換できるかどうかを調べられる機能と、実際に変換する機能を、ライブラリとして追加する提案となっている。変換可能かどうか調べる機能は、type traitsで提供され(C11向けにヘンテコなプリプロセッサーマクロでも提供されるかもしれない)、変換機能は、関数テンプレートで提供される(C11向けにヘンテコなプリプロセッサーマクロでも提供されるかもしれない)

[論文のフォーマットはプレインテキストかHTMLに統一されて欲しい] N4014: Uniform Copy Initialization

この論文は、=に続く{ ... }という形の初期化子を、コピー初期化ではなく、直接初期化にする提案をしている。

以下の例を考える。

struct name
{
    explicit name( std::string const &, std::string const & ) { }
} ;

name n1 { "Nobuo", "Kawakami" } ; // OK
name n2 = { "Nobuo", "Kawakami" } ; // エラー

なんで?

n2がn1より危険であるという理由はどこにもない。n1が認められるのならば、n2も認められるべきである。

C++規格から言えば、n1は直接初期化なので合法だが、n2はコピー初期化なので違法となる。しかし、ソースコード上は=がついているかどうかという些細な違いでしかない。

ほぼすべてのプログラマーは、厳密な文法を理解した上でコードを書かないし、当然そうあるべきだ。その上で、多くのプログラマーが、上記のn2がコンパイルエラーになるという問題に出くわし、原因を調べるのに、無駄に時間を浪費している。この問題は、C++にリスト初期化が追加される以前から存在する問題である。C言語畑からやってきたプログラマーは初期化で{ }を使う前には=が必要だという先入観があるので、当然のように=を書いて、この問題にぶち当たる。

プログラマーの貴重な時間を、このような些細な文法上の問題で浪費させるべきではない。

この論文は、= { ... }という形のコピー初期化を、直接初期化と同じように扱う提案をしている。この提案の元では、上記のn2は合法となる。{ }以外の初期化子の挙動は変わらない。

explicitの機能が損なわれることはない。explicitは暗黙の型変換を防ぐ目的で、依然として機能し続ける。

[PDFは予期していない] N4015: A proposal to add a utility class to represent expected monad

optional<T>をより汎用化して、Haskellのモナド風味にしたライブラリ、Expected<E, T>の提案。

optional<T>は、T型か、あるいはT型を格納していないかというライブラリである。これはもう少し深く考えると、T型とT型を格納していないというエラーを示す型とのenumとなる。ということは、もっと汎用化できるではないか、すなわち、T型か、エラー型のどちらかを格納しているenumのような、もっと汎用的なライブラリがあればよいのだ。

ところで、エラー処理について考えてみよう。プログラムを実行中にエラーが起き、そのエラーを上位の呼び出し元に伝える場合の方法について考える。C++では、エラー処理の方法として、関数の戻り値と例外という、二つの方法がある。

関数の戻り値はC言語からある伝統的な方法だ。しかし、関数の戻り値という通信経路をエラー通知に専有されてしまうのは問題だ。しかも、関数の戻り値をいちいちにチェックしなければならず、甚だ面倒である。通常の処理とエラー処理を綺麗に分けることができない。

例外は、エラー通知専用の別の通信経路である。しかし、ある関数がどんな例外を投げるかどうかというのは、関数の宣言や呼び出しからでは分からず、コードを追っていかなければならない。さらに、例外は一旦エラー情報を保存していくとか、スレッドを超えて伝播させることが面倒だ。

この問題は、関数の戻り値と例外を両方使うライブラリによって解決できる。すなわち、結果を通知する値であるT型か、エラーを通知する値であるE型か、そのどちらかを格納するクラス、Expected<E, T>の提案となる。

より正確には、T型か、std::unexpected<E>型のどちらかを格納する。unexpectedというのは、TとEが同じ型であることを許容するためのタグ型である。

以下のコードは、典型的な、エラー通知を例外で行う関数である。

double safe_divide(double i, double j)
{
    if (j==0) throw DivideByZero();
    else return i / j;
}

となる。ゼロ除算を防ぐコードである。これを使う側のコードは、例えば以下のようなものになるだろう。


double f1 ( double i, double j, double k )
{
    return safe_divide( i, k ) + safe_divide( j, k ) ;
}

これをexpectedを使って書き直すと、

enum class arithmetic_errc
{
    divide_by_zero, // 9/0 == ?
    not_integer_division // 5/2 == 2.5 (which is not an integer)
};

std::expected<std::error_condition, double> safe_divide(double i, double j)
{
    if (j==0) return make_unexpected(arithmetic_errc::divide_by_zero); // (1)
    else return i / j; // (2)
}

となる。これを使う側のコードは以下のようになる。


double f1 ( double i, double j, double k )
{
    return safe_divide( i, k ).value() + safe_divide( j, k ).value() ;
}

expectedのメンバー関数valueは、値がある場合は値を、そうでない場合は例外を投げる。

値があるかどうか、明示的に確認することもできる。


double f1 ( double i, double j, double k )
{
    auto s1 = safe_divide( i, k ) ;
    auto s2 = safe_divide( j, k ) ;

    if ( s1 && s2 )
    {
        return *s1 + *s2 ;
    }
    else
    {
    // エラー処理
    }

}

さて、これをmonad風に書くとこうなるそうだ。


expected<error_condition, int> f(int i, int j, int k)
{
    return safe_divide(i, k).bind([=](int q1) {
        return safe_divide(j,k).bind([=](int q2) {
            return q1+q2;
            });
        });
}

これで、値がある場合は値を、値がない場合はexpectedをそのまま呼び出し元に返すようにできる。Haskell厨も大満足。めでたしめでたし。

C++では、lambda式の文法があまりにも冗長すぎるために、悲惨なコードになってしまっている。論文ではこの問題を解決するために、いくつか方法を提示している。

ひとつは、外部の関数としてmapを定義すること


expected<exception_ptr,int> f(int i, int j, int k)
{
    return map(plus,
        safe_divide(i, k),
        safe_divide(j, k) );
}

ただし、これは遅延評価されないし、何より評価順序が未規定である。

これを完全に解決するには、コア言語にHaskellのdo記法風の文法、do式を導入して、以下のように書けるようにすればよい。


expected<error_condition, int> f2(int i, int j, int k)
{
    return (
        auto s1 <- safe_divide(i, k) :
        auto s2 <- safe_divide(j, k) :
        s1 + s2
    );

これはexpected以外にも広く役に立つ。

この論文を読むのは疲れた。

[本記事最後のPDF] N4016: Light-Weight Execution Agents Revision 2

OSの提供するネイティブなスレッドよりは軽い実行単位を提供するライブラリの提案。

N4017: Non-member size() and more

タイトル通り、非メンバー関数としてのstd::size, std::empty, std::front, std::back, std::dataの提案。

たとえば、std::sizeは以下のように使える。


std::vector<int> v(10) ;
std::size(v) ; // v.size() == 10

なぜ必要なのか。可読性と安全性と効率と汎用性のためである。

このように非メンバー関数であれば、たとえば、配列にも使える。


int a[10] ;
std::size(a) ;

配列の場合は、以下のような関数テンプレートを書くことで、サイズを返すことができる。

template <class T, std::size_t N>
constexpr std::size_t size(const T (&array)[N]) noexcept
{
    return N;
}

これは、醜悪なマクロよりも安全だ。

非メンバー関数を使うことにより、様々な型が、共通の方法で操作できることになる。

std::sizeはstd::forward_list向けのオーバーロードがない。これは、多くの利用者はsizeが低数時間であることを期待しているが、定数時間で実装できないためである。

N4018: C++ Standard Core Language Active Issues
N4019: C++ Standard Core Language Defect Reports and Accepted Issues
N4020: C++ Standard Core Language Closed Issues

C++のコア言語で既知の問題、解決済みの問題、議論の結果、問題ではないと判断された問題の一覧。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

今日は台風なのでさっさと帰る。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

cc by-nd 4.0: creative commons — attribution-noderivatives 4.0 international — cc by-nd 4.0

2014-07-07

Kickstarterでポテトサラダを10ドルでクラウドファンディングした者が、すでに8000ドルの出資を受けた話

Potato Salad by Zack Danger Brown — Kickstarter

クラウドファンディング用のWebサービス、kickstarter.comで、10ドルの出資を受けたならばポテトサラダを作るという触れ込みで出資を募った者が、すでに8000ドル以上もの出資を受けるという大成功を収めている。

ポテトサラダ

俺はポテトサラダを作るぜ

いや、俺は単にポテトサラダを作る予定だ。どういうポテトサラダを作るかはまだ決めてない。

追記:作った

目標を延長:

35ドル:俺は4倍のポテトサラダを作るぜ。40ドルとは10ドルの4倍ではないが、まあ、出資者への感謝の気持を込めて。

75ドル:ピザパーティ!

100ドル:2種類のポテトサラダのレシピを試すぜ

追記2:報道すべき価値のあるポテト

http://www.cnet.com/news/guys-kickstarter-dream-making-potato-salad-possibly-with-dill/

追記3:ワーオ、お前ら最高だぜ

進捗最高だぜ。こりゃもう帽子をつくるしかねーな。帽子が欲しい人向けに出資枠を増やしたぜ。帽子の見た目に興味がある奴は以下を見れ。

http://www.zazzle.com/i_love_potato_salad_mesh_hat-148005376484063142

目標を延長:

250ドル:高品質のマヨネーズ(自然食品から選ぶぜ)

300ドル:コックを読んでレシピを教えてもらう。

350ドル:もっとポテトサラダを作るのと、あとたぶん3種類目のレシピに挑戦

ニュースになったぜ!

http://www.abc6onyourside.com/news/features/top-stories/stories/mans-potato-salad-plea-takes-off-kickstarter-33010.shtml

新たに目標を延長:

1000ドル:ポテトサラダ作成をストリーミング放送する。

1200ドル:出資者に感謝の意を伝えるための動画を撮影するために人を雇う

延長大目標:

延長して設定した目標を次々に達成していっちまった。もうこれ以上なにをすればいいのかわかんねーや。とりあえず目標額を倍にするしかねーよな?

3000ドル:俺のキッチンは狭い。パーティホールを貸しきってネット民をみんな招待するぜ!(キッチンに入れるのは10ドル以上出資したやつだけな)。ネット民はポテトサラダを愛しすぎだろ。ポテトサラダもネット民を愛していることをみせつけてやろうぜ!!

なんともまぁ。

まあ、kickstarterでよくあるクラウドファンディングの趣旨からは、だいぶ外れる気もするが、コメディアンとしてはとてもおもしろい。金を出資するだけの価値は十分に生み出していると言えよう。

2014-07-05

Qualcommが謎のDMCA取り下げ通知を発行

[Phoronix] Qualcomm DMCA Notice Takes Down 100+ Git Repositories

QualcommがGitHubの100件以上ものレポジトリのファイルに対して、DMCA取り下げ通知を発行したそうだ。

まあ、それが実際に著作権侵害なのであればいいのだが、どうやら報告によると、単にQualcommの著作権表記の文字列だけを検索して機械的に通知を出したと思われる節があるらしい。多くのファイルは、公に公開されているリファレンスコードやサンプルコードだ。まあ、これはまだ著作権を主張するのもわかるが、androidカーネルのソースファイルと同等のものも取り下げられたらしい。ソースファイルには"Qualcomm Confidential and Proprietary"と書いてあるものの、すでにLinux財団の管理下にあるはずのソースコードだという。

Qualcommも映画業界の仲間入りを果たしたらしい。

2014-07-04

2014-05-pre-Rapperswil mailingのレビュー: N4000-N4009

さて、さくさくC++WG論文を解説していく。

[記念すべきキリ番がPDF] N4000: Towards a Transaction-safe C++ Standard Library: std::list

STLコンテナーをトランザクションセーフにするための研究の一環として、std::listをトランザクションセーフに書き直してみた実験の報告。STLコンテナー自体をトランザクションセーフにすることで、ユーザーが明示的にトランザクショナルメモリーのコードを書かなくてもすむ。

実験は、現在提案されているTransactinal Memoryを実験的に実装したGCC 4.9とそのstd::listの実装に対して行われた。

論文によると、十分に実装可能であり、変更は最小限ですんだという。変更の大半は、メモリ確保と解法、swap関数にtransaction_safeキーワードを使うだけだという。

論文では、実装経験の結果持ち上がった問題についても論じている。

size()が定数時間

C++11では、すべてのコンテナーのsize()のオーダーは低数時間であると定められた。これは、std::listをトランザクショナルセーフにする際に、scalableではなくなるという問題を引き起こす。ライブラリ拡張WGのメンバーは、C++11で軽々しくsize()を低数時間にしたのは誤りであったと認めた。議論の結果、この問題に対処するためにsize()のcomplexityを再び変更するなどということは行わないことで合意したそうだ。

size()がconst noexcept

トランザクショナルメモリーは、ロールバックを認めている。ロールバックを行うには、副作用を一時的に保持しておくストレージを確保する必要がある。ストレージを確保しようとして、確保できない場合が発生すると、bad_allocがthrowされるが、それはconst noexceptであるsize()の中で起こる。しかし、const noexceptな関数の中からそれはできない。これに対処するためには、もっと安全な方法で実装を余儀なくされる。

議論の結果、実装に内部的な静的ストレージをロックやトランザクションで保護できる自由を与えればよかろうという方向に向かったようだ。

非安全な処理を行う要素型への対応

std::listの要素型が、コンストラクターや代入の歳に、ロールバックできない副作用(I/Oなど)を引き起こす場合、いったいどうすればいいのか。

議論と経験の結果、実装はそのような非安全な要素型のインスタンス化を阻害すべきではないが、トランザクションのなかでそのようなメンバー関数を呼び出すことを、コンパイラーは禁止すべきであるという。

論文では、GCCでは、多少の変更でこの挙動を実現可能であるとしている。

論文では、この後、std::listに施した具体的な変更内容の説明が続いている。実験的実装をしたstd::listは、以下のGitHubレポジトリにおいてある。

mfs409/tm_stl

[テキストのみのPDFにする理由が一切感じられないPDF] N4001: SG5: Transactional Memory (TM) Meeting Minutes 2014/02/03-2014/05/19

トランザクショナルメモリーに関する会議の議事録

[PDFも消毒だ] N4002: Cleaning-up noexcept in the Library

標準ライブラリにnoexceptを着ける基準を見直す提案。

File System TS Active Issues List (Revision R1)
File System TS Closed Issues List (Revision R1)
File System TS Defect Report List (Revision R1)

Filesystem TSに持ち上がっている問題、解決済みの問題、議論の結果問題ではなかったと判断された既存の問題のリスト。

N4006: An improved std::{unordered_,}map::emplace

std::mapとstd::unordered_mapのemplaceにムーブ可能な値を渡すと、実際にムーブされるかどうかは、未規定である。


std::map<std::string, std::unique_ptr<Foo>> m;
m["foo"] = nullptr;

std::unique_ptr<Foo> p(new Foo);
auto res = m.emplace("foo", std::move(p));

上記のコードを実行した結果、pがムーブされるかどうか、つまりassertに引っかかるかどうかは、規格上、未規定である。emplaceはひょっとしたらpをムーブせずにコピーするかもしれない。

emplace自体を修正するのは難しいので、挙動を保証した、emplace_stableとemplace_or_updateを新たに追加しようという提案をしたのが、N3873だ。

Issaquah会議で議論した結果、emplaceは動くべき(Just Work)だという意見が大勢を占めたので、この提案では、従来ひとつだったemplaceを三つに分割する。

N4007: Delimited iterators (Rev. 2)

ostream_iteraterの改造版、ostream_jointerの提案。

ostream_iteraterは、以下のように使いたくなる。


std::vector<int> v = { 1, 2, 3 } ;
std::cout << "(" ;
std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, ", " ) ) ;
std::cout << ")"

なるほど、これは汎用的なアルゴリズムを適用できて便利だ。しかし、この出力は、以下のようになる。

(1, 2, 3, )

実は、ostream_iteraterのデリミターは、実はデリミターではなくて、サフィックスとでもいうべき動きをするのだ。

そこで、本当にデリミターとして働くostreamのイテレーターラッパーが提案されている。ostream_jointerだ。ostream_jointerを作るためのmake_ostream_jointerもあって、以下のように使う。


std::copy( v,begin(), v.end(), std::make_ostream_jointer( std::cout, ", " ) ) ;

これを実行すると、出力は、(1, 2, 3)となる。

なお、この論文筆者は、学生に課題としてこれの実装を毎年課しているという。

[PDFは同時に粉砕されるべき] N4008: SIMD polymorphism

コンパイル時に最適なSIMD関数を型システムによって選ぶ、SIMDポリモーフィズムの提案。

ある関数があって、その関数に対して、特定の条件に対しては効率的なSIMD関数を生成できるとする。条件というのは、例えば、ループの中で、関数の引数が、固定、線形に変化、不定といった条件だ。これらの条件に対して、最適なSIMD関数を生成する。

論文は、OpenMPなどの既存のSIMD用の実装による経験を元に書かれている。論文では、上記のような条件を記述するための、何らかの文法があるものと仮定して話を進めている。

さて、あるひとつの関数に対して、条件ごとに最適な複数のSIMD関数コードと、安全にフォールバックするための通常関数コードを生成したとする。この複数の関数から、どのようにして、特定の条件に会う最適な関数を選べばいいのだろうか。

コンパイル時条件分岐というと、まずまっさきに思い浮かぶのが、テンプレート実体化とオーバーロード解決だ。残念ながら、この二つのコンパイル時条件分岐は、あまりにも選択が早すぎる。最適なSIMD関数を選ぶための条件は、テンプレート実体化やオーバーロード解決が終わった後、コンパイラーによるデータフロー解析の結果、判明する。したがって、条件が判明した時には、すでに選択が行われてしまっている。

論文では、この選択には、型システムを使うべきだと主張している。関数の集合を、ひとつの型として認識する。もちろん、関数へのポインターも、通常の関数ポインターとは異なる型で、しかもひとつの型として認識する。その実態は、複数の関数が、条件に従って適切に選ばれるのだ。実装は複数の関数の中から、適切なSIMD関数にディスパッチする。適切なSIMD関数を選択するのは、ループの外で行われるので、virtual関数呼び出しのようなパフォーマンスの問題はない。

ひとつの関数から生成される複数のSIMD関数と通常関数のコードは、ユーザーからは完全に一つの型、SIMDポリモーフィズムな型としてみえる。ユーザーが特定のひとつのSIMD関数を個別に参照することはできない(特定の条件で呼び出せば、間接的に選択可能ではあるが)

論文では、通常の関数へのポインターとSIMDポリモーフィズムな関数へのポインターを、相互に型変換できるべきであるとしている。また、相互に等価を比較できるべきであるとしているが、等価比較には、色々とコストがかかり、最適な実装方法がないとしている。

また、複数のアーキテクチャが混在するヘテロコンピューター環境が珍しくない現代、このSIMDポリモーフィズムの機構を使って、実行時に最適なコードを選ぶといった将来性もあるであろうが、この論文では、今回はそれを考察しないと結んでいる。

ただでさえわかりにくい型シムテムを、さらにわかりにくくする提案だ。そして、まだ具体的なSIMD条件を記述するための文法が提案されていない以上、この論文だけではどうしようもない。

N4009: Uniform Container Erasure

コンテナーから条件を満たした要素をすべて消し去り、サイズも変えるerase_if(container, pred)の提案。

以下のように使う。


std::vector<int> v = { 1231, 132, 2321 , 222, 35, 6643, 11, 2, 890, 33} ;

std::erase_if( v, [](auto && elem ){ return elem < 100 } ) ;

// vは{1231, 132, 2321, 222, 6643, 890}

従来、これをするには、以下のように書く必要があった。


v.erase(
    std::remove_if(v.begin(), v.end(),
        [](auto && elem ){ return elem > 100 }
    )
    , v.end()
    ) ;

しかし、もし以下のように書いてしまった場合、意図通りには動かない上に、コンパイルが取ってしまい、実行できてしまう。


v.erase(
    std::remove_if(v.begin(), v.end(),
        [](auto && elem ){ return elem > 100 }
    ) ) ;

これは、STLコンテナーのeraseメンバー関数には、イテレーターをひとつだけ取るオーバーロードと、イテレーターの範囲を取るオーバーロードがあるからだ。コンパイラーはこのミスを警告すらできない。

このため、erase_ifを提案する。

なぜerase_ifはメンバー関数ではないのか。このようなコンテナーごとに最適な実装が異なるアルゴリズムは、従来ならばメンバー関数として実装していたではないか。この理由としては、basic_stringがやりすぎてカオスなことになってしまっているのを反省してのことらしい。

また、名前がややこしいという問題もある。eraseとremoveは意味が似通っていてわかりにくい。論文ではこの疑問に対して、eraseというのは、listとforward_listのような例外を除けば、コンテナーのサイズを変更する場合に一貫して使われている。コンテナーのサイズを変更するremoveはない。また、eraseという非メンバー関数は使われていないとしている。

ただし、やはりわかりにくいとは思う。バイク小屋議論は尽きないものだ。

なぜpredicateだけなのか。なぜ削除すべき値を指定するオーバーロードはないのか。問題は、連想コンテナーとunordered連想コンテナーには、erase(key)というメンバー関数があり、混同しやすいからだとしている。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

この記事を執筆中に、社内の筆者の近所の席から、何やらダースベイダーの呼吸音のような音が聞こえると思ったら、ビーダマン後期の製品、コバルトブラスタードライブキャノンとデストロイドラゴンで遊ぶエンジニアがいた。リモコンで前身と旋回操縦可能な上に、ビー玉単発や連写までできるすぐれものだ。ただし、シメ撃ちはできそうにない。シメ撃ちできないと滝をぶち破ったりできないと思うのだが、いったいどうするのだろうか。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

Ubuntu 14.04のUnityの設定をぶっ壊した場合の修復方法

今朝、コンピューターを起動して、Ubuntu 14.04にログインしようとしたら、なぜか画面が固まってしまった。

まあ、この程度は情報強者たる筆者にとっては、造作もないことだ。Ctrl+Alt+F1で華麗に仮想コンソールに切り替えて、Upstartのinitctlを使ってlightdmを再起動させた。

$sudo restart lightdm

カチャカチャ・・・ターンッ!

restartは、initctl restartの代わりに使えるinitctlへのシンボリックリンクだ。おそらく、Ubuntuも将来的にはsystemdに移行するであろうから、いずれはsystemctlを使う必要があるであろう。だが、それはまだ先の話だ。

Ctrl+Alt+F7で戻ったところ、無事にlightdmによるログイン画面が表示された。さっそくログインしなおしたが・・・Unityがぶっ壊れていた。

背景とマウスポインターは表示される。右クリックするとメニューも表示される。しかし、それ以外のUIが一切ない。ランチャーもメニューバーもないので、このままではGUI作業ができない。GNOMEターミナルを開くキーボード・ショートカットも動かない。

仕方がないので、情報弱者らしく再起動をしてみたが、

$sudo shutdown -r now

Unityは壊れたままだった。

やってしまった。これはおそらく、無理やりlightdmを再起動させたので、どこかの設定ファイルが壊れてしまったのだろう。試しに別のユーザーでログインしてみると、ランチャーもメニューバーも通常通り表示される。しかし、Unityの設定ファイルをぶっ壊してしまったので別ユーザーを使います、というのは情報弱者にもほどがある。さて、どうやって復旧しようか。

あるいは、この機会に、別のWMを試してみるという手もある。しかし、何はともかく、Unityを復旧させたい。

まず、Compizの設定をリセットしようと思い立った。Compizの設定をリセットするには、CompizConfig Settings ManagerというGUIのソフトウェアを使う必要がある。しかし、ランチャーもターミナルもないと、起動することができない。

調べたところ、DISPLAY変数を適切に設定することで、仮想コンソールからプログラムを起動してそのウインドウを望みのディスプレイに表示できるようだ。

$sudo apt-get install compizconfig-settings-manager
$export DISPLAY=:0
$ccsm

無事に起動できたので、Unityプラグインを設定しなおしたり、デフォルトの設定を読み込ませたりしてみたが、残念ながら、これでは直らなかった。さて、どうするか。

さらに調べたところ、unityを起動するラッパーである/usr/bin/unityに、--resetオプションを指定すると、設定ファイルをリセットしてくれるという。

$man unity
unity(1)                              Linux User's Manual                              unity(1)

NAME
       unity - wrapper for starting the unity shell and handling fallback

SYNOPSIS
       unity [options]

DESCRIPTION
       The  unity program can be used to start the Unity shell as a compiz module, and to spec‐
       ify how to handle logging, debugging, as well as how to deal with the user's profile.

OPTIONS
       --advanced-debug
              Runs unity under debugging (using GDB or another debugger tool) to help  tracking
              issues. Should only be used on request from a developper following a bug report.

       --log filename
              This  parameter,  followed  by a path or filename, tells the Unity shell to store
              logs in the specified file.

       --reset
              This option allows the user to reset profile parameters in compiz and restart the
              Unity shell with default settings.

       --verbose
              This  option turns on displaying additional debugging output for the Unity shell.
              It can be used by the user to debug configuration issues. This  option  is  often
              used along with the --log option to save output to a file.

SEE ALSO
       unity-panel-service (1)

                                        9 December 2010                                unity(1)

なるほど、ではさっそく

$ unity --reset
ERROR: the reset option is now deprecated

なんだと。

さらに調べたところ、Ubuntu 14.04では、unity-tweak-toolが公式なレポジトリに入っていて、これにはUnityの設定をリセットする機能があるようだ。

$sudo apt-get install unity-tweak-tool
$man unity-tweak-tool

unity-tweak-tool(1)                   Unity User's Manual                   unity-tweak-tool(1)

NAME
       unity-tweak-tool - configuration manager for Unity desktop environment

SYNOPSIS
       unity-tweak-tool [options]

DESCRIPTION
       The unity-tweak-tool program can be used to tweak Unity desktop environment. Unity Tweak
       Tool is a one-stop settings manager for Ubuntu Unity.

OPTIONS
       -u     Starts unity-tweak-tool in Unity section.

       -w     Starts unity-tweak-tool in Window Manager section.

       -a     Starts unity-tweak-tool in Appearance section.

       -s     Starts unity-tweak-tool in System section.

       --reset-unity
              Reset Unity, wiping all changes to configuration.

BUGS
       Please report any bug you may experience to the unity-tweak-tool developers, who can  be
       reached at https://launchpad.net/unity-tweak-tool.

AUTHOR
       unity-tweak-tool was written by Freyja Development Team and this manual page by Barneed‐
       har Vigneshwar <barneedhar@ubuntu.com>.

       Both are released under the GNU General Public License, version 3 or later.

                                        11 February 2013                    unity-tweak-tool(1)

これを使ってみよう。

$unity-tweak-tool --reset-unity

これはうまくいった。無事に、Unityが復旧した。

たまに環境が壊れると、刺激があって面白い。動かないものを動くように直す作業は楽しい。しかし、それは危険な誘惑である。

xkcd: Cautionary

Linux: 実際にあった話:第一週

もしもし、あたしあたし、姪だけど。新しいパソコン手に入れたんだけどさ、Windowsとか入れたくないのよ。Linuxとかいうやつのインストール手伝ってくれない?

いいよ

第二週

XORGが壊れたって。XORGって何? どうすればいいの
「manページ教えるよ」

第六週

autoconfigがうまくいかないんでUbuntuからDebianに変えることにする
「えっ」
Gentooにするかも
「やばい」

第十二週

「最近電話に出ないけど」

寝らんない。カーネル、コンパイル、しなきゃ。

「手遅れか」

親に告ぐ:誰か他人に教わる前に、子供にLinuxを教えるべきである。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

昨日、いつも通り午後2時頃にドワンゴに出社したところ、ACアダプターを家に忘れたことに気がついたので、その日はバッテリーが切れる前にさっさと退社した。今日は朝からネタができたので、午前11時に出社した。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-07-02

妖怪ハンモック

さて、妖怪ハウスにハンモックを導入してしばらくたった。筆者がハンモックを購入した理由は他でもない。夜にハンモックで寝るためである。ハンモックで寝るということには、ロマンがある。

最初に買った、ハンモックを吊るす土台付きのハンモックは、寝っ転がってリラックスするにはよいが、寝具として使うには機能不足であった。そこで、もっと幅が広いハンモックをもう一枚購入した。問題は、二枚目のハンモックは多きすぎて、すでに買った土台には取り付けられない。ベランダの手すりに取り付けることはできるのだが、日光が直接顔面にあたって寝られない。

この問題を解決するために、筆者はビーチパラソルを購入した。幸い、アマゾンには安いビーチパラソルが売られていた。これでハンモックでも快適に寝られるはずである。さっそく、今夜は雨が振らない天気予報であることを幸い、寝心地を試してみようと思う。

ビーチパラソルは、ハンモックの他にも色々と役に立つはずである。

日々変わりない平凡な日常では腐ってしまう。常に変化が必要である。次はどんな変化を試みようか。