2015-05-23

江添ボドゲ会@6月開催

江添ボドゲ会@6月 - connpass

6月の第一土曜日である6月6日に妖怪ハウスで江添ボドゲ会を開催する。

最近、引越して自らシェアハウスを始めることを考えている。ボドゲ会を開催するために広いリビングのある物件を探している。

Unixの歴史のgitレポジトリ

dspinellis/unix-history-repo

現在入手しうる限りの情報を使って、Unixの歴史を再現したgitレポジトリを作成する試みが行われている。

1972年から2015年までの入手可能な断続的なスナップショット、レポジトリ、研究記録を元に、単一の歴史を辿れるgitレポジトリを作り上げるというプロジェクトだ。

スナップショットからはソースコードと日付を、研究記録からは貢献者とブランチを、レポジトリからはすべての情報を得て、単一の歴史というメタデータを辿れるgitレポジトリを生成する。これはUnixの歴史研究のために非常に便利だ。

ちなみに、case-insensitiveなファイルシステム上に展開するとファイルの欠落を生じるそうだ。

2015-05-21

xkcd 1526: プラシボ阻害薬

xkcd: Placebo Blocker

プラシボ効果の作用原理についての研究が進んでいる。

その研究の成果を用いて、新薬を作成した。プラシボ効果阻害薬。

さて、臨床試験を行わなければならない。2つの被験者群を用意して、両方にプラシボを与え、しかる後に、片方には本物のプラシボ阻害薬を与える。そしてもう片方には・・・

・・まてよ

頭痛が痛くなってきた。

同じく。

この偽薬でも飲むかい?

2015-05-20

ask.fmの回答を簡単にするブラウザー拡張を書いた

Big Sky :: 江添さんに簡単に質問出来るコマンドを golang で書いた。

珍しくフルチンではないmattnさんが、ask.fmの私のアカウントに質問を投稿するCLIのツールをgoで書いたようだ。そのためと、しばらく回答していなかったため、ask.fmが大量のオヤジギャグを含む質問で埋まってしまった。

ask.fmをブラウザーから閲覧して質問に答えるのはいいが、UIに不満がある。マウスを使わなければ質問に答えられない。このため、キーボードだけで質問に答えられるよう、ブラウザー拡張を書いた。

https://github.com/EzoeRyou/askfm-mod

質問の一覧でショートカットキーを押すと、最新の質問の回答URLに移動する。回答を入力してショートカットキーを押すと、回答ボタンをクリックする。何も回答を入力しないままショートカットキーを押すと、「質問ではない」と回答する。

本来なら、こういうブラウザー拡張はもっと早く書くべきだったのだが、ダルいためなかなか作成に踏みきれずにいた。

ドワンゴ広告

久しぶりにChromiumの拡張を作ったら、manifest.jsonのフォーマットが微妙に変わっていた。こんなことより、早くC++の論文集を読まなければならないのだが。

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

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

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

2015-05-19

Linuxカーネルを2038年問題に対応させるには

System call conversion for year 2038 [LWN.net]

lwn.netでLinuxカーネルを2038年問題に対応させるにはという記事が公開されている。

32bit版Linuxカーネルのtime_tはsigned 32 bitなので、現行の32bit版Linuxカーネルをそのまま使い続けるシステムは、2038年問題の影響を受ける。

問題の日付が近づくにつれ、32bitシステムは様々な楽しげな理由により障害を起こすことが予測されるので、今日のLWN読者は、退職から呼び戻されて、紀南を救うために英雄的な活躍をするだろう。今対策をしなければの話だが。

さて、32bit Linuxカーネルでも、time_tなどの時間の表現に64bitの値を使えば2038年問題は解決できるか。実は、問題はそれほど単純ではない。

カーネル内部の時間表現を64bitに移行するだけではない。ユーザースペースのインターフェースも変えなければならない。いずれは移行しなければならないとしても、現行のバイナリとのABI互換はどうするのか。

このために、すべての時間を扱うシステムコールを、カーネル内部の64bit表現と、従来の32bit表現との変換を行う変換レイヤーとしてのシステムコールで置き換える。64bit時間表現のシステムコールには新しいシステムコール番号を割り当てる。もちろん、2038年までしか使えない。

最終的には、既存のバイナリは一掃される。

ところで、時間を扱うシステムコールと簡単に言うが、すべてを洗い出すのは難しい。ioctlには、現在何千も登録されているが、その一部は時間を扱っている。これをすべて洗い出して直していかねばならない。

ext4はタイムスタンプを32bitのtime_t型で格納している。ディスク上の表現として34bitに拡張しているバージョンのext4もあるが、ext3はそういう対応はしていない。ext3は使用を辞めなければならない。NFSv3も同様の問題があり、おそらく同じ道をたどるだろう。XFSは変更に問題を抱えている。ファイルシステムの問題は、64bitシステムにも影響を及ぼす。他にも、ユーザースペースとカーネルスペース両方で問題になる場面が多々あるだろうは疑う余地がない。そのため、2038年にシステムを対応させるのは、単にシステムコールを64bit値に移行する以上の問題がある。とはいえ、システムコールを直すのは、まず第一歩である。

2038年問題、一体どうなるのだろう。ファイルシステムのようなものは切り捨てるしかないのだろうか。NTPはどうするのだろう。GPSと同じようにするのだろうか。

ドワンゴ広告

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

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

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

2015-05-18

歌舞伎座.tech #8 「C++初心者会」を開催した

歌舞伎座.tech#8「C++初心者会」 - connpass

5月17日に、歌舞伎座.thch #8 「C++初心者会」を開催した。

今回は、勉強会の初心者が発表できる場を設けようという意図から、発表枠には、初心者枠とガチ枠を設けた。これにより初心者が積極的に発表しやすくなるはずだ。さて、問題は参加者と発表者が集まるかどうかだ。いざフタを開けてみると閑古鳥が鳴いているようでは極めて痛い。

さて、connpassで告知と募集を開始すると、参加枠が即座に埋まっていく。どうやら勉強会の需要はあるようでまずは一安心だ。発表枠も埋まり始めたが、その参加者を見ると、どうも、技術的、勉強会的にみて、初心者とは思われない。

さて、公開直後の参加申し込みの波がひけてみると、参加枠と初心者枠は埋まっているものの、ガチ枠が埋まらない。どうやら、みなチョットデキル的な謙遜精神を発揮してしまったようだ。仕方がないので、ガチ枠をクソザコ枠に改名した。するとすぐに発表者で埋まった。しかし、発表者のプロフィールと発表タイトルをみると、どうもザコとも思われない。

さて、当日、

Eigenでオンライン機械学習アルゴリズムを実装したときの話

C++初心者ではあるのかもしれないが、機械学習の初心者ではない人間が発表した。C++に関係のある部分としては、行列計算ライブラリとして、Boost.UBLASは使い勝手が悪く、Eigenの方がパフォーマンスも使い勝手もよいとのことだ。

Seastar 高スループットなサーバアプリケーションの為の新しいフレームワーク

C++初心者ではあるのかもしれないが、カーネル開発の初心者ではない人間が発表した。Seastarとは、カーネルではなくユーザーランドでネットワークスタックを実装して高パフォーマンス化を図るものだ。ネットワークスタックをユーザーランドで実装する利点として、カーネルからユーザーへのメモリコピーが省けるとのことだ。

なるほど、これが必要になるのはどういう状況だろうか。100GbpsのNICが出たら話は変わるのかもしれないが。

Improving Linux networking performance [LWN.net]

Seastarの提供するfutureがthenをサポートしているのも興味深かった。これはC++標準化委員会にconcurrency TSとして提案されている機能だ。そういう意味で、この発表者には是非ともC++標準化委員会に出てきて知見を上げてほしいものだ。

Boost.Asioで可読性を求めるのは間違っているだろうか

果たしてC++初心者はBoost.Asioを使えるのだろうか。Boost.AsioはC++標準化委員会で、ネットワーキングライブラリとしてTSに提案されている。既存のネットワークライブラリで、標準化委員会で合意に達することができるものは、Asioぐらいしかないであろうが、日本の標準化委員会の中では、Asioは使いづらいという意見が出ている。

Boost.Spirit.QiとLLVM APIで遊ぼう

果たして初心者がExpression Templatesの悪用の最たる例であるBoost.Spiritと、LLVM APIを使うだろうか。ただし、便利なライブラリのおかげで、コード自体はとても短く綺麗だった。

任意の文をマングリングすることができないクソザコなのでconstexprラムダをライブラリで作った

lambda式のクロージャーオブジェクトのoperator ()がconstexprではないのは、もし仮にそうであると、lambda式がSFINAEの文脈で使えてしまうので、任意の文のsubstitutionに成功するかどうかを判定する、極めて強力な悪用ができてしまう。その機能を実現するためには、任意の文を型としてマングリングしなければならない。そのような機能は、抜け穴的な技法ではなく、コンセプトのような、その目的のために特別に設計された機能で実現すべきだ。

発表者は、Boost.LambdaのようにExpression Templatesを悪用して、コンパイル時に評価できるlambda式風のDSLをC++上に実装していた。これがザコのすることだろうか。

Haskellを書きたい人生だった

C++でExpression Templatesを悪用して、Haskell風のDSLを実装した話。ソースコードがまるでC++ではない上に、初心者のすることではない。

文字列とC++

これは初心者らしい発表だった。C++を学ぶときに引っかかった落とし穴をいくつか解説している。

ロボティクスとC++

Pythonを褒め称える発表だった。

私が市販のロボットのプログラミング環境に思うことは、バイナリブロブでの配布が多すぎるということだ。そのプログラミング環境は、10年後に維持できない。使い捨てである。そんな使い捨て文化では、一向にソフトウェア資産がたまらない。発表者は個別に差異を吸収するレイヤーライブラリを書いて、自分のコードはその上に書けばよいと主張したが、そういう互換レイヤーは、個人個人で独立して書かれるので、一向にソフトウェア資産がたまらず、ロボット開発の未来は暗い。

不自由ソフトウェアは長期的な利益をもたらさないので根本的に価値がない。

クソ雑魚がC++のウェブフレームワークを食い散らかした話

巷に転がっているC++で書かれたWebフレームワークをいくつか試してみたという発表。

ビルドするのが極めて困難なフレームワークが多いという話だった。ビルド可能性はとても重要で、まともなシステム管理者がドキュメントを読んで数行のコマンドを入力するだけでビルドできるようにしておくべきだ。

大学でC++03を教わった私が、便利そうだと思ったC++11の新機能

これも初心者らしい話。聞説、発表者の大学では、この2015年に大昔の化石規格であるC++03を教えて、それで学位を与えているようだ。日本の教育機関は10年ほど前からC++標準化委員会と関わらなくなっているため、もはや日本の教育機関に最新のC++規格をまともに把握している人間はいない。そのため、C++11を教育できる人間がいないのだろう。

この2015年にC++03しか教育できない教育者しかいない大学というのは何なのだろうか。しかも発表者によると、教育内容には規格上の誤りが多かったという。

Visual C++で始めるOpenCV

OpenCVという画像認識ライブラリの概要を説明する発表のようだった。

組み込み向けC++のやり方を探る

あまり内容を覚えていない。

なぜC++は組み込みに採用されにくいのか

C++はどのようなコードに落とし込まれるか人間が手動で推測しにくいので組み込みには向かないという発表であった。

virtual関数の実装方法として主流なvtableによるクラスオブジェクトのサイズ増加や、関数のオーバーロードをされるとその処理コストがコードを見ただけではわからないという話。

これは疑問で、Cでも実行時に決まる情報を元に分岐処理を行えば、vtable文のメモリ消費量増加はあるので同じだ。

関数のオーバーロードでコストを見積もれないというのも不思議だ。組み込みの分野では、何度も行う処理を関数という単位に分割しないのであろうか。

class Something { } ;
Something plus( Something const &, Something const & ) ;
Something operator + ( Something const &, Something constg & ) ;

のようなライブラリがあったとして、

Something c = plus( a, b ) ;

と書くのと、

Something c = a + b ;

と書くのとで、その処理コストを手動で見積もる難易度に差があるとは思われない。

発表者は、C++標準化委員会は組み込みでも使えるC++のサブセットを定義すべきであると主張したが、それはC++を分断するだけである。C++を分断すると、利用者も分断される。それは適切ではない。C++標準化委員会はC++のサブセットの定義は行わない方針である。

C++でHello worldを書いてみた

これは一見すると実に初心者らしい、微笑ましいタイトルだ。しかし、ホットペプシと名乗るこの発表者のプロフィールを確認すると、競技プログラマーであるという。発表者の最近解いた問題を少し見るだけでも、もはやこの発表者はHello worldやFizzBuzzを書いて正しく動いたことを確認して喜ぶレベルはとっくに過ぎ去っていることが明らかである。

以下がhello worldのC言語のコードである。

_[]={
'('-'!'|((','-' ')<<('$'-' '))|(('$'-' '|(('$'-' ')<<('$'-' ')))<<('('-' '))|(('$'-' '|(('#'-'!')<<('$'-' '))|((('/'-' ')<<('$'-' '))<<('('-' ')))<<('='-'-'))
,'('-' '|(('$'-' ')<<('$'-' '))|(('%'-' '|(('&'-' ')<<('$'-' ')))<<('('-' '))|((','-' '|(('&'-' ')<<('$'-' '))|((','-' '|(('&'-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,'('-'!'|((','-' ')<<('$'-' '))|(('$'-' '|(('$'-' ')<<('$'-' ')))<<('('-' '))|(('$'-' '|(('#'-'!')<<('$'-' '))|(('$'-' '|(('/'-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,'/'-' '|(('&'-' ')<<('$'-' '))|((','-' '|(('#'-'!')<<('$'-' ')))<<('('-' '))|((('#'-'!')<<('$'-' ')|(('('-'!'|(('('-'!')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,'('-'!'|((','-' ')<<('$'-' '))|(('$'-' '|(('$'-' ')<<('$'-' ')))<<('('-' '))|(('$'-' '|(('#'-'!')<<('$'-' '))|(('('-' '|(('/'-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,'/'-' '|(('&'-' ')<<('$'-' '))|(('#'-'!'|(('('-'!')<<('$'-' ')))<<('('-' '))|((','-' '|(('&'-' ')<<('$'-' '))|(('$'-' '|(('&'-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,'&'-' '|(('&'-' ')<<('$'-' '))|(('('-'!'|((','-' ')<<('$'-' ')))<<('('-' '))|(('$'-' '|(('$'-' ')<<('$'-' '))|(('$'-' '|(('#'-'!')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,','-' '|(('/'-' ')<<('$'-' '))|((!!""|(('#'-'!')<<('$'-' ')))<<('('-' '))|(('*'-' '|(('*'-' '|(('+'-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,'.'-' '
,'('-' '|(('$'-' ')<<('$'-' '))|(('+'-' '|(('+'-' ')<<('$'-' ')))<<('('-' '))|((!!"")<<('='-'-'))
,('+'-' '|(('.'-' ')<<('$'-' '))|((')'-' '|((!!"")<<('$'-' ')))<<('('-' ')))<<('='-'-')
,('('-' '|(('$'-' ')<<('$'-' '))|(('-'-' '|(('('-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-')
,'$'-' '|(('('-'!')<<('$'-' '))|(('$'-' '|(('#'-'!')<<('$'-' ')))<<('('-' '))|((('/'-' ')<<('$'-' ')|(('/'-' '|(('+'-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,!!""
,')'-' '|(('('-' ')<<('$'-' '))|(('('-' '|(('/'-' ')<<('$'-' ')))<<('('-' '))|(('/'-' '|(('%'-' ')<<('('-' ')))<<('='-'-'))
,!!""|(('#'-' ')<<('$'-' '))|(('/'-' '|(('/'-' ')<<('$'-' ')))<<('('-' '))|(('('-' '|(('+'-' ')<<('$'-' '))|((','-' '|(('#'-' ')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,(('/'-' ')<<('('-' '))<<('='-'-')
,'%'-' '|(('-'-' '|(('('-' ')<<('$'-' ')))<<('('-' '))|((','-' '|(('$'-' ')<<('$'-' '))|(('$'-' '|(('#'-'!')<<('$'-' ')))<<('('-' ')))<<('='-'-'))
,('/'-' ')<<('$'-' ')|(('('-' '|(('+'-' ')<<('$'-' ')))<<('('-' '))|(('$'-' ')<<('='-'-'))
,('-'-' '|((','-' ')<<('$'-' '))|((('('-' ')<<('$'-' '))<<('('-' ')))<<('='-'-')
,!!""|(('#'-' ')<<('$'-' '))|(('+'-' '|(('-'-' ')<<('$'-' ')))<<('('-' '))|(('('-' '|(('+'-' ')<<('$'-' '))|((!!"")<<('('-' ')))<<('='-'-'))
,(('-'-' '|((','-' ')<<('$'-' ')))<<('('-' '))<<('='-'-')
,('('-' ')<<('$'-' ')
};

このコードは、_という名前のint型の配列を定義している。その配列は.textセクションに配置される。配列のビット列は、x86とx86-64において"Hello, world!"と出力するものである。あとはプログラムのエントリーポイントを_startではなく_にしてリンクしてやれば、プログラムを実行するとこのビット列を実行しようとし、結果としてhello worldが出力される

このコードは、記号のみを使っている。アルファベットや数字は一切使っていない。ではどうやって、任意の数値を表現するのか。記号文字を使えるということは、たとえば'-'とか'$'のような文字リテラルを使うことができる。文字コードを限定すれば、その値はわかる。あとは、ビット演算を用いて任意の値に変えてやればいいだけだ。

_[]={ // 名前_の暗黙のint型の配列の宣言
'('-'!'|((','-' ')<<('$'-' ')) // 0xC7
    |
(('$'-' '|(('$'-' ')<<('$'-' ')))<<('('-' ')) // 0x44
    |
(('$'-' '|(('#'-'!')<<('$'-' ')) // 0x24
    |
((('/'-' ')<<('$'-' '))<<('('-' ')))<<('='-'-')) // 0xF0
,... 

// F0 24 C7 44
// mov dword ptr[esp-16], imm

もちろん、これを手で生成するのはダルいので、これを生成するコード、hello_gen.ccを書く。

#include <iostream>
#include <string>

using namespace std;

template <unsigned int n> struct Symbolizer {
 string s;
 Symbolizer() {
  if (n >= 0x10000) {
   s = "(" + Symbolizer<(n >> 16)>().s + ")<<(" + Symbolizer<16>().s + ")";
   if (n & 0xffff) {
    s = Symbolizer<(n & 0xffff)>().s + "|(" + s + ")";
   }
  } else if (n >= 0x100) {
   s = "(" + Symbolizer<(n >> 8)>().s + ")<<(" + Symbolizer<8>().s + ")";
   if (n & 0xff) {
    s = Symbolizer<(n & 0xff)>().s + "|(" + s + ")";
   }
  } else if (n >= 0x10) {
   s = "(" + Symbolizer<(n >> 4)>().s + ")<<(" + Symbolizer<4>().s + ")";
   if (n & 0xf) {
    s = Symbolizer<(n & 0xf)>().s + "|(" + s + ")";
   }
  } else {
   s = "(" + Symbolizer<(n >> 1)>().s + ")<<(" + Symbolizer<1>().s + ")";
   if (n & 1) {
    s = Symbolizer<1>().s + "|(" + s + ")";
   }
  }
 }
};

template <> Symbolizer<0>::Symbolizer() { s = "!\"\""; }
template <> Symbolizer<1>::Symbolizer() { s = "!!\"\""; }
template <> Symbolizer<2>::Symbolizer() { s = "'#'-'!'"; }
template <> Symbolizer<3>::Symbolizer() { s = "'#'-' '"; }
template <> Symbolizer<4>::Symbolizer() { s = "'$'-' '"; }
template <> Symbolizer<5>::Symbolizer() { s = "'%'-' '"; }
template <> Symbolizer<6>::Symbolizer() { s = "'&'-' '"; }
template <> Symbolizer<7>::Symbolizer() { s = "'('-'!'"; }
template <> Symbolizer<8>::Symbolizer() { s = "'('-' '"; }
template <> Symbolizer<9>::Symbolizer() { s = "')'-' '"; }
template <> Symbolizer<10>::Symbolizer() { s = "'*'-' '"; }
template <> Symbolizer<11>::Symbolizer() { s = "'+'-' '"; }
template <> Symbolizer<12>::Symbolizer() { s = "','-' '"; }
template <> Symbolizer<13>::Symbolizer() { s = "'-'-' '"; }
template <> Symbolizer<14>::Symbolizer() { s = "'.'-' '"; }
template <> Symbolizer<15>::Symbolizer() { s = "'/'-' '"; }
template <> Symbolizer<16>::Symbolizer() { s = "'='-'-'"; }

int main(int argc, char* argv[])
{
 cout << "_[]={" << endl;
#include "numbers.cc"
 cout << "};" << endl;
 return 0;
}

さて、.textセクションに書くバイナリ列はどのように生成するのか。これはhello_gen_gen.ccで、xbyakというライブラリを使って生成している。

#include <string>
#include <iostream>
#include <cstring>
#define XBYAK32
#include "xbyak/xbyak.h"

class PutString: public Xbyak::CodeGenerator {
 void syscall() { db(0x0F); db(0x05); }
 void int80h() { db(0xCD); db(0x80); }
public:
 PutString(const std::string &message) {
  unsigned int *data = (unsigned int *)message.data();
  mov(dword[esp - 16], data[0]);
  mov(dword[esp - 12], data[1]);
  mov(dword[esp - 8], data[2]);
  mov(word[esp - 4], data[3]);
  mov(edx, message.length());
  dec(eax);
  mov(ebx, 1);
  jmp("@f");
  add(byte[eax], al);
  dec(eax);
  lea(esi, ptr[esp - 16]);
  mov(edi, 1);
  mov(eax, edi);
  syscall();
  xor(edi, edi);
  mov(eax, 60);
  syscall();
L("@@");
  lea(ecx, ptr[esp - 16]);
  mov(eax, 4);
  int80h();
  xor(ebx, ebx);
  mov(eax, 1);
  int80h();
 }
};

int main(int argc, char * argv[])
{
 PutString put_string("Hello, world!\n");
 unsigned int *bin = put_string.getCode<unsigned int *>();
 size_t dwords = (put_string.getSize() + 3) / 4;
 std::string delim = "";
 for (size_t i = 0; i < dwords; ++i) {
  std::cout << "cout << " + delim + "Symbolizer<" << std::dec << bin[i] << "U>().s << endl;";
  std::cout << "  // " << std::hex << bin[i];
  std::cout << std::endl;
  delim = "\",\" + ";
 }
}

また、生成するビット列は、面白い工夫をすることで、x86, x86-64どちらでも動くようになっている。

実際にコードを入手して手元で動くことを確認したので、認めるしかない。

https://github.com/firewood/test

https://github.com/herumi/xbyak

ツール系で「BiiCodeとCLion」

あまり覚えていない。パッケージマネージャーはOSが提供すべきだ。

不遇の標準ライブラリ

valarrayの話。

Nicolai Josuttisが参考書に書いていたのだが、valarrayは標準化の途中で作者が途中で抜けたが、そのまま残ってしまったものらしい。標準ライブラリなので、ベクトル型としてコンパイラーが認識すれば最適化できるが、既存のほとんどの実装はvalarrayをベクトル型と認識した最適化をしない。

ベクトル計算は、Expression Templatesによる最適化に研究が向かってしまったので、型情報としてのベクトル型は放置されてしまった。

ただし、コンパイラーの最適化技術は進んだので、今ベクトル型として認識すれば、かなりいいコードが生成できる。現にiccはvalarrayをそれなりに最適化する。

ただし、ベクトル型を定義するのであれば、今新たに設計したほうがいい設計になるだろうから、やはりvalarrayに価値はない。

unique_ptrにポインタ以外のものを持たせる時

std::unique_ptrはカスタムデリーターにネストされた形名pointerを定義すれば、ポインター以外のものも管理できそうだが、既存の実装はnullptrと比較していたりして結局動かなかった。

C++標準化委員会には汎用RAIIラッパーが提案されている。

その後、22時頃まで一部の参加者が残って雑談したあと、解散した。

後片付けをした筆者が職場の自席に戻ると、日曜日なのに同僚のtayamaがいた。こんなに夜遅くに休日出勤なのだろうか。話しかけてみると、そうではなく、単に職場近くを通りかかったので、ついでに寄って、アニメを鑑賞しているだけだという。

勉強会で競技プログラマーがすごいhello worldを書いていたという話に及び、そのついでに、AtCoderで問題開示後3秒でコードを提出して通った猛者がいるという話をした。chokudai氏によれば、「問題の流出は確認されていない」という声明を出すに及んだという。

その場で調べてみると、3秒で提出されたコードは以下のものであった。

Submission #286413 - AtCoder Regular Contest 030 | AtCoder

問題は以下の通り。

A: 閉路グラフ - AtCoder Regular Contest 030 | AtCoder

n個の頂点からなる閉路グラフがあって、その頂点のいくつかを取り除くことでグラフを分断し、最終的にk個の連結成分のみが残るグラフにできるかという問題である。

問題文が意図的に難しく書かれているが、解法は、実際にグラフを生成して操作する必要はなく、単に\(k < \frac{n-1}{2}\)の場合は"YES"を、そうでなければ"NO"を出力すればいいだけだ。

問題開示後3秒でコードを提出したので、もはや人間業ではない。AtCoderにログインしてページをダウンロードしてコードを生成してアップロードするまですべてが自動化されている。どうやら、問題文は無視して、入力と出力のサンプルから、入力に対する正しい出力の計算方法を推定して、コードを生成したようだ。

ちなみに、問題の提出を探す仮定で、24秒で提出して通過したものなどが見つかった。こちらはどうやら手で書かれたようだ。問題は極めて簡単とは言え、人間業とは思えない。

我々はひとしきり感心した後に、職場を後にした。

ドワンゴ広告

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

ドワンゴは勉強会の会場を提供しています。

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

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

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

2015-05-14

歌舞伎座.tech #8 C++初心者会の参加枠を10人増やした

歌舞伎座.tech#8「C++初心者会」 - connpass

17日に行われるC++勉強会について、当日の都合の悪い人は、早めにキャンセルをしていただきたい。

まだ会場の空間に若干の余裕があることと、当日の参加率(100%参加は経験上おそらくない)を見込んだ上で、10人ほど枠を増やした。これにより、待機枠からの10人分の繰り上げが発生した。

繰り上がった人は、これまた都合が悪ければ、早めにキャンセルをしてもらいたい。

ドワンゴ広告

そういえば、勉強会は私の発表時間を確保していなかった。ただ、今話せるネタもあまりない。C++17はまだ遠く、現在の提案を元に何を話しても、おそらく最終的にはガラリと変わってしまうだろうから。

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

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

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

2015-05-13

C++標準化委員会の文書集、2015-04 pre-Lenexa mailingsのレビュー: N4381-N4389

ISO/IEC JTC1/SC22/WG21 - Papers 2015

N4381: Suggested Design for Customization Points

現在、C++の標準ライブラリにはいくつかのユーザー側で挙動を変更できる箇所が存在する。

  • swap
  • begin
  • end

だ。文面の解釈次第では、iter_swapも該当するかもしれないとのことだ。

論文は、標準ライブラリのうち、これらの挙動を差し替え可能な部分を、カスタマイゼーションポイント(Customization point)と名づけている。

この関数テンプレートは、std名前空間で定義されていて、汎用的な実装になっている。もし、独自のユーザー定義型に独自のswap/begin/end実装を書きたい場合

struct X
{
    int data[100] ;
} ;

その型の名前空間スコープに、同名の関数/関数テンプレートを書けばよい。

int * begin( X & x ) { return data ; }
int * end( X & x ) { return data + 100 ; }

こうすることによって、ADLで適切な関数が選ばれる。

問題は、標準のカスタマイゼーションポイントと、ユーザーの提供するカスタマイゼーションポイントを合わせて呼び出すには、std::beginのようにqualified nameで呼び出すことはできない。現行のカスタマイゼーションポイントは、ADLを使っているので、以下のように呼ばなければならない。

template < typename Container >
void f( Container && c )
{
    using std::begin ;
    using std::end ;

    auto iter = begin( c ) ;
    auto end = end( c ) 
}

こうすることによって、std::begin, std::endという名前をname lookupで発見できるようにしたうえで、unqualified name lookupを行うと、ADLも働き、見つかった名前の中でオーバーロード解決が行われる。

しかし、このようにusing宣言を書いてからunqualified nameを使うやり方は、その原理の説明まで含めると、規格の詳細まで踏み込まねばならず、面倒だ。普通にstd::funcのようにqualified nameで呼び出してもこのような挙動になってほしい。

このようなcustomization pointは、今後も追加される見込みであるから、将来追加されるcustomization pointは、関数オブジェクトにして、その中でADLを用いたディスパッチにしようというという提案。

namespace std {
    namespace __detail {
        struct __begin_fn
        {
            template < typename R >
            constexpr decltype(auto)
            operator () ( R && rng ) const
            noexcept(noexcept(begin(forward<R>(rng))))
            {
                return begin(forward<R>(rng)) ;
            }
        } ;
    }

    template < typename T >
    constexpr T __static_const { } ;

    namespace {
        auto const & begin =
            __static_const< __detail::__begin_fn > ;
    }

}

つまり、std::funcはstd名前空間にあるfuncという関数や関数テンプレートではなく、関数オブジェクトになる。その関数オブジェクトは内部でADL経由のオーバーロード解決を行う。単純に__begin_fnの変数を宣言していないのは、ODRを回避するためだ。変数テンプレートにすることで外部リンケージを持ち、そのリファレンスを取ることですべての翻訳単位で共通にする。かつ、無名名前空間で囲むことによってその翻訳単位だけにする。

論文では、最適化の結果、出力されたコードにオーバーヘッドは一切ないことを確認したと書いてある。非最適化コンパイルではオーバーヘッドが生ずるが、問題ないコストであるという。

ただし、論文にも挙げられているように、問題も多少あるので、まだ議論が必要そうだ。

論文は、既存のcustomization pointには互換性のためにこの技法を適用しないとしている。そういう不一致もどうかと思う。

この手法は、range-v3ライブラリで試されているという。

N4382: Working Draft, C++ extensions for Ranges

イテレーターをさらに高級にしたレンジというライブラリの提案。提案中の軽量コンセプトを使って作られている。番兵の概念も導入するらしい。

N4383: C++ Standard Library Active Issues List (Revision R92)

N4384: C++ Standard Library Defect Report List (Revision R92)

C++ Standard Library Closed Issues List (Revision R92)

標準ライブラリの既知の問題、解決済みの問題、議論の結果却下された問題の一覧。

[極めて無駄なPDF] N4386: Unspecialized std::tuple_size should be defined

std::tuple_sizeのプライマリーテンプレートは従来未定義だったが、これを定義する提案。これにより、enable_ifのようなSFINAEの文脈で使いやすくなる。

N4387: Improving pair and tuple, revision 3

pairとtupleのコンストラクターがexplicitとなっているために、一部の初期化ができない問題を修正する提案。

以下のコードはエラーになる。

std::tuple<int, int> pixel_coordinates() 
{
  return {10, -15};  // エラー、なんで?
}

// コピーできない型、直接初期化はできる。
struct NonCopyable { NonCopyable(int); NonCopyable(const NonCopyable&) = delete; };

std::pair<NonCopyable, double> pmd{42, 3.14};  // エラー、なんで?

pairとtupleが設計されていた当時、暗黙に型変換できない型から暗黙に構築できてしまうことを防ごうとした。

また、C++03時代の0というnullポインター定数の挙動の互換性を保とうという設計もされていた。

また当時、pairはアロケーターサポートのためにコンストラクターの数が膨れ上がっており、新しくコンストラクターを追加するのはできない雰囲気であった。

結果として、N3240提案を受け入れた結果、pairとtupleは以下のような設計がなされることになった。

1. 要素の型が実引数の型から暗黙に変換できない場合は弾く。

struct B { explicit B(bool); };

std::tuple<B> tb = std::tuple<bool>(); // エラー

非テンプレートとテンプレート版の同等のコンストラクター、tuple( const Type & ... )は、explicitとなった。これにより、要素がひとつだけのtupleが、explicitしかコンストラクターがない実引数からコピー初期化されるのを防ぐ

struct X { X(); explicit X(const X&); } x;

std::tuple<X> tx = x; // エラー

struct E { explicit E(int); };

std::tuple<E> te = 42; // エラー

非テンプレート版のコンストラクターは、nullポインター定数である0からの変換を許容する。

class C;

std::tuple<int*> tpi(0); // OK
std::tuple<int C::*> tpmi(0); // OK

この提案は、実装例として、perfect initializationと称する技法を提示している。テンプレートのexplicit/非explicitのコピー風コンストラクターをオーバーロードすることで元の型とほぼ同じように初期化できるという仕組みだ。文面はこの技法を使うことを必須としておらず、実装上の自由をもたせている。

N4388: A Proposal to Add a Const-Propagating Wrapper to the Standard Library

メンバー関数のconst性をポインター風のメンバーに対しても伝播するライブラリ、propagate_constの提案。

非staticメンバー関数のconst修飾は、ポインター風のデータメンバーを伝播しない。

struct A
{
    void f() { } // 非const
    void f() const { } // const
} ;

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

    void f()
    {
        ptr->f() ; // 非const版が呼ばれる
    }

    void f() const
    {
        ptr->f() ; // 非const版が呼ばれる
    }
} ;

これは言語的には正しい挙動だが、意味上のconstとして、ポインターを経由したアクセスでもconst版のメンバー関数が呼ばれて欲しい場合がある。この時に使える。propagate_constライブラリを提案している。名前通りに、const性を伝播させる。


struct B
{
    std::propagate_cosnt<std::unique_ptr<A>> ptr ;

//  以下同じ
} ;

N4389: Wording for bool_constant, revision 1

std::integral_constantのbool版のエイリアステンプレート、bool_constantの提案。既存のtrue_typeとfalse_typeはbool_constantを使ったものに書き変える。

namespace std {
  // 20.10.3, helper class:
  template <class T, T v> struct integral_constant;

// N4386提案
template <bool B>
using bool_constant = integral_constant<bool, B>;

// C++14の定義 
// typedef integral_constant<bool, true> true_type;
// typedef integral_constant<bool, false> false_type;

// N4386提案
typedef bool_constant<true> true_type;
typedef bool_constant<false> false_type;

ドワンゴ広告

今週末は勉強会だ。今回は初心者に発表経験を持たせるために、初心者ばかりを募ったはずなので、それほど怖い話はないはずだ。たぶん。

歌舞伎座.tech#8「C++初心者会」 - connpass

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

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

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

2015-05-11

D4492: Bjarne StroustrupによるC++17の考察の翻訳

April 2015 : Standard C++

C++WG内部のMLで議論していた内容が、どこからか外部に流れて、様々なフォーラムで話題になっている。

“What will C++17 be?” -- Bjarne Stroustrup on C++17 goals : programming

What will C++17 be? | Hacker News

C++ Daddy Bjarne Stroustrup outlines directions for v17 • The Register Forums

これを受けて、Bjarne Stroustrupは議論をまとめて標準化委員会の論文として公開することにしたが、それも時間がかかるので、ドラフトがC++財団にあがっている。

[PDF注意] D4492

C++17の考察

Bjarne Stroustrup

このドラフトはLexena会議における議論の方向を定めるためのものである。

これは標準化委員会内部のやり取りが外部に流通して広く議論されていたのを、ドキュメント化する価値があるので、意見を参考にまとめたものだ。委員会内のわかりにくい符牒は置き換えるようつとめた。内部で議論したり、Web上で議論した人間に感謝する。筆者はリンクも追加した。これは正式な論文や提案というよりは、議論のための考えの列挙に過ぎない。

この文章は委員会のメンバーに向けて書かれたものだが、いつのまにか公に出回った。以下がWeb上のコメントの一部である。

見てわかるように、委員会外の人間も、強い意見を持っている。これらの意見は、筆者が委員会内で聞くものとはかなりかけ離れているし、現実ともかけ離れている。

筆者は、「C++17はどのようになるのか?」とか、「C++17は私に何をもたらすのか」といった質問をよくされる。「よくされる」というのは、「ほぼ毎週2回以上」程度である。私はC++17がどのようになるかを簡単に説明することができないので、この質問に対しては自信恥ずかしい思いをする。言語機能や標準ライブラリの一覧は、納得できる答えではない。

筆者はC++98, C++11, C++14における目標について話そうと思う。今のC++を実現してきた目標とは何か。

今と同じように、かつてもC++を委員会による設計の弊害を受けた汚らしい成れの果てだとみなす風潮があった。これは、委員会が組織される前から言われていたことだが、今や更にひどく言われているように思う。今やC++はより巨大になった(特に標準ライブラリを考慮すると)。そのことと、現在の大量の提案を考えれば、その指摘にも一理あるように見える。この手の連中が、変態的な技法を用いたパズルめいたものを提出して攻め立てるのはいらただしいことだ。その手のものは、筆者からすれば、「何か問題があるのかね。もちろんメタハンマーで頭を叩くのは痛いだろう。だからそんなことはするな」というカテゴリーに分類されるべきものである。連中は委員会の責め立てる。そのようなコードはたいてい、C++を貶めるために使われるものだ。よりよいソフトウェアを書いたりするのに役に立たないばかりか、。人々をC++の学習から遠ざけてしまう。

物を作るより批判するほうが簡単だ。

Robert Klarerが言うには、「委員会による設計に対する懸念は、必要以上に恐れられている。そもそも、この世界の殆どの者は委員会によって設計されているというのに。人間によって作られたもので、何らの協調作業も発生していないものは極めて少ない」と。我々はチームで作業しなければならない。他の方法はないのだ。

C++は多くの利用例において最良のツールである。特に、リソースの制約が厳しいであるとか、巨大であるとか、利用期間が長いなどの過酷な用途に向いている。これをさらに改良し、かつ初心者にわかりやすくし、それほど過酷ではない仕事(ただし、大抵は急いでいる)に従事する人にも使いやすくしたい。

さて、C++17はどのようなものになるべきか。私の考えはこうだ。

  • 巨大な依存のあるソフトウェアのサポートの改良
  • 高級な並列実行モデルのサポートの提供
  • コア言語の利用を簡単にする。とくに、STLと並列実行と、主要な間違いの元を改良する

最後の項目は、先の2つの項目の書き直しでもある。

そして以下が、C++11やC++14で継続して行ってきたことの簡単なまとめだ。実際、C++の長期的な目標からはあまり違わない。

標準化委員会はC++の根本的な強みを維持しなければならない。

  • ハードウェアに直接マッピング可能なこと(Cから)
  • ゼロオーバーヘッドの隠匿(Simulaから)

[訳注:Simulaは極めてオーバーヘッドが大きかったので反面教師的な意味合いか?]

この強みから離れると、その言語はもはやC++ではなくなる。別の目標を持った言語は様々ある。他の言語とてすべての問題に対する解決を提供しているわけではない。当初の目標から外れず、変化を受け入れる姿勢こそが、理想に近づけるのだ。C++は計算機の歴史上、もっとも成功した言語の一つとなった。これを維持するためには、2つの落とし穴を避けねばならない。

  • 過去を捨て去ること(例、互換性を深刻に失うこと、C++は長期的に使われるシステムで多用されてきた)
  • 新しい問題への対処を怠ること(例、高級な並列実行モデルをサポートしないこと。C++は並列実行の需要を満たすために多用されている)

さて、これが基本だ。以下が詳細だ(関連する論文へのリンクもある)

筆者はライブラリと言語機能を意図的に分割しなかった。そういう区別は一般ユーザーには無意味なものだからだ。

筆者の予想では、C++17は2017年に制定される。標準的なISOの10年リリースサイクルに戻るべきだとは思わない。

この表に好きな機能がないとしたら? それはフレームワークに取り込んで使える機能だろうか? C++の目標は変えるべきだろうか? 主要な目標は3つ程度であるべきで、後の2つは外せない重要なものだ。なにかよりよい目標を設定できるだろうか?

もし、お気に入りの機能が今回入らなかったとして、C++20の時間枠に入るだろうか? 筆者は、単に自分の提案だからという理由ではなく、短期から中期(C++17, C++20)において、いま重要だと思うことに注力している。

歴史的に、委員会は、目標にそぐわなかったとしても、自明に有用でよく使われているものを追加しようとしてきた。complex<T>はそのいい例だ。そのようなことは二度としないとはいわないが、頻繁に行うべきではない。そのような方向性の定まらないアイディアで、重要な目標や納期を見失ってはならない。

C++17は、マイナーリリースだったC++03やC++14と違い、メジャーリリースとなる予定である。何か主要な機能を提供しなければ失望されるだろう。筆者の考えでは、2つか3つほどの主要機能と、いくつかの中規模な機能と、いくつかの小規模なものが、最低限の許容可能で実現可能なものだろう。筆者は規模の大小について、標準規格の文面の量ではなく、ユーザーに与える影響で考える。そのため、コンセプト、モジュール、レンジは大規模(そして筆者の好ましいと思う機能)で、デフォルト比較やstd::optionalは小規模だ。(とはいえ、筆者の好みの機能だ)

無関係の機能やライブラリを大量に追加するのは、言語を複雑にし、初心者にも、「通常のプログラマー」にも、C++を恐れさせてしまう。一部のエキスパート(標準化委員の一部とその身内)は満足だろうが、目標を明確に見据えなければ、一般のプログラマーを惹きつける魅力は得られない。これを「マーケティング」と呼ぶ人もいるだろうが、筆者は、「設計」と呼びたい。

わかりやすい例を出すと、STLはそのいい例だ。もしAlex Stepanovがたった数種類のコンテナーと数個のアルゴリズムしか提案しなかったのであれば、その提案は今よりとてもわかりやすかっただろうが、STLに与えた影響は今よりも軽微であっただろう。実際、STLは変わっていくものである。筆者はコンセプトとコンセプトベースの標準ライブラリが次のいい例となることを期待している。「委員会による設計」の典型例となって嫌われることは望まない。

筆者がしたくないこと:

  • C++を劇的に違う言語にすること
  • 分割された言語のサブセットを提供することで、C++の一部をさらに高級な言語とすること
  • 新しいパラダイムをサポートするためにC++に機能をツギハギすること
  • C++が必要とされている分野でC++が使われることを妨げること
  • 99%の利用者にとってC++を使う際の複雑性を上げることによって、1%(標準化委員とその身内)を利すること

このどれもが失敗のもとだ。

これについては同意できるだろうが、果たして読者はその同意を維持できるだろうか。怪しいものだ。抽象的な目標について同意することはできても、その目標の意味する具体的なところについては、何かができなくなったり、納期に間に合わせるために後回しにしたりしなければならないため、この基本目標への同意は用意に破られやすい。「何を捨てるのか決定するのが難しいのだ」とはよく言ったものだ。

もちろん、筆者は特定の一覧の他は一切C++を改良するための提案を行わないことを主張しているわけではないが、しかし、なにか優先度について合意をしておかなければ、委員会には何十もの「ほぼ完了した」主要機能が2016年に溜まり続け、機能追加を辞める段階になっても、どれも規格制定には至らない状態になっていることだろう。何十もの小規模な、独立した機能は、我々がプログラムを構築するのにそれほどの影響をもたらさないので、主要機能ほどの魅力はない。

Pete Beckerの言葉を要約すれば、鉄の三原則とは、機能、品質、納期だ。2つまでならば選んでもよい。選択をしなければ、委員会は何も選ばなかったことになる。

委員会の避けるべき悪い習慣、C++批判の燃料となる習慣:

  • 言語機能よりもライブラリのほうが標準化委員会で受け入れられやすいのでライブラリとして提供する(たとえその提供する機能が根本的なものであると主張する十分な材料があるとしても)
  • 既存の機能と組み合わせた使い方は互換性の問題を生ずるので、独立した機能として提供する。これは単に組み合わせを将来に先送りするだけだ
  • 2つの相反する選択肢がある場合に、両方とも採用する。あるいは選択肢を3つにして、最初の2つの選択肢を、投票権を持つ全員が喜ぶ形に書き直す(これは純粋に委員会による設計だ)
  • 自分のお気に入りの提案に費やす時間と労力が足りないために、別の提案に反対する
  • 超短期的な利益のみを追求する
  • 現在の自分の仕事に関係のない提案に反対する。他人を利する改良を停滞させる。
  • 論文の文面に注力して、ユーザーの需要を無視して、現在の文面に一致する技術的な選択をする。
  • 文法の多さはプログラマーを楽にするはずだという考え
  • ライブラリ作者などのエキスパート達のみを相手にして、大多数の現在と潜在的な世間一般のC++プログラマーを無視する
  • 「現在の流行」を追い、C++のプログラミング流儀に与える影響と既存のC++機能との併用を考えずに、他の人気の言語からの機能をダメ押しする
  • 既存の機能との併用を避けるために、提案を自己完結させる
  • すでに提案されている他の提案を無視する
  • 「原則」を神聖にして不可侵るものだと主張する
  • 完璧でないものを受け入れない
  • 何でもしようとする

こういうことをしてはいけない。

筆者がよく聞かれることに、特に、影響力がある有名人に聞かれることに、D&E 2を予定していないかということがある。予定していない。筆者はC++の利用と改良にとても忙しい。しかし、もし引退するのが都合がいいと考えたならば、D&E 2はよい企画だ。しかし、そのためには言語と友人をけなす必要が内容にしなければならない。委員会は自ら誇って語れるものを制定する必要がある。

標準化委員会には長期的な目標が必要だが、そういう目標は、往々にして「カーチャンの味噌汁の味付け」のような絶対に反論不可能なものになる。委員会には短期的な目標も必要だ。さもなければ、現在の誰かの問題を解決するためだけの機能を追加し続けることになり、将来の発展の妨げになり、機能の重複にもつながる。これは、筆者が、「開発者視点の思考」と名付けるもので、何十年も存続する長期的なプロジェクトにはふさわしくない。目標についてよく考える必要がある。筆者の主要な目標は、長期的な利益の方にバイアスがかかっており、残りの2つは、C++17についてだ。

標準化の仕事では、標準化委員は単なる開発者ではいられない。成功するためには、委員は、研究、目標の設定、計画、管理、実装、教育と普及などなどの様々な役割をこなさなければならない。

標準化委員会はなにか大きなものをC++17で制定しなければならない。筆者が考えるに、委員会はその方向で動いている。実験と称して規格制定を遅らせたり、小さな改良のみに注力するのは大きな間違いだと思う。つまり、標準化委員会はいくつかの大きな問題と、それを支える小さな問題に注力しなければならない。筆者の恐れることは、委員会はすべてのことをしたがるあまりに、すべての提案を等しい優先度で扱い、結果として、全方向に僅かな改良だけが得られるということだ。明らかに、C++20まで先送りにしなければならないものもある。標準化委員会にはStudy GroupとTS(ISO Technical Specification)があり、両方共、標準化のために必要な諸々の作業を提供することができる。現在作業しているすべての労力がC++に入るわけではないし、好ましいもののみがC++17に入るわけでもない。大きな集団にありがちな、利己的な目標を達成するために規則を悪用するようなことにはなってほしくないものだ。

「でさ、Bjarne」と私の友人の一部が笑いながら言う。「お前が本当に考えてることを聞かせてくれよ」と。つまり、私の考えていることはあまりにも尊大で誰かを侮辱するかもしれないということだ。私の考えることが、誰か、C++コミュニティの利益を考える人間を侮辱するということはない。実際、私の言っていることは侮辱ではない。

さて、これが個人的なC++17のトップ10リストだ(順不同)

  • コンセプト(ジェネリックプログラムを詳細に規程できる上、エラーメッセージの品質が悪いという不満を解消できる)
  • モジュール(マクロから独立できる上、コンパイル時間の短縮になる)
  • レンジとその他のコンセプトを使ったSTLコンポーネント(エラーメッセージの改良とSTL2としてのライブラリ文面の改良)
  • 統一関数呼び出し記法(仕様の簡単化とテンプレートライブラリ利用の簡略化)
  • コルーチン(とても高速で簡単であるべき)
  • ネットワークのサポート(TSのasioベース)
  • 契約(C++17の標準ライブラリで使われる必要はない)
  • SIMDベクトル演算と並列アルゴリズム
  • コルーチン[訳注:原文ママ]
  • optional, variant, string_view, array_viewのような"vocabulary type"

最後に、筆者は言語とライブラリと、新機能と、既存の機能との、一貫性の重要について再び記しておく。標準化委員会の目標は、関係性の曖昧な機能群ではなく、有用なアイディアのための一貫した言語でなければならない。

この一覧表はすべて、C++17の標準規格の文面に入れるのに現実的であり、コンパイラーとライブラリの実装も現実的である。ほとんどの機能は、すでに何らかの形で存在している。重要なのは、どのように設計するか、どのようにコードを書くかである。

これが、筆者の機能一覧だ。C++コミュニティの利益と、実現性を考えた結果だ。読者の機能一覧はこれとは異なるかもしれない。よく考えてもらいたい。私の好む提案で、特に筆者も著者となっている論文で、この一覧にあげていないものもある。解決すべき問題があるが、まだ技術的な解決法がないのだ。例えば、標準C++ABIなど。筆者が思うに、C++17にはまだいくつかの提案が出てくるだろうから、これを最終的な機能一覧だとは考えないでもらいたい。これは議論を集中させるための土台で、最終決定ではない。それに、まだTSもある。

C++17制定後は、C++20がC++17を完成させるだろう。C++14がC++11に大してそうだったように。

ドワンゴ広告

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

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

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

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

2015-05-07

InfoQのC++17についてBjarne Stroustrupへのインタビュー記事の翻訳

Stroustrup: Thoughts on C++17 - An Interview

C++の設計者にして最初の実装者であるBjarne Stroustrupは、C++17の設計と新機能の議論の起爆剤となるための、ドラフトを公開した。Stroustrupによれば、C++17は以下の3つの設計目標がある。

  • 巨大な依存関係のあるソフトウェアのサポートの改良
  • 並列実行に高級なモデルのサポートの提供
  • コア言語を簡単にする

上記の設計目標について、StroustrupはC++17に入る以下もしれない機能を列挙した。Stroustrupの好ましいと考える機能の例が以下だ。

Stroustrupは、「言語とライブラリの新機能の一覧」をもって、C++17がどのようなものになるかを説明することはできないと注意を促している。C++17は、C++14と違い、メジャーリリースであるため、少なくとも、言語がユーザーに与える影響として「2つか3つほどの大きな機能」が入っているべきであるとしている。例えば、コンセプトやモジュールやレンジなど。

この文書は興味深いことに、C++17が目指さないことについても書いてある。特に、Stroustrupが不適切であるとしたものは以下の通り。

  • C++を急激に別言語にすることや、言語のサブセット言語を作ること
  • 「他の言語がみんなサポートしている」とか、新しいパラダイムをサポートするという理由だけによって、新機能を追加すること
  • 言語を複雑にしたり、システムプログラミング用の言語としての力を阻害すること

InfoQはStroustrupと話す機会を得た。

InfoQ、「C++17の機能一覧についてコメントをくれませんか。優先順位はありますか」

Stroustrup:

コンセプトは既存のジェネリックプログラミングへの考え方を改めるだろう。ジェネリックプログラミングをさらに主流のものとする。コンセプトはエラーメッセージが難解であるという不満への解決でもある。それには、標準ライブラリにコンセプトを対応させなければならない。

モジュールはコンパイル時間とマクロの濫用を劇的に改善し、優れたC++のツール開発につながるだろう。

高級な並列実行モデルは並列コードを書くのをとても簡単にし、低級なスレッドとロックによる並列コードよりも、結果のコードの実行を高速にするだろう。

これらの機能はコードを簡単にすることで品質を向上させるので、理想的だ。

InfoQ、「ここ数年と今後の標準化委員会のC++17働きにより、C++言語はよく議論される制限を克服しようとしているように見えます。これは、「委員会による設計」は実用的なものを生み出さないという意見を否定的に証明しているようです。委員会による設計についてコメントをください。どのようにすれば成功するのでしょうか。」

Stroustrup:

委員会による設計の問題を見過ごすことはできない。100人もの個人(会議に出てこないものまで含めれば、あるいは300人もの個人)からなる集団から、なにか新しい、信頼できる、統一感のあるものを創りだすのは並大抵ではない。

我々がやっていけるのは驚異的なことだ。もちろん、もっとうまくやれた部分もある。もちろん、委員会として活動するのは埒が明かないときもある。しかし、このスケールは、個人ではやり遂げることができない。これは委員会か個人かどちらがよいかという問題ではなく、委員会として活動するのが必須であるというだけの話だ。この世界の重要なことで、個人によって成り立っているものは実に少ない。

InfoQ、「C++17はC++が根本的に、低級(言語の意味をとても細かく操作できるという意味)で、マルチパラダイムで、複雑な言語であるということを示しています。しかし、委員会の目的に言語を使いやすくするということが含まれています。C++をより使いやすくするという委員会の思想についてお答えください。」

Stroustrup:

言語の低級性高級性について考えるのは間違いだ。C++はハードウェアを直接操作することを妨げないということと、それに加えて、隠匿の仕組みを用いて、必要であればより高級に隠匿できるものとして考えるべきだ。ハードウェアに近いプログラミングは必要だが、あまり快適ではない。C++はゼロオーバーヘッドの隠匿を可能とし、コストを加えずしてハードウェアから離れることができる。「ゼロ隠匿」というのは、手で書いた低級な実装よりも、1バイトも1サイクルも無駄にしないということだ。関数呼び出しのオーバーヘッド(特に間接的な関数呼び出し)ですら懸念される。ハードウェアアクセスと隠匿を同時に提供するのが、C++の考えだ。それを効率的に行うというのが、他の言語との違いだ。

私はこれをもう「マルチパラダイム」とは呼んでいない。なぜならば、私はこの言葉が、言語のすべての力を活用するより、単にひとつのパラダイムを選択してソレだけを使うことを推奨してしまっていると気がついたからだ。残念ながら、私はこれに変わるいいバズワードを思いついていない。

委員会が何らかのひとつの思想を持っているというのは公平ではないだろう。我々は多くの個人であり、それぞれ異なる事情と視点を持っている。多くはC++について上記のことに同意している。これがC++の精神であり、誤解してはいけない。我々は互換性を厳格に守らなければならないということについても同意している。C++業界は改良を求めるが、しかし、この業界は絶対に絶対に既存の何十億行ものコードが、その改良の結果として壊れることを望まない。どのような改良をしたかの詳細については重要だ。これはまともな時間内に実現可能でなければならないし、言語とライブラリでどのように表現するかということも重要だ。これは多くの集団で合意が得られにくいものだが、合意は必須だ。だからこの文書を書いたのだし、次の会議でもこのことについて話すのだ。

私がC++とその標準化に多大な時間を費やしてきたのは、これが多くの業界にとって重要だからだ。コンピューター、セミコンダクター、交通、電信、ファイナンス、製造業、旅客機、娯楽業界、などなど。多くの重要なシステムやガジェットの中身を見てみると、だいたいC++が使われている。この事実と、ソフトウェアシステムによって科学に貢献していることが、私の動機だ。C++は重要な財産を作るために使うためのツールだ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。最近、ドワンゴがITSCJの規格賛助員になったので、いつかC++標準化委員会の国際会議にも出席してみたいものだ。

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

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

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

2015-05-06

Jacob Kaplan-MossのPyCon 2015における基調講演: プログラミングの才能という都市伝説

Keynote - Jacob Kaplan-Moss - Pycon 2015 - YouTube

The programming talent myth [LWN.net]

PyCon 2015で、Djangoの貢献者であるJacob Kaplan-Mossが興味深い基調講演をしているので紹介する。LWM.netでほぼ全面書き起こしに近いまとめがあったので助かった。

自己紹介

Kaplan-MossはDjangoの貢献者であり、Herokuのセキュリテイ部門の部長である。PyCon参加者としては歴史が長く、その他のカンファレンスでもよく発表している。Pythonコミュニティは「自分にとってこの業界におけるとても重要なもの」であり、PyConの基調講演を行うということは、「自分のキャリア上の絶頂」である。

自分の最初のPyConの発表は2005年のことで、PythonとAppleScriptを結びつけるツールについてのものであった。ワシントン DCで開かれた当時のPyConで、Adrian HOlovatyは、自分の働くカンザス州Lawerenceの新聞社のWebサイトを構築するためのツールの技術デモを行った。このツールは、後にDjangoとなるものであった。今や、Djangoは10歳になり、世界中で使われている。PyCon参加者が300人から3000人に膨れ上がるまでを見てきた。コミュニティは新規参加者で膨れ上がり、別物になりつつある。そのため、「自分のキャリアにおける絶頂」というのは、文字通りの意味だ。

しかし、頭の中でふと思うに、自分はこの発表のステージに立つのにふさわしくないのではないか。この成功を受けるほどの価値ある人間ではないのではないか。脳内で、謙遜が起こる。

今までの業績は誇らしい物だ、実際、自分の過去の業績は、自分をこの場に立つ価値があるものにしている。しかし、自分は聴衆が考えているような人間ではない。

聴衆の多くは、自分がここで基調講演を行っているのは、「Djangoの発明者」であるからだと考えているだろう。しかし、それは違う。Djangoの由来を知っているものは、「Djangoの共同開発者」であると考えるだろう。しかし、これも過大評価である。実際には、自分はAdrian HolovatyとSimon WillisonがDjangoを発明して共同開発した一年後に、新聞社に雇われて開発に参加した者である。そんなわけで、自分は「すでに出来上がって1年以上たったものを開発するために雇われた人間」である。

皆、自分のことをDjangoの発明に関わりのある人物だと考えるのは、自分が「素晴らしいプログラマー」であると考えているからだろう。つまり、「ロックスター」とか「ニンジャ」とか、あるいは「転職エージェントが最近よく使う言葉」のプログラマーであると考えているからだろう。皆、自分はプログラミングの能力によって成功したと考えている。しかし、それは違うのだ。「私は、言うてありきたりなプログラマー」である。

ランニングについて

[ライドにウルトラマラソンランナーのAnn Trason] Ann Trasonはスポーツの歴史上素晴らしい成果を上げた者だ。ウルトラマラソンとは、26マイル以上走るマラソンのことだ。大抵は、山道を走ったり、川を横切ったりするもので、難しいものになると、何日も走り続けなければならないものだ。走る距離はたいてい50kmから160kmほどだ。Trasonは10年、20年後も破られない記録をいくつも作っている。彼女の記録に一時間以内に入れる人間はいない。Trasonはこの業界を独占していて、実にずば抜けて優秀な人物である。自分がこれを話すのは、自分もこの間、50kmのウルトラマラソンを走ったからだ。

しかし、自分はTrasonには遠く及ばない。同じブランドの靴を履いているだけだ。自分はどこにでもいるありきたりなランナーであり、1000人中535位であった。ランニングのパフォーマンスを評価する数値は多数ある。ペース配分、コースの距離や高度などだ。ランナーのスコアを計算して、そのランナーがどのくらい優勝者に近いかをはじき出すWebサイトがある。自分は68%であり、Trasonは98.58%だ。つまり、彼女はだいたい優勝するということだ。

この差は驚くに当たらない。レースのタイムのヒストグラムを描いてみると、よく見慣れた曲線が描かれる。ベル・カーブ、あるいは正規分布と呼ばれているものだ。ほとんどの人間は平均的で、ごく一部の例外的に優秀か、ダメな者が、極めて細い曲線の終わり付近にいる。我々が計測方法を知っているおよそすべての能力は、この曲線のような分布をする。

ありきたりということについて

さて、じぶんはありきたりなプログラマーであるが、聴衆の中には、信じない人もいるだろう。何故だ? ここにいる聴衆のほとんどは、Kaplan-Mossと共同作業をしたことがないはずなのだが、なぜ自分のコーディング能力が例外的に優秀であると言えるのか。評価すべきデータが存在しない状況では、曲線の中央辺りに位置すると考えるべきではないのか。そもそもの問題として、コーディング能力を評価する方法がないということがある。我々はソフトウェアを作成する能力を評価する方法を模索している赤子のようなものだ。評価基準としては何がある? コード行数か? 一体それは何を評価しているのだ? ストーリーポイントか?[訳注:スクラム用語、ストーリーを完了するために必要な作業時間の見積もり]。そもそも、ストーリーポイントって何なんだ?

プログラマーは論理的な解析的な現場で働いていると思いがちであるが、実際のところ、プログラミング能力を機械的に計測する方法などないのだ。人間は、データが与えられない時、逸話を作る。この逸話は、単純でステレオタイプになりがちである。そこで、我々は、「プログラミングのできないザコ」とか、「プログラミングのできる神」などと言ったりして、その中間を完全にすっ飛ばしてしまうのだ。人というのは誰でも、素晴らしいプログラマーか、あるいは、「椅子を浪費するだけの無能」のどちらかに分類される。

しかし、その場合、プログラミング能力というものは、U字型の曲線を描くことになる。ほとんどの人はその両端のどちらかに属している。これはいかにもありえないことだ。思うに、人間というものは経験を積むにつれて学んでいくものだろう。どうやって、何もできないザコからガチ勢まで、中間を経ずして能力の向上ができるのだろうか。両極端な2つの分類しかできないため、多くの者は自分を「素晴らしいプログラマー」に分類するのだ。あいつはDjangoの関係者である。するとクソなプログラマーの方に分類することはありえない。自然として、もうひとつの方を選ぶようになるのだ。

しかし、もし、何らかの方法でプログラミング能力を評価できるとしたならば、その曲線は正規分布するはずである。ほとんどのひとはほとんどのことにおいて平均である。Wobegon湖[架空の地名。過大評価する例えに用いられる]ではないのだから、大多数が平均より上であることはありえないのだ。

危険な都市伝説

この、プログラミング能力がバイモーダル分布(U字型)するという考えは、危険であり、都市伝説である。この都市伝説は、ロックスターかニンジャでなければプログラミングできないという雰囲気を作り出す。これは人々をプログラミングの学習から遠ざけるという害悪をなしており、将来のためによろしくない。

アメリカ労働省の統計によれば、2020年には150万人のプログラマー職の求人数にたいする労働者の供給不足が生じると予測されている。これは、多くの職場で人手不足ということになる。これは5年後のことだ。EUも似たような数字を出している。2018年に120万人。3年後だ。つまり、我々はなんとかしてもっと多くの人材をこの業界に呼び込まねばならない。しかし、この都市伝説はプログラミングを仕事に選択しようと考える人たちを躊躇させるものとなっている。この都市伝説は、プログラミングというものは生まれながらにして持つ先天的な才能であるという考え方からも支持されている。まだソフトウェアを書いたことがなく、都市伝説を信じるものは、用意にこの罠に引っかかる。年齢が30か、あるいは20か15になって、まだ一度もコードを書いたことがないので、一生コードを書けるようにはならないだろうと考えてしまう。

もし、選択肢が神かザコしかないのであれば、仕事に対してやりがいを感じなければやってられないと考えるようになるだろう。いつなんどきでも四六時中プログラミングのことを考えている奴、ほんの僅かでもよそ見をすれば、すぐに神からザコに落ちてしまうという考え。この考えは、人々をして長時間労働させ、プライベートな時間でも常にプログラミングについて学ぶようにさせていたりする。

しかし、他の業界については、我々はそのようには考えない。去年マラソンを走った50万人の参加者の全員が、先天的にランナーとしての才能を持っていたのであろうか。疑わしいものだ。私はそんな才能は持っていない。ほとんどの参加者は、かなり悪く走っていた。極めてひとにぎりの者達が、とてもよく走っていた。ランナーとなるためには、靴が一足あればいいだけのことだ。ランナーとなるために、走ることを好きになる必要はない。

自分がランニングで一番好きなことは、ゴールすることだ。マラソンを走るのは難しい。訓練と継続が必要だ。ソフトウェアを書くことは、Pythonを書くことは、マラソンを走るより難しいだろうか。なぜここには50万人の聴衆がいないのか。コーディングという能力に対してはそういうは話をしておきながら、ランニングという別の能力にはそういう話をしていないではないか。

自分は数年前、カンザス大学のGISデーで、カンザス川の反乱の予測に関する素晴らしい発表を聞いた。この学生が使ったツールは、このPyConでは使い慣れたものが多いであろう、Amazon Web ServiceとかLinuxとかPostgreSQLとかPytonとかDjangoとかGeoDjangoといったものだ。この学生はPythonで数千行のコードを書いたばかりだった。自分はうちの会社の採用面接を受けるつもりはないかと聞いてみた。学生は、「自分にはできない」という。なぜならば、「自分は本物のプログラマーではないから」と。この学生は自前で分散GISデータ処理パイプラインをたったいま実装した者であるが、本物のプログラマーではないという。これはプログラミングとは都市伝説の中の話で、自分に関係のあることではないという考えによるものだ。

実際のところ、プログラミングというのはやりがいとか才能によるものではない。プログラミングとは学ぶことができる能力を寄せ集めたものでしかない。そもそもプログラミングとはひとつではない。ここまで、プログラミングというひとつのものがあるかのように話してきたが、プログラミングには実に多くの能力が必要であり、コーディングはその能力のうちのひとつでしかない。設計、コミュニケーション、作文、デバッグも必要だ。そうそう、それからUnicodeについて理解している者が最低一人は必要だ。[聴衆の笑い声]

実に多くの独立した能力があるが、我々は人をスキルセットのうちの最も貧弱なもので評価しがちである。ほう、君はデザイナーとして優秀で、人前で話すこともできれば作文もできる。しかもプロジェクトマネージャーとして優秀である。結構なことだ。しかしリンクリストを理解していないだと? 「おうちに帰んな坊や」とね。他の能力と同じように、プロとしてプログラミングすることもできれば、たまにプログラミングすることもできるし、趣味としてプログラミングすることもできる。パートタイムかフルタイムかどちらでもよい。プログラムを下手に書くこともできるし、うまく書くこともできる。しかし、大半は平均的なプログラマーだ。

「そこそこの実力で十分だ」という考え、平均的な能力でよいという考えが広まれば、新参者がプログラミングに抱く恐れが少なくなる。もし、成功のハードルが、ずば抜けて優れているのではなく、そこそこで十分だとなれば、コミュニティに新たにやってきた人にも、やすやすと飛び越せるだろう。実際、コミュニティにやってきた人に、才能の都市伝説が与えた悪影響は一度限りではない。人々を技術から遠ざける結果となってしまう。

技術業界は、性差別、人種差別、同性愛差別などのあらゆる差別が渦巻いている。これは一つの問題ではないし、原因も一つではないのだが、才能の都市伝説も問題のひとつだ。我々の業界では、才能の都市伝説は、優秀なクソ野郎の都市伝説としても存在する。つまりこうだ。世の中には10倍以上の生産力を発揮するプログラマーがいて、仕事があまりにも素晴らしいので、その挙動が難ありだとしても、周りはなんとか協調してやらねばならないというものだ。現実には、正規分布を考えれば、その手の人間は、それほど例外的に優れているものでもない。しかし、もし仮にそういう10倍プログラマーがいて許容するとしても、そいつ一人を維持するために何人のプログラマーを拒否しなければならないというのか。

[スライド:優秀なクソ野郎というタイトルでLinusがnVidiaに対して中指を突き立てている画像を表示、聴衆は大笑い]

10倍プログラマーはどういう見た目をしているのか。

さて、現実には能力は正規分布するのに、プログラマーは神かザコのどちらかに分類されるという考えには、危険なバイアスが待ち構えている。さて、10倍プログラマーはどのような見た目をしているのかということを考えてもらいたい。

[スライド: 映画ソーシャルネットワークで、Mark Zuckerbergを演じたJesse Eisenbergの写真]

我々はこのような見た目を思い浮かべるであろう。これはMark Zuckerbergだ。若い白人の男だ。なぜならメディアで目にするのはそういう人間だからだ。ネタバレしないでもらいたい[聴衆から笑い声]。だがこれはMark Zuckerbergではない。先ほどから笑っている人もいるように、これはMark Zuckerbergを演じたJesse Eisenbergだ。大手映画会社で、その内容は・・・若い白人の男がIT起業するという話だ。

[スライド: Sutarday Night LiveというアメリカNBCのコメディバラエティ番組のキャストで、Mark Zuckerbergを演じたJesse Eisenbergを茶化して演じたAndy Sambergの画像 ]

これがMark Zuckerbergだ。[聴衆から笑い声]。いや、これはMark Zuckerbergではない。これはAndy Sambergで、Jesse Eisenbergを演じていて、その演じられたJesse EisenbergはMark Zuckerbergを演じている。

[スライド: Mark Zuckerbergの写真]

これが、たぶんMark Zuckerbergだ。

[スライド: 三者の顔]

とにかく、ここで言いたいことは、若い白人の男という典型例は極めて一般的で、3人とも同じ人物を演じているというわけだ。どれが本物だっけ? とにかく、この3人に似通わないような人間は本物のプログラマーには見えないので、本物のプログラマーとはみなされない。自分の知るこの業界の女性のほとんどは、プログラマーだとは思われなかったという話を持っている。このPyCon、今年のいまここで、複数の女が、どの男と来たかとたずねられたと聞いた。ここに来る理由は、配偶者の男がプログラマーだったからというわけだ。もし、男だったならば、そういう質問はされただろうか。

逆に、ステージに上がった自分は、そういう典型例に似ている。そこで、聴衆は自分を本物のプログラマーだと推定する。このような推定は、かなりの数の人間をこの業界から遠ざける。

National Center for Women & Information Technologyによれば、コンピューターサイエンス科の学位を得た女の半数は、雇用にその学位を使っていないとのことだ。40%の女は10年以内にこの業界を去る。男はたったの17%だ。女性の半数以上はキャリアの途中で業界から去るわけだ。

もちろん、性差別だけが原因ではないだろうが、何十年もの経験ある女が、ド素人だとみなされるのは極めて不快だろう。この差別を克服するには大変な努力が必要だ。我々がプログラマーというもの、プログラミング能力というものについて考えなおさなければ、解決は望めない。

ランナーには様々な人がいる。短距離走者、長距離走者、マラソン走者などなど。体格や性別や年齢や人種も様々だ。皆、成功の条件が違うし、その条件にあった成功を収めることができる。この業界にも、そのような考え方が必要だ。

何年も前に、Lynn RootとPyConで話した内容が、この発表の元ネタになっている。Rootはプログラマーで、PyLadiesのサンフランシスコ支社の創始者で、Python Software財団の委員で、このコミュニティに長くいるものだ。PyLadiesは、その当時はまだ新しいもので、その集団の能力や意欲には期待すべきものがあった。その時自分はRootに、「そういう強者の女プログラマーが出てきたのはよいことだ」などと言った。するとRootは、「まあ、そうだけど、本当に成功するためには、大量の平均的な女プログラマーが必要だ」と答えた。

我々の言う才能の都市伝説は、参入のハードルを不可能なほどに上げてしまう。この都市伝説を元に考えれば、今ここに我々がいるという事自体が驚きだ[訳注: ほとんど者はその資格がないはずのため]。この都市伝説は捨て去る必要がある。コミュニティは、「平均は実際とてもよいことだ」という考えを持つ必要がある。さて、私はありきたりのプログラマーで、皆にもそうなってほしいし、普通にやることをこなそうじゃないか。

人間のたいていの能力の評価値をグラフに描くと正規分布するのでベル曲線を描く。ザコと神しかいない、プログラミングには生まれながらの天性の才能が必要だという都市伝説に従えば、正規分布していない。すごくできない奴とすごくできる奴ばかりで中間がほとんどいないという、バイモーダル曲線を描く。とはいえ、前に紹介したふたこぶラクダの論文は、現実の評価結果がバイモーダル曲線だったと報告している。

本の虫: 60%の人間はプログラミングの素質がない

ドワンゴ広告

ドワンゴはベル曲線の良い方の端にいるC++プログラマーを募集しています。

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

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

2015-05-04

constexprで非定数式の状態を保持

Non-constant constant-expressions in C++

なんと、C++のconstexpr関数を呼び出すたびに戻り値を変える方法があるという。つまり、以下のstatic_assertが引っかかるコードだ。

int main ()
{
    constexpr int a = f ();
    constexpr int b = f ();

    static_assert (a != b, "fail");
}

なんと、constexpr関数は状態を保持できる計算能力を備えているというのだ。

fはconstexpr関数である。

読んでみたところ、要するにこうだ。

noexcept演算子はオペランドが定数式かどうかを判別するのに使える。

// exprが定数式であればtrue
constexpr bool b = noexcept( expr ) ;

未定義の関数は定数式ではない。

// 宣言
constexpr int f( int ) ;

void check1( )
{
    noexcept( f( 0 ) ) ; // false
}

// 定義
constexpr int f( int ) { return 0 ; }

void check2( )
{
    noexcept( f(0) ) ; // true
}

friend宣言は関数の定義を書くことができる。

constexpr int f( int ) ;

struct S
{
    friend constexpr int f( int ) { return 0 ; }
} ;

friend宣言で定義した関数はADL経由でしか呼び出せないが、それは問題ではない。friend宣言が現れて初めてconstexpr関数fが定義され、呼び出しが定数式になるということだ。

もし、frined宣言をするクラスをテンプレートにしたらどうなるだろうか。テンプレートが実体化した時だけ、関数fは定義されるということになる。

// 定義されたかどうかの1bitのフラグ
constexpr int flag (int);

// 関数を定義することでフラグ書き込む
template<class Tag>
struct writer {
  friend constexpr int flag (Tag) {
    return 0;
  }
};

// writerの実体化を遅延させるためのラッパー
template<bool B, class Tag = int>
struct dependent_writer : writer<Tag> { };

// 実際の使い方
// 一回目に呼ばれた時点ではまだwriterが実体化しておらず、
// flag<int>は定義されていない
// 二度目以降に定義されるのでtrueとなる
template<
  bool B = noexcept (flag (0)),
  int    =   sizeof (dependent_writer<B>)
>
constexpr int f () {
  return B;
}
int main () {
  constexpr int a = f ();
  constexpr int b = f ();

  static_assert (a != b, "fail");
}

あとはこれを並べれば、何ビットでも状態が保持できる。

ドワンゴ広告

GWは長い。今週は休みだが、有給を申請し忘れたので木金は出社する。

ドワンゴは本物のC++プログラマーを募集しているようですが、休暇中なのでa要素を使ってリンクしません。

<a href="http://info.dwango.co.jp/recruit/">採用情報|株式会社ドワンゴ</a>

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

2015-05-01

婚約者が作って欲しい料理:オムライス

婚約者がオムライスを作って欲しいと言ったので、作ってみた。

オムライスを作るにあたって問題がある。私はケチャップが嫌いだということだ。ケチャップは安直な味がする。スパゲティにケチャップをかけるさもしい異端者になりたくはないものだ。私はケチャップと味覇を封印することを空飛ぶスパゲティモンスター様に誓っている。ラーメン。

色々と調べた結果、ケチャップではなく、ホールトマト缶で作ることに決めた。

作り方

鶏の胸肉を細かく刻んでオリーブオイルと塩とハーブ(コショウ、バジル、オレガノ)を入れたジップロックに入れておく。

タマネギ、人参、ピーマンをできるだけ細かくみじん切りする。

フライパンで肉と野菜を炒める。

ホールトマトを入れて、コンソメと塩とハーブをいれて煮込む。

ご飯を入れて炒める。

卵に牛乳を少しだけいれてよく混ぜる。

フライパンを熱して、多めにバターを入れて、溶き卵を入れる。火は10秒ほどで消す。

卵の片側にトマトチキンライスを置き、真ん中からふたつに折るようにしてくるむ。

フライパンの底側の方が見た目がよいので、皿に移すときにひっくり返す。

こうして、ケチャップを使わないオムライスが完成した。

なお残念なことに、婚約者は冒涜的にもケチャップで上に絵を描いてしまった。

2015-04-30

GCC 5の変更点

GCC 5の変更点で興味深い部分を紹介してみる。

GCC 5 Release Series — Changes, New Features, and Fixes - GNU Project - Free Software Foundation (FSF)

まず、C言語のデフォルトが-std=gnu11になったことだ。C11にGCC拡張を付け加えたものがデフォルトとなる。

__has_includeと__has_attributeのサポート

__has_includeは、ヘッダーファイルがあるかどうかを確認できるプロプロセッサーの定数式の中で使える特殊な式で、特定のヘッダーファイルがあるかどうかを確認するのに使える特殊なマクロのように振る舞う。

// __has_includeが存在するか確認
#ifdef __has_include
// <optional>が存在するかどうか確認
#   if __has_include(<optional>)
#       include <optional>
#   else
#       define NO_OPTIONAL_HEADER 1
#   endif
#endif 

__has_attributeは、属性名に対して同様に働く。

#ifdef __has_attribute
#   if __has_attribute(__noinline__)
#       define ATTRIBUTE [[__noinline__]]
#   else
#       define ATTRIBUTE
#   endif
#endif

この機能は、C++のSD-6: SG10 Feature Test Recommendationsの実装だ。同時に、この提案のマクロも定義されている。

__builtin_add_overflow, __builtin_sub_overflow, __builtin_mul_overflowの追加

オーバーフローしたかどうかを返す。

void plus( unsigned int x, unsigned int y )
{
    unsigned int result ;

    if ( __builtin_add_overflow( x, y, &result ) )
    {
        // オーバーフローした
    }
    else
    {
        // オーバーフローしなかった
    }
}

3つの引数を取り、ひとつ目とふたつ目の引数を加算、減算、乗算したあと、結果をポインターとして取った3つめの引数に書き込む。また、戻り値として、オーバーフローしなかった場合はfalse, オーバーフローした場合はtrueを返す。

変数テンプレートのサポート

template < typename T, typename U >
constexpr bool is_same_v = std::is_same<T, U>::value ;

constexpr bool b = is_same_v<int, int> ; // 

変数テンプレートは、変数宣言をテンプレートにできるC++14の新機能だ。

テンプレートテンプレートパラメーターにおけるtypenameキーワードの許可

template <
    template < typename T >
    typename U >
struct S ;

C++17に入った機能だ。

アグリゲート初期化と非staticデータメンバー初期化子の併用ができるようになった。

struct S { int x ; int y = 2 ; } ;
S s = { 1 } ; s.x == 1, x.y == 2

C++14のconstexprの制限緩和に対応。変数の宣言、変更、if分やループが書けるようになった。これにより、constexpr関数が普通に書けるようになった。

constexpr unsigned int f( unsigned int x )
{
    int temp = 0 ;
    for ( ; x != 0 ; --x )
    {
        ++temp ;
    }

    return temp ;
}

C++14のサイズ付き解放関数に対応。

void operator delete (void *, std::size_t) noexcept;
void operator delete[] (void *, std::size_t) noexcept;

C++の最新の規格準拠のために、C++ライブラリのABIに非互換な変更が加えられた。新しいABIがデフォルトになる。

ドワンゴ広告

今日は有給を取ったので仕事が休みだ。

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

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

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

vim-clang: clangを使ったC++の静的補完Vimプラグイン

justmao945/vim-clang

Vimでclangを使ったコード補完としては、Rip-Rip/clang_completeが有名なだったが、vim-clangというものもあると聞いた。早速使って見る。

" Install vim-clang
NeoBundle 'justmao945/vim-clang'

" set clang options for vim-clang
let g:clang_c_options = '-std=c11'
let g:clang_cpp_options = '-std=c++1z -stdlib=libc++ --pedantic-errors'

なるほど、clang_completeより使い勝手がよい。乗り換えることにした。

Debian GNU/Hurd 2015がリリースされた

Debian GNU/Hurd 2015 released!

GNU/Hurd 2015がリリースされた。

Debian sidからのスナップショットだそうだ。

アーキテクチャはi386のみで、Debianのパッケージの80%以上を含むという。

2015-04-29

Linus Torvalds、「dbusはマジでクソだ」

Gmane Loom

Linus Torvaldsが、kdbusがdbusに比べてスピードアップしたということについてMLで話している。Linusの考えでは、dbusをカーネル側に持って行ったらコンテキストスイッチなどのオーバーヘッドを回避できるのでパフォーマンスアップにつながるという主張は間違っていて、現状のdbusのユーザースペースの処理が無駄にクソすぎるので遅いだけだという。

From: Linus Torvalds <torvalds <at> linux-foundation.org>
Subject: Re: [GIT PULL] kdbus for 4.1-rc1
Newsgroups: gmane.linux.kernel
Date: 2015-04-27 22:00:09 GMT (1 day, 3 hours and 39 minutes ago)

On Mon, Apr 27, 2015 at 2:40 PM, Andy Lutomirski <luto <at> amacapital.net> wrote:

> "USER"を"SESSION"に変えてみては。

動いた。

> ビルド方法は

そんなこと誰がするか。俺はこうした。

gcc client.c -o client $(pkg-config --cflags --libs gtk+-2.0)

これでいけた。

[訳注:先のLinusの発言]
>> とは言え、これはお前がpotatoでテストを動かしてるか、dubsが >> マジでクソかのどちらかだろ。1000バイトのメッセージを2万回往復 >> するのに4秒以上もかかるのはありえん。とはいえ、さっきも言ったように >> 俺には何が起こっているのか確かめることもできん[訳注: Linusはdbusのビルドができなかった] > > いえーい、俺はこのメールをpotatoで書いているんだけど見てるー?

いや、お前は正しいようだ。どうやらpotato説は違ったみたいだな。「dbusはマジでクソだ」説だ。

こいつにカーネルフットプリントなどほぼありゃしねぇ。時間をすべてユーザースペースのオーバーヘッドで浪費してやがる。

マジレスすると、プロファイルをちらっと見ただけでも、「kdbusはパフォーマンス上、重要だ」というのは完全に根拠のない話のようだ。これが問題の上位15だ。

   2.62%  gdbus    libc-2.20.so                [.] _int_malloc
   2.43%  gdbus    libc-2.20.so                [.] free
   2.31%  server   libc-2.20.so                [.] free
   2.12%  gdbus    libc-2.20.so                [.] malloc
   1.77%  gdbus    libglib-2.0.so.0.4200.2     [.] g_utf8_validate
   1.43%  gdbus    libglib-2.0.so.0.4200.2     [.] g_slice_alloc
   1.41%  gdbus    libglib-2.0.so.0.4200.2     [.] g_hash_table_lookup
   1.28%  server   libc-2.20.so                [.] _int_malloc
   1.27%  gdbus    libglib-2.0.so.0.4200.2     [.] g_mutex_lock
   1.22%  gdbus    libglib-2.0.so.0.4200.2     [.] g_variant_unref
   1.16%  server   libc-2.20.so                [.] malloc
   1.14%  gdbus    libglib-2.0.so.0.4200.2     [.] g_bit_lock
   1.07%  gdbus    libglib-2.0.so.0.4200.2     [.] g_slice_free1
   1.05%  gdbus    libglib-2.0.so.0.4200.2     [.] g_bit_unlock
   1.01%  gdbus    libglib-2.0.so.0.4200.2     [.] g_mutex_unlock

上位15にカーネル関数などありゃしねぇ。全部オーバーヘッドだ。これはサーバーサイドのものだが、クライアント側もほぼ同じだ。

たぶんだが、kdbusのスピードアップとやらは、カーネルには一切関係がない。単にdbusサーバーのユーザースペースのクソを使わなくてすむようになったからだ。

要するに、コンテキストスイッチを回避できるからとか宣う奴らはたぶん、単なるドアホだ。コンテキストスイッチじゃねーよ。クソなユーザースペースのコードのせいだ。

Linus

2015-04-28

超会議2015の感想

超会議2015が開催された。

ほぼすべてのドワンゴ社員は、何らかの形で超会議の運営スタッフとなる。筆者はゲームエリアでアナログゲームのインスト要員をしたかったが、どういうわけかまるなげ広場に割り当てられた。

さて、事前の社員説明会が月曜日の朝(ドワンゴ時間)に行われた。説明会のスケジュールが社内のスケジュール管理システムに追加されたのは、おそらく金曜日の昼(ドワンゴ時間)以降である。月曜日は朝過ぎに出社して、ボードゲームなどをしていたので、説明会に参加するのを忘れてしまった。さて、同じ場所に割り当てられた表に顔の出ている他のドワンゴ社員であるま○ら○きも、同じく忘れたらしい。二人で議論した結果、この状況で説明会に参加するのは不可能であるという結論に達した。

さて、説明会に参加した人の話では、まるなげ広場に割り当てられたスタッフは、馬車をやるらしい。

馬車というのは、野尻抱介なる人物が毎年行っている超会議の企画だ。その内容は、荷車に人を載せて、人力で引っ張りながら、会場である幕張メッセのホール内を一周するというものだ。と、概略だけ説明すると、なんともチープな企画のように読めるが、その文脈が問題だ。

なにしろ、超会議は来訪者が相当に多い。去年の超会議では、通路に人があふれ、目的の場所まで進むにも人をかき分けて行かなければならない有り様だった。そこに荷車を通すのだから大変だ。荷車の前後左右に人を配置して、荷車が通れる空間を確保しながら進まなければならない。

さて、超会議の前日にリハーサルで幕張メッセに行ってみると、馬車が用意されていた。予想に反してなかなか興味深い装置が取り付けられている。ブレーキはもちろんのこと、何とパワーステアリングがついているではないか。また、車輪のボールベアリングの性能のおかげか、とても軽い力で引っ張ることができる。荷車には乗り降りするための階段がついているが、今回は強化されているらしい。聞くところによれば、前回の超会議で、力士が乗ろうとしたところ、その重さで階段が壊れたとのことだ。去年の雪辱を晴らすべく、今回の階段は力士が乗っても問題ないようにしたとのことだ。

他には、スピーカーがついていて、効果音を鳴らしたり、マイクが使える。電光掲示板がついていて、文字列を流すことができる。取り外しできる椅子がついている。

さて、リハーサルで練習がてら、他のブースを回ってみた。アニメブースでは、ごちうさブースとゴルゴ13ブースが特に興味深かった。

ごちうさブースでは、空気で膨らますクッションのコースに乗り、水平に張られるロープを体に装着して、「あぁ^~心がぴょんぴょんするんじゃぁ^~」と叫びながら、前方の抱きまくらをホールドするアトラクションが設置されていた。見事抱きまくらをホールドできたものには、何と抱きまくらがそのままもらえるという。

実際に体験してみたが、かなり難易度が高かった。ロープには伸縮性がなく、空気でふくらませる土台の伸縮性のみを使って目的の一まで到達しなければならない。戦略として、勢いよく跳躍する方法と、土台を掴んでにじり寄る方法とがありそうだ。両方試してみたが、どちらもうまくいかない。土台は掴みどころがないが、ボルダリングで握力が鍛えられたためか、ピンチ力でつまむことはできた。しかし体を引っ張れるほどの力が出せない。

あとから成功した者に話を聞くと、姿勢を低くして跳躍すればよいらしい。成功者はアメフト経験があり、かなり大柄な体格をしていたというのも大きい。

ゴルゴ13ブースは、斜めに張られたロープを滑車で滑空しながら標的を赤外線銃で狙い撃つもののようだ。リハーサルで運営スタッフしかいないのにだいぶ待ち時間があった。また、ハーネスを装着するのは、明らかにクライミング経験のない素人スタッフで、下にマットやネットが張られておらず、やや不安を覚えた。また、実際のアトラクション自体は、並んでまで体験するほど面白くも感じられなかった。もちろん、これはリハーサルでありわずかなにわか運営スタッフだけで練習している段階だからそう感じるのであって、本番は違うのかもしれないが、本番環境では体験していないのでわからない。

アナログゲームのブースを見たが、卓の距離があまりにも密接しすぎている気がした。超会議の参加人数から考えれば、周りが人で埋まって悲惨なことになるのではないか。それに、他のブースと距離が近いのも気になる。

さて、リハーサル後は、海浜幕張駅の近くのイオンモールの中にある、PEKIPEKIというクライミングジムに行った。なかなかおもしろいジムだった。日本でここにしかないクライミングマシーンが置いてある。ベルトコンベヤーを縦にしたような機械にガバホールドが大量に取り付けてある。さながらハムスターの回し車のように、延々と登り続ける機械だ。また、壁の角度も稼働中に変更可能なのだ。実際に使ってみたが、これはトップロープで長い課題を登っていく感覚に近いようだ。PEKIPEKIに行くクライマーは、むしろ短くて難しい課題を好むので、このマシンはほとんど使われていないという。それにしてもどこでもクライミングができる面白い機械だ。自宅や会社にあるといいのだが、お値段が5,600万ぐらいするとのことだ。そしてアメリカから輸入しなければならず、またこの手の機械は、定期的に保守点検しなければならないだろうから、保守契約も結ぶ必要があるだろう。そんなに金があれば、普通に壁を設置させたほうがまだ安そうだ。

さて、当日だ。何しろ会場が幕張メッセだ。運営スタッフの中には自腹で近場に宿を取ったものもいるが、私は家から向かった。幸い、今回はとあるシェアハウスに泊まったため、野方から行くよりも一時間ほど通勤時間を節約できた。

さて、東京駅から京葉線で海浜幕張まで向かったが、まだ朝6時だというのに混んでいる。これが皆超会議に向かうのかと思いきや、乗客の半分ほどは、舞浜駅で降りていくではないか。これが、某黒いネズミの土地だ。毎週末ごとにこれなのだろうから、その集客力たるや呆れ返るばかりだ。

一日あたり、ホールを20周以上歩いたので、○さ○っきは足の痛みを訴えていた。しかし、休むと言いながら、女コスプレイヤーが乗るとカメラを抱えて場所の周りを歩きつつ写真を撮っている。

「いや、足は痛いんだけど、写真はとらなきゃなんないし」

見上げた根性だ。

初日の終わりに、乗合馬車の運営スタッフから打ち上げに誘われたが、極めて非常識的なことに、ニコチン中毒者が同席してタバコを常用すると聞いたので、断った。一体何を考えているのだろうか。失礼という言葉には限度というものがある。その場で罵らなかっただけ、私も丸くなったものだ。

さて、一日目の帰りに、新卒の同僚から飲みに行かないかと声をかけられた。行きたいところではあったが、やはりニコチン中毒者が同席してタバコ吸引をするという。これも断った。一体この世の中はどうなっているのだ。

二日目も終わり、やはりPEKIPEKIに行って壁を登ってから帰った。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれなかった。振替休日と有給でしばらく休みだ。

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

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

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

ビッグデータツールチェインのセキュリティはビッグリスク、あるいは、誰もHadoopをスクラッチからビルドする方法を知らない件について

The sad state of sysadmin in the age of containers

コンテナー時代のシステム管理者の惨状

システム管理は惨劇に見舞われている。現状は悲惨だ。

筆者は昔気質のシステム管理者に不満はない。システムの稼働を維持し、アップデートし、アップグレードする方法を知っている者達だ。

この憤りは、コンテナーと構築済みVMと、それらがもたらす、「信頼」や「アップグレード」の欠如による悲惨な惨劇に対するものだ。

例えば、Hadoopを見てみろ。誰もHadoopをスクラッチからビルドする方法を知っているようには見えないぞ。依存性とバージョンとビルドツールが悲惨なほどに絡まりあっている。

この手のイケてるツールの中で、古典的なmakeコマンドでビルドできるものは存在しない。すべてのツールが独自の互換性も移植性もない、「今朝俺が考えた方法」でビルドされている。

そして、誰もスクラッチからコンパイルできる者がいないので、皆、コンパイル済みのバイナリをどっか適当なWebサイトから落としている。たいていは、何らの認証や署名もなしにだ。

NSAとマルウェア作成者にとっては天国だろうよ。もはやセキュリティホールを突く必要などないのだ。単にappとかVMとかDockerのイメージを作成して、悪意あるバイナリを読みこませればいいのだ。

DebianのHadoopのWikiページが典型的な例だ。要するに、Debianの連中は、2010年には、Debian上でHadoopをソースからビルドして便利なパッケージを提供するのを諦めたってわけだ。

Apache Bigtopをビルドするには、まずpuppet3なるものをインストールしなければならない。こいつはインターネット上から不可思議な謎のデータをダウンロードする。そして、sudo puppetしてNSAのバックドアを有効にしようとする(たとえば、こいつは時代遅れのビルド済みJDKをダウンロードしてインストールする。なぜならば、利用者は自力でJavaのインストールができないほどのマヌケだと考えているからだ)。そして、gradleのビルドが200行もの役に立たないバックトレースを吐き出さないかどうか祈るのだ。

私はふざけているのではない。こいつは以下のようなコマンドを実行しようとしやがる。

/bin/bash -c "wget http://www.scala-lang.org/files/archive/scala-2.10.3.deb ; dpkg -x ./scala-2.10.3.deb /"

訳注:暗号化されていない、いくらでも途中の経路で差し替え可能な脆弱なHTTPプロトコルを使いコンパイル済みのバイナリをダウンロードして、単に展開する。

これが、パッケージを正しくインストールすらしていないことに注意されたい。単にルートディレクトリに展開するだけなのだ。このダウンロードは署名を一切確認していないし、SSL証明書すら確認していない。(ソース:bigtop/scala.pp at master · apache/bigtop

たとえ、ビルドが正しく動いたにせよだ、まだMavenが未署名のバイナリコードをインターネット上からダウンロードして、そいつをビルドに使いやがる。

クリーンでモジュール化されたアーキテクチャにしないどころではない。最近はどこでもそびえ立つクソのような相互依存性のデッドロックに陥る。前回筆者が調べたところでは、Hadoop classpathはすでにjarファイル100を超えていた。筆者はHBaseGiraphFlumeCrunchPigHiveMahoutSolrSparkElasticsearch(あるいは似たようなApacheのカオスなもの)を使わずに、今では150個ぐらいにはなっている方に賭けてもよい。

スタックとは、「俺は自分が何やってるか全然わかんねー」という意味の新しい言葉だ。

Maven, ivy, sbtは、システムに未署名のバイナリをインターネットからダウンロードし、自分のコンピューターで実行させるためのツールだ。

そしてコンテナーが、この惨状をさらに悲惨にする。

お前ら、コンテナー内でセキュリティアップデートしたことがあるか?

要するに、Dockerの手法とは、未署名のバイナリをダウンロードして、実行して、かつまたそれが会社のネットワークに何らのバックドアをも仕込まないことを祈るためのツールなのだ。

90年代のWindowsのシェアウェア時代に逆戻りしたようだぞ。

さて、Ask toolbarを含むDockerイメージが最初に公開されるのはいつだろうな。Dockerイメージ経由で広がるインターネットワームが最初に流行るのはいつだろうな。

かつて、Linuxディストリビューションは安全なオペレーティングシステムを提供しようとしてた。署名されたパッケージと、Web上の信頼とでだ。バイナリ一致の再現性のあるビルドを試みているところまである。

だが、全てが急にWindows化されてしまいやがった。セキュリティを気にせず、アプリケーションを次のバージョンにアップグレードすることも考えずに、ダウンロードして実行する「アプリ」なるものが氾濫している。「手間と時間の節約」という名目で。

追記:筆者は、これがDocker以前にも行われていたと指摘を受けた。「Dockerとは新しい'curl | sudo bash'である」と。その通りだ。しかし、もはや「データセンター」で信頼できないソフトウェアをダウンロードして実行するのが主流になってしまった。これはまずいことだ。極めてまずい。かつて、システム管理者はセキュリティホールを防ぐことに力を注いでいた。今では、自らdevopsと称し、ネットワーク上に先を争って進出している。

Debianですら2010年にHadoopのソースからビルドしてパッケージ化をあきらめているとは悲惨だ。

続き

Your big data toolchain is a big security risk!

ビッグデータはセキュリテイにとってビッグリスク

この記事は、先の記事、コンテナー時代のシステム管理者の惨状を受けての追記である。この記事を編集している間に、HackerNews, Reddit, Twitterで取り上げられ、多くのコメントやメールが筆者のもとに届いた。驚くべきことに、多くのコメントは、私の意見を支持するものであった。筆者はもっと多くの、「お前は俺のお気に入りのツールが嫌いだからそういうことを言っているのだ」という文句が寄せられるものだと思っていたのだ。しかし、多くの人が筆者と同じ懸念を抱いているようだ。驚いた。

訳注: The sad state of sysadmin in the age of containers | Hacker News, Your big data toolchain is a big security risk | Hacker News

さて、以下が新しい文句記事だ。ビッグデータを別の側面から切り込んでいる。

最近、みんな「ビッグデータ」とやらをやっているようだ。いや、少なくとも、上司にビッグデータをやっていると見せかけているようだ。大抵の場合、そんなにビッグなデータはない。データ解析を以前より行うようになったというだけの話で、そういうことに「ビッグデータ」の名札を貼り付けて宣伝して、上司から承認をこぎつけようとしている。そんなところだろうか。

「ビッグデータ」とは技術用語ではない。ビジネス用語だ。以前ならば使わなかったデータを解析することによって、ビジネス上の何らかの価値を得ようとすることだ。この視点から考えると、そのようなプロジェクトの多くは、確かに「ビッグデータ」と言える。というのも、「データによる利益の創出」プロジェクトだからだ。容量(Volume)とかその他のVを期待する人たちには不満かもしれないが、まあ、この言葉の使われ方はこんなところだ。

しかし、データ容量と複雑度により新たなオモチャツールを必要とする場合においても、重大な問題が見過ごされているようだ。システムとデータのセキュリティである。

現在使われている、「ビッグ データ テクノロジー スタック」なるものは、セキュア以外の点についてはうまくやっている。まあ独自のHadoop(独自のHadoopディストリビューション)ケルベロス認証で共用型サーバーを売りつけて儲けようとする会社もあるにはあるが。

セキュリティの問題は「スタック」の奥底にまである。これは、その環境にも影響されている。流行のツールを追いかける種類の人間を取り巻く環境だ。多くのプロジェクトでは、システム管理者も務めるLinux開発者というものがもはやいなくなり、かわりに、Apple信者が占めている。この種類の人間は半年後に技術が時代遅れになるような世界に生きているので、プロダクトをそれ以上延命させる必要はないのだ。この種類の人間は開発環境を頻繁に再インストールすることを好む。なぜならば、毎回、何かが変わるからだ。この種類の人間はまた、コンピューターが壊れたら新しい型番を買い直す世界に生きている。(これはビッグデータプロジェクトではうまく行かないことに注意されたい。半年おきにスクラッチから出発するだと・・・)。さて、Macユーザーは長年様々な脅威から影響を受けずにいられたが(そして気にしていなかった。GoToFailとかrootpipe exploitを修正するのに失敗したとか)、Macというオペレーティングシステムはとてもセキュアではない。セキュリティを気にかけないユーザーと組み合わせると、爆発しそうだ。

この種類の開発者は、スタートアップ向けのWebサイトのプロトタイプを短時間で立ち上げたり、毎日新機能をローリングリリースしてユーザーにベータテストさせたりして、ドットコム2.0バブルを維持するのには優れている。また、主要なプロダクトのターゲットとする客層もこの種類のユーザーだ。この種類の人間は半年前のことはさっさと忘れ去り、次の技術プロダクトを心待ちにしていて、発売直後に購入する者達である。

この態度は、スタックという、パッケージがビルドされ、アップグレード(安全なアップグレード)される際に、根本的に問題になる。誰も整合性とか再現性に気を払わないのだ。

このブログにコメントしたある者によると、これらのツールはすべて、「二十歳そこそこのガキによって書かれたようだ」。おそらく正しい。もし、マサカリかついだ経験豊富なシステム管理者が近くに板ならば、ここまでひどくなることはないだろう。どうやってシステムを構築し、10年間保守し、セキュアかつ自動的にデプロイするかという経験がある者は、puppetハックとwgetとunzipと未署名のバイナリコードなど決して信頼しない。

このことを聞きたがる人はあまり多くいないだろうが、

お前のHadoopシステムは多数のみ署名のバイナリコードが至るところで使われている。ダウンロード、アップロード、再ダウンロードを際限なく繰り返した結果だ。その.jarが皆が考えるものと同じである保証はどこにもないのだぞ。

Hadoopは依存性の塊だ。そのほとんどが、セキュリティ目的でまともに調査されたことがない。そもそも、調査されたコードからビルドされたバイナリであるかどうかのチェックができるようすらなっていないのだ。

もしかすると隠し機能が潜んでいて、"yourcompany.com"のようなホスト名のシステムを待っていて、コマンドを監視し、会社の重要なデータを盗むかもしれないぞ。そういう風に組まれたシステムは、どうせファイヤーウォールもこの手の対策のために十分に強固に設定されていないだろう。ソフトウェアはどこかと勝手と通信していても、いわゆるDevOps達には気づきっこないのだ(そもそもこの種類の人間は気にしないのだ。)

最近の「ビッグデータスタック」の精神は、90年代のWindowsシェアウェア時代と同じものだ。インターネットのどこかから適当なバイナリをダウンロードして、セキュリティのためにチェックもせず(Hadoopクラスターにアンチマルウェアかけたって話を聞いたことがあるか?)、どこにでもインストールし散らかすのだ。

なお悪いことに、インストールしたものと、インストール方法とを、管理していない。なぜならば、ツールは毎年変わるからだ。しかし、もし開発者が去ったらどうするのだ。もう二度と実行できる状態に戻せないぞ。

一度実行して忘れ去る(fire and forget)

筆者は、この先5年以内に、多くの会社で数多くのセキュリティ上の問題が起こると予想する。これは産業スパイ天国だ。多くの企業は隠し通すだろうが、一部はマスコミに流出して、この適当なコンポーネントをひっつけはっつけするヒプスター的手法は非難されるだろう。今、巨大な「Hadoopバブル」が膨れ上がっていて、いずれははじけるだろう。

信頼できる状態にするには、ビッグデータツールチャインは以下をマモならければならない。

  • 濃縮

    作業に使うツールが多すぎる。多すぎるツールを管理するツールも多すぎる上に、フロントエンドのフロントエンドすら多すぎる。

  • 軽量化

    あらゆるプロジェクトが、あまりにも大量の他のプロジェクトに依存しているが、その殆どは、極めて些細で特殊な使い方しかされていない。依存性を解消すべきだ。

  • モジュール化

    依存性を解消できないが、個々の機能は小さいのであれば、それはユーザーが必要なときにだけインストールすればよいオプショナルな拡張モジュールとするべきだ。

  • ビルド可能性

    MavenとかlvyとかSBTでバックグラウンドで自動的に何かをダウンロードしなくても、誰でもスクラッチからビルドできるようにするべきだ。オフラインで、クリーンなビルドディレクトリで、ビルドを検証して、ドキュメント化せよ。バグ修正が正しく適用されているかどうかを確かめられるためにも、すべてはどんなシステム管理者でも再現性のある方法でビルドできるようにすべきだ。

  • 配布

    CDNからのバイナリのダウンロードを唯一の配布方法にすべきではない。既存の信頼できるLinuxディストリビューションなどの、別の方法での配布も推奨すべきだ。

  • 互換性の維持

    成功するビッグデータのプロジェクトは、一度だけやって終わりというものではない。いずれ、商業化され、何年も動かす必要が出てくる。環境を新しい、より巨大なクラスターに移行する必要が絶対に生ずる。以降に際してデータを失うことはあってはならない。

  • 署名

    コードには署名が必要だ。議論の余地なし。

  • 検証

    ダウンロードには、ダウンロードされたファイルがアップロードされたものと一致するかという検証が必要だ。

  • 統合

    Linuxシステムがサーバー用途にとても優れているのは、万能のソフトウェアの統合管理があるからだ。システムをアップデートしたならばアップデートされる。アップデートには用途に応じたチャンネルがある。例えば、保守的な"stable/LTS"チャンネル、基本的なQAを受けた最新版が入手できるチャンネル、QAをするための最新版が入手できるチャンネル、システムで使うほぼすべてのソフトウェアはこれによって管理される. カーネルに対するセキュリティフィクスであろうと、Webサーバー、ライブラリ、追加機能、拡張モジュール、スクリプト言語などなど。修正を引っ張ってきてすぐにアップデートする。

さて、読者の中には、HortonworksやClouderaやBigtopなどは、すでにパッケージを提供していると反論するものもいるだろう。それは・・・クソだ。連中が「パッケージ」と称するものは、あらゆる品質の標準を下回るものだ。技術的に、ヴァルトブルクは車である。しかし、現在の安全基準を満たすものではない。

たとえば、連中がサポートしているのはUbuntu 12.04だけである。3年も前の古代のUbuntuが、奴らがサポートしている最新版なのだ。それだけではない。この手のパッケージはだいたい同じだ。Clouderaは管理を「コミュニティ」に丸投げした(要するに、自分たちでやることを諦めたのだ。そして、誰かが尻拭いをしてくれることを期待している)。HortonworksとHDP(あとたぶんPivotal HD)も、同じように丸投げした労力を使っている。連中がやっていることといえば、追加のドキュメントを提供したり、最小の労力でBigtopを使ってパッケージをビルドする方法を教育して利しているだけだ。例えば、bigtopの"spark" .debパッケージは空っぽだ。パッケージに.jarSを入れ忘れているのだ。パッケージングがクソであるという例をこれ以上挙げる必要があるだろうか。bigtopのパッケージはすべて、たったひとつのスクリプトのためだけに、独自のgroovyに依存している。そのたった一つの問題のスクリプトをすでに必須な別の言語で書きなおしたり、ディストリビューションが提供するgroovy対応に書きなおしたりせずに、奴らはbigtop-groovyというパッケージを新たに作ったわけだ。

HortonworksとIBMは「オープン データ プラットフォーム」とやらを発表したのを読んだが、筆者には全く関心がなかった。筆者の知る限り、連中は既存のツールに新しい名前をつけただけのことだ。そういうわけで、ClouderaとMapRがこのブランド改名運動に参加しなかったのは、全然驚きでもない。Hadoopはほぼ似通っているのに、なんでそんな名前が必要なんだ?

さて、なぜこれが問題になるのか。もし、何かが動かなかった時、現時点ではどうしようもなくなるのだ。例えば、Hadoopにバグがあってデータを処理するのに失敗したとする。するともうお手上げだ。それ以上データは処理できない。完全に受け身だ。誰が直すのだ? 巷の「ディストリビューション」と称するものはすべて、同じ、クソみたいな出所から始まっている。この世に問題を把握して修正し、ツールチェインを完全にビルドできる人間は、数十人もいないだろう。明らかに、Hadoop会社はどこもかしこも、Ubuntu 2012.04以降をサポートできていない。これで連中が自分で売っているものを理解していると言えるのだろうか。疑わしいものだ。巷のフリーランスの連中は、皆Hadoopをダウンロードして使う方法は知っている。しかし、果たしてツールチェインの中の業務上深刻なバグを修正して、もう一度実行することができるだろうか。これはLinuxディストリビューションに比べて極めて悲惨だ。Linuxにはビルドデーモンがある。すべてのソフトウェアがコンパイル可能かどうかを検証するサーバーだ。典型的なLinuxのパッケージをスクラッチからビルドするには、大抵、二行のよく知られた有名なコマンドを打つだけですむ。経験ある開発者は誰でもマニュアルを読んで、パッケージを修正できる。別のコンパイラーでディストリビューション全体をコンパイルしようと試みている者達さえいる。これによって将来発生するかもしれない互換性の問題を早期に発見できる。

つまり、連中が販売している「Hadoopディストリビューション」なるものは、奴ら自らコンパイルしたものではないのだ。大半はインターネットのどこからか落としてきた未署名で未暗号化で未検証の.jarファイルだ。奴らはどうやってリビルドすればいいのか分かってないし、誰がコンパイルしたのかも分かってないし、どうやってビルドすればいいのかも分かってない。奴らがわかっているのは、最後のレイヤーだけだ。連中はHadoop .jarをコンパイルする方法を知っている。しかし、それをするには、自動的に大量のバイナリをどこからか自動的に落としてくるときたものだ。ツールは自動的なバイナリのダウンロードを警告しない。連中はそれをHadoopディストリビューションに含めている。

現状では、筆者は業務上のデータをHadoopに食わせることを推奨しない。

おそらく、データをHDFSにコピーして遊ぶのは大丈夫だろう。クラスターと開発機を強固なファイヤーウォールで隔離すればの話だ。だが、すyべてを失って最初からやり直しになる覚悟はしておけ。まだ、実用化には程遠い上に、更に不要なゴミを積み重ねているので、更に実用化は遠い。

ツールチェインの未熟についてもう一つ例をあげよう。

scala-lang.orgのscalaパッケージは、UbuntuとDebianに存在する古いscalaパッケージからクリーンにアップグレードできない(どうも、ディストリビューションは、クソみたいな鶏と卵問題を抱えるビルドプロセスのせいで、新しいScalaをコンパイルするのを諦めたようだ。scalaとsbtをブートストラップするのはかなりやっつけハックになる)。上流のパッケージすら、簡単に修正できない。なぜならば、標準のパッケージツールでビルドされておらず、自動的で摩訶不思議で重要な機能を欠くsbtヘルパー(特に、Replaces:フィールドや、cleaner:にすらアクセスできないからだ。パッケージを適切にコンポーネントに分割するための機能)を使っているからだ。どうやら、UbuntuやDebianのパッケージングの経験が一切ないどこかの馬の骨が書いたらしく、すでに実績あるツールを使わず、自前でやっつけハックを使って自動化を試みる間違ったラッパーになっている。

筆者は、いわゆる「ビッグデータ」プロジェクトなるものの大半は、悲惨な失敗を喫することになるだろうと思う。その原因は管理過剰か管理過少か、データやツールやプロジェクト管理の経験不足だろうが、もちろん、当然のことながら、誰も失敗を認めようとはしないだろう。プロジェクトはすべて、政治的なプロジェクトなのだから、絶対に成功しなければならないのだ。たとえ商業化に結びつかず、一ドルも利益を生み出さなかったとしても。

思うに、機械学習をしている連中というのは、システム管理者でもプログラマーでもないのだ。彼らは目的の計算をするためにコンピューターを使っているだけの利用者である。たしかに、コードは書くものの、プログラマーではないし、自称もしない。

2015-04-25

超会議2015 開幕前

超会議2015がやってきた。

前回は超チューニング祭りというハッカソンに割り当てられたが、今回は馬車に割り当てられた。あの尻Pこと野尻抱介の企画で毎年やっているそうだ。

ちなみにこの馬車だが、パワーステアリングがついている。また、ボールベアリングのおかげで、人が乗っても軽々とひくことができる。スピーカーが搭載されていて騒音を発する。かなり世紀末感のある馬車だ。

また、ペッパーも乗るらしい、

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。超会議は勤務である。

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

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

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

2015-04-20

C++勉強会: 歌舞伎座.tech#8「C++初心者会」の開催案内

歌舞伎座.tech#8「C++初心者会」 - connpass

歌舞伎座タワーにあるドワンゴのセミナールームを使い、C++勉強会として、歌舞伎座.tech#8を開催する。

前回はC++の濃い人間を集めすぎて、単なる発表会になってしまったという半生から、今回は、初心者に積極的に発表する勉強会を目的としていて、外部からの飛び入りの参加者を募集している。

勉強会は、発表してこそ勉強になる。そこで今回は、初心者に積極的に発表する場を提供したいと思った。今回の勉強会で発表の経験を得てもらいたい。

20分枠で話すのは難しいと思うかもしれないが、初心者は発表の時間配分の目安が分からず、発表が伸びがちであることを考慮して、余裕を持った時間設定をした。20分間も話さなければならないというわけではない。

当初、初心者枠とガチ枠を設けて、普段発表をしない初心者に積極的に発表をさせようと目論んだが、あまりにも初心者詐称が多いので、ガチ枠を改めてクソザコ枠とした。C++に僅かにでも関係していれば発表できる。

発表者以外からは、参加費千円を徴収して、ピザとビールを注文し、夕方から雑談できる時間も設ける予定だ。勉強会は多種多様な人が集まって、雑談ができるというところにも価値がある。これは通常、勉強会のあとの懇親会という形で行われるが、今回はその場で無造作にピザとビールを設置してみることにした。

ドワンゴ広告

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

勤務中に勉強会の企画をして、勤務先の施設を使い、勉強会がたぶん勤務扱いになる不思議な仕事をしている。

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

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

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

2015-04-19

散財

作画、檜山大輔、原作、村田真哉のマンガ、魔女に与える鉄槌が、アマゾンのウィッシュリスト経由で送られてきた。ネット上で切り抜きを見て興味深そうだと思って登録しておいたものだ。実際に読んでみたが、残念ながらファンタジー要素が強かった。

さて、今日は久しぶりに何の用事もない休日なので、高円寺までぶらりと歩いていった。業務スーパーで雑穀米の素を買い求めたい。また、久しぶりに、何か散財したいものだ。散財とはいえ、本当に何の訳にも立たないものを買う趣味はない。何か便利なものがあれば買いたいものだ。

さて、高円寺を歩いていると、洋服屋の軒先にジャージが売られているのに気がついた。そういえば、今持っているジャージはだいぶ傷んでいる上に、一枚しかない。もう一枚買ってもよさそうだ。ジャージ上下で1900円+消費税であった。

さて、高円寺の業務スーパーにたどり着いて、目的の雑穀米の素と、その他数日中に食べる食材を買い込んだ。

さて、帰宅しつつブラブラと歩いていると、リカーオフが目に着いた。ここは、酒の未開封の中古品を販売している店だ。立ち寄ってみたが、あいにくと、面白そうな酒は置いていなかった。ただし、赤いショットグラスが200円と手頃な値段で綺麗だったので、購入した。

なおも歩くと、リサイクルショップが見えてきた。覗いてみたところ、ホームベーカリー用の機器が複数置いてあった。一番安いものはなんと1800円。とても興味深かったが、買うのはやめておいた。

その後、古本屋に入った。野中英次の課長バカ一代が全巻セットで売られていたので、購入した。私は野中英次のギャグセンスが好きなのだ。また、F. Scott FitzgeraldのThe Great Gatsbyと、Richard DawkinsのThe God Delusionを購入した。

なおも別の古本屋に入り、手塚修とか水木しげるなどの昔のマンガがたくさん収録されている漫画集があったので、購入した。

久しぶりに結構な金を使った気がする。

XKCD 1513: コード品質

xkcd: Code Quality

「僕は独学だからさ、コードはちょっと汚いかもしれないけど」
「とにかく見せてみなよ。大丈夫だって」

「うわ・・・」
「ガキが家の写真一枚だけを参考にして斧一本で建てた家みたい」

「顧問弁護士がExcel数式しか辞書がないケータイのスペル訂正機能使ってサラダのレシピを書いたらこんな感じかしら」

「IKEAで口論してるカップルの書き起こしを土台にエラー無しでコンパイルが通るまで適当に書き換えたらこうなるのかしら」
「分かったよ。コード記法の参考書読むから」

The Old New Thing: なぜ環境変数にはTMPとTEMPがあるのか。どちらが正しいのか

Why are there both TMP and TEMP environment variables, and which one is right? - The Old New Thing - Site Home - MSDN Blogs

久しぶりにRaymond Chenの記事を翻訳する。

環境変数を覗いてみると、一時ファイルを置いておく場所を指定する目的の変数が2つあることに気がつくだろう。TMPとTEMPだ。なぜ2つもあるのか。もし値が異なる場合、どちらが正しいのか。

話は1973年にさかのぼる。この当時の一般的なマイクロコンピューター用のオペレーティングシステムはCP/Mだった。CP/Mオペレーティングシステムには環境変数がなかった。環境変数の話を始めるにしては不思議な時代だが、実は大事な話なのだ。環境変数が存在しなかったのだから、TMPやTEMPなどあるはずがない。当時、プログラムに一時ファイルを置いておく場所を指定したければ、プログラムごとに独自の方法で行う必要があった。たとえば、実行ファイルの特定の1バイトをパッチして一時オブジェクトを置いておくドライブレターを変更するなど。

(筆者の記憶する限り、当時のほとんどのCP/Mプログラムはパッチによって設定していた。少なくとも、筆者はそのように設定していた。筆者はWordStarマニュアルに、どのバイトをパッチすればどのように動作するのかという記述があったことを覚えている。また、プリンター用に独自の動作を設定したい場合などに、利用者が独自のサブルーチンを書くことができる数十バイトのパッチスペースが設けられていた。筆者は、「プリンターは次の文字を受け取る用意があるか?」関数を書くのに使った。これでバックグラウンドでの印刷がスムーズになった。)

1981年に話は飛ぶ。8086プロセッサーとMS-DOSオペレーティングシステムがやってきた。8086プロセッサーの設計と、MS-DOSおペーレーティングシステムの設計は、CP/Mの影響を受けている。実際、8080プロセッサー用に書かれたCP/Mプログラムは、機械的に8086プロセッサー用のMS-DOSプログラムに変換できることが設計目標だった。もちろん、変換器は自己改変コードとか、命令の途中にジャンプするとか、コードをデータとして扱うなどの変なトリックを使わないことを前提にしているが、健全なコードならば、変換器はプログラムを変換できたのだ。

(8080プロセッサー用に書かれたコードを8086プロセッサー向けに機械変換できるという目標は、8086命令セットに存在するいくつかの不思議な制約を説明できる。たとえば、8080のHとLレジスターは、8086のBHとBLレジスターにマップされている。8080では、計算されたアドレスにアクセスできるレジスターはHLだけであった。これにより、なぜ8086の4つの基本的なレジスター、AX, BX, CX, DXのうち、メモリにアクセスできるのはBXだけなのかが説明できる)

MS-DOSがCP/Mとの互換性以上に追加した機能として、環境変数がある。既存のCP/Mのプログラムは環境変数を使っていなかったので、初期のMS-DOSプログラムも使うことはなかった。なぜならば、最初のMS-DOS用のプログラムというのは、すべてCP/Mから移植されていたからだ。もちろん、TEMPやTMPといった環境変数を設定することはできるが、誰も注意を払うものなどいない。

やがて、プログラムは最初からMS-DOS用に書かれるようになり、環境変数は設定データを格納するために使えることに皆気がついた。混沌とした市場から、2つの環境変数が、一時オブジェクトを格納する場所を記述するのに使われるようになった。TEMPとTMPである。

MS-DOS 2.0はあるプログラムの出力をパイプして、別のプログラムの入力とする機能を追加した。MS-DOSはシングルタスクのオペレーティングシステムのため、この機能は、最初のプログラムの出力を一時ファイルにリダイレクトして、実行が終了するまで走らせ、しかる後に第二のプログラムを実行しつつ、入力は一時ファイルからリダイレクトするという方法でシミュレートされた。さて唐突に、MS-DOSは一時オブジェクトを作成する場所を必要とするようになった。何らかの理由で、MS-DOSの作者はTEMP環境変数を一時ファイルが作成される場所を指定する方法として使うことにした。

ところで、COMMAND.comがTEMPを使うことにしたという決定は、他のプログラムがTEMPとTMPのどちらを使うかという選択には影響しない。作者の気分次第で選ばれるものだ。多くのプログラムは両方を確認するという折衷的な戦略を取った。そして、どちらの環境変数を先に確認するかというのも、やはり作者の気分次第で選ばれた。たとえば、昔のDISKCOPYとEDITプログラムは、TMPの前にTEMPを先に確認した。

Windowsも似たような道をたどったが、何らかの理由で、GetTempFileName関数の作者は、TEMPより先にTMPを見にいった。

結果として、特定のプログラムの一時ファイルに使われるディレクトリは、プログラムの種類次第となった。WindowsプログラムはGetTempFileName関数を使って一時ファイルを作成することが多く、その場合、TMPを優先する結果となった。

環境変数の設定ダイアログをみると、まだ2つの変数、TMPとTEMPが生き残っていて、読者の興味をひきつけている。ギーク版のアディダスVSプーマのようなものだ。

2015-04-17

超会議2015

ニコニコ超会議2015が25, 26日に開催される。

今回のドワンゴの企画ブースにおけるアナログゲームは、

  • おばけキャッチ
  • ワードバスケット
  • ワンナイト人狼
  • ごきぶりポーカー
  • エセ芸術家ニューヨークへ行く
  • 6ニムト
  • 麻雀
  • 花札
  • ポーカー

他にも、囲碁将棋のブースがある。

今回は闘会議と違い、重たいゲームがほとんどない。

ちなみに、超会議2015では、私はゲームエリアには割り当てられていない。ゲームエリアでボドゲのインストをしたかったので希望を出したのだが、なぜか丸投げ広場に割り当てられた。今回の丸投げ広場は、幕張メッセの9-11ホールなので、いつもの場所とは離れている。その分、去年より面積が広く確保できているようだ。

私は何をするのかというと、おそらく馬車の先導役なのではないかと思われる。ドワンゴ社員の中でも変わり者が割り当てられたと見える。私のほかに割り当てられたもう一人のドワンゴ社員である○○らっきも、やはり変わり者だ。

ドワンゴ広告

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

ちなみに、馬車の先導役に割り当てられた私とまさ○○きは、予定されていた社員用の説明会を揃って出席し忘れた。金曜日の夜頃に追加された月曜日の昼からの説明会スケジュールなど把握するのはいかにも無理だ。

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

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

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

2015-04-16

GCC 5.0でのx86におけるPICの改善と、いかに32bit PICコードがクソであるかというお話

New optimizations for X86 in upcoming GCC 5.0: PIC in 32 bit mode. | Intel® Developer Zone

GCC 5.0では、x86(32bit)におけるPIC(Position Independent Code)が改善された。これまではEBXレジスターがGOT(Global Offset Table)のために予約されていたのだが、これを使わなくなった。この結果、貴重なレジスターがひとつ多く使えることになった。

32bit x86におけるPICのダメっぷりは、以下の記事に詳しい。

EWONTFIX - 32-bit x86 Position Independent Code - It's that bad

32-bit x86 Position Independent Codeは実にクソだ。

まず、簡単なCの関数がposition-independent-codeでどうコンパイルされるのかを見てみよう。(つまり、shared library用に-fPICが使われるということだ)

void bar(void);

void foo(void)
{
    bar();
}

さて、GCCはどうコンパイルするのかというと、

foo:
    pushl   %ebx
    subl    $24, %esp
    call    __x86.get_pc_thunk.bx
    addl    $_GLOBAL_OFFSET_TABLE_, %ebx
    movl    32(%esp), %eax
    movl    %eax, (%esp)
    call    bar@PLT
    addl    $24, %esp
    popl    %ebx
    ret
__x86.get_pc_thunk.bx:
    movl    (%esp), %ebx
    ret

ありゃ、なぜこうなるんだ。

もちろん、ここで期待すべきは以下のようなコードだ。

foo:
    jmp bar

PICではないコード生成ならばこうなる。あるいは、barがみえているPICでもこうなる。この理想的なコードは、PICでは得ることができない。なぜならば、呼び出される側(bar)の相対アドレスは、リンク時に固定されていないからだ。別のshared libraryの中かもしれないし、メインプログラムの中かもしれない。

position-independentコードとGOT/PLTのことをご存知の読者は、なぜ以下のようにできないのか疑問に思うかもしれない。

foo:
    jmp bar@PLT

ここでは、symbol@PLTというアセンブリの記法で、アセンブラーに特別な再配置を指定している。これはリンカーがcall命令における相対アドレスを"procedure linkage table"(PLT) thunkしたコードを生成する。このthunkはshared libraryの固定された場所に配置され(つまり、ライブラリがどのアドレスにロードされようと、呼び出し側から固定された相対アドレスとなる)、関数の実際のアドレスをロードしてジャンプする処理をする。 %

これが、問題の発端だ。

実際の関数barにジャンプするために、PLT thunkはグローバルデータにアクセスする必要がある。つまり、ジャンプ先に使う"global offset table"(GOT)へのポインターにアクセスする必要がある。PLT thunkコードは、以下のようなものだ。

bar@PLT:
    jmp *bar@GOT(%ebx)
    push $0
    jmp <PLT slot -1>

ふたつ目と3つめの命令はlazy binding(後述)に関係するもので、ひとつ目がここで問題にするところだ。32-bit x86は現在の命令ポインターからの相対的なメモリーのロード/ストアをする方法が提供されていないため、SysV ABIがその方法を提供している。コードがPICとしてPLT thunkを呼び出すとき、GOTへのポインターを%ebxに隠し引数として渡さなければならない。

さて、なぜそれが4つ前のコードになってしまうのか。

ABI上、呼びだされた側で破壊していい(call-clobbered)レジスターは%eax, %ecx, %edxだけなのだ。隠しGOT引数用のレジスターである%ebxは呼びだされた側で破壊できない(call-saved)。つまり、fooが%ebxを改変した場合、保存してリストアさせる責任を負う。そのため、極めて悲惨な非効率的状況に陥る。

  1. fooは%ebxをbar@PLTへの引数としてロードしなければならない
  2. fooは呼び出し元に戻る前に、%ebxがcall-savedなレジスターのため、%ebxをスタックに保存して復帰させなければならない。
  3. barの呼び出しは末尾呼び出しにならない。なぜならば、fooはbarから戻った後に処理を行わなければならないから。%ebxをリストアさせなければならない

そのため、例2のようなそびえ立つものとなる。

一体どうやったらこの問題を解決できるのか。

まず挙げられる解決法は、隠し引数を渡すレジスターを変えることだ。しかし、これはコンパイラーとリンカーのABI規約を変えずに行えないので、選択肢からは外れる。

bar@PLTへの隠し引数の要件を無くすというのはどうだろうか。これも、ABI変更を伴うが、非互換ではない。とはいえ、現実的ではない。PLT thunkがレジスターを破壊せずにGOTアドレスをロードするのは簡単ではなく、破壊してもいいたった3つのレジスターは、すべてデフォルトではないがサポートしなければならない"regparam"呼び出し規約のために使われている。%ebxを使うという選択は意図的なものだ。引数私に使われている可能性のあるレジスターを壊すのを避けるためだ。

では、どんな手が残されているのか。

PLT thunkをなくしてしまうというのはどうだろうか。例4のようなコードを生成することを目指すのではなく、以下のようなコードを目指すのはどうか。

foo:
    call    __x86.get_pc_thunk.cx
    jmp *bar@GOT+_GLOBAL_OFFSET_TABLE_(%ecx)
__x86.get_pc_thunk.cx:
    movl    (%esp), %ecx
    ret

これはfooの肥大化のかなりを削れるし、PLT thunkのための追加のキャッシュラインの必要な命令もひとつ減らせる。なかなかよさそうだ。

なんで最初からこうなっていなかったのか。

残念ながら、こうなっていなかったのには理由がある。その理由はよろしくない。

PLTが存在するそもそもの理由は、メインプログラムが固定アドレスにロードされて(PIE以前の時代を考えてみよ)、position-independent codeを使わずにshared libraryの関数を呼び出すためのものだ。メインプログラムのPLTは、%ebxに隠しGOT引数を必要としない種類のものだ。なぜならば、固定アドレスであるため、自分のGOTには絶対アドレスを使えるのだ。ただし、メインプログラムはPLTを必要とする。なぜならば、レガシー(非PIC)なオブジェクトファイル、呼び出す関数が実行時に任意の場所にロードできることを知らないコードに対応するためのものだ。(そのようなオブジェクトファイルから、PLT thunkを生成して適切に結びつけられた、ダイナミックリンクされたプログラムを生成するのは、リンカーの仕事だ)

position-independent codeはPLTを必要としない。例6で例示したように、GOT自信から目的のアドレスをロードして、間接的なcall/jumpを行える。position-independentna tなshared libraryコードにおけるPLTの利用は、PLTの別の利点を活用するためのものだ。すなわちlazy bindingだ。

lazy bindingの基本

lazy bindingが使われるとき、ダイナミックリンカーは呼び出される側のシンボル名の検索をロード時まで遅延させる。名前検索は関数が最初に呼ばれる時まで遅延される。理論上、これは実行時のオーバーヘッドとして、やや複雑な機構と最初に関数を呼び出した時の遅延を犠牲に、起動時間を節約するものである。

少なくとも、数十年前にこの機構が設計された時の理屈はそうであった。

現在、lazy bindingはセキュリティの足かせとなっているし、パフォーマンス乗の利点というのも疑わしくなっている。最大の問題は、lazy bindingが機能するためには、GOTは実行時に書き込み可能でなければならないということだ。これは任意のコードの実行への攻撃ベクターとなってしまっている。近代的な強固なシステムはrelroを使う。これはGOTの一部ないしは全部を、ロード後にリードオンリーにする。しかし、lazy bindingするPLTのGOTスロットは、この防衛から外さねばならない。relroリンク機能の恩恵を受けるには、lazy bindingは無効にしなければならない。それには以下のようなリンクオプションを使う。

-Wl,-z,relro -Wl,-z,now

つまり、lazy bindingというのは、deprecated扱いされていると考えて差し支えない。

そういうわけで、musl libcはlazy bindingをそういう理由と他の理由で、サポートしていない。

lazy bindingとPLT

例5のPLT thunkの2行目と3行目を見よ。どのように動作しているかというと、bar@GOT(%ebx)は当初(lazy binding前)2行目へのポインターがダイナミックリンカーにより設定されている。2行目で定数0がpushされているのは、PLT/GOTスロット番号だ。jumpする先のコードはthunkで、スタックに引数としてpushされたスロット番号を使い、lazy bindingを解決するためのコードを呼び出す。

例6で、同じことを実現するのは簡単ではない。同等のことをしようとすれば、呼び出し側を遅くさせ、呼び出すたびにコード重複が必要だ。

つまり、効率的なx86 PIC関数呼び出しができないのは、大昔の間違った機能をサポートするためなのだ。

幸い、修正可能だ。

もし、lazy bindingを諦めることができればの話だ。

Alexander MonakovはGCCの簡単なパッチを用意した。これはPLT経由のPIC呼び出しを無効にするものだ。ひょっとしたら上流に取り入れられるかもしれない。

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 3263656..cd5f246 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -5451,7 +5451,8 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
   if (!TARGET_MACHO
       && !TARGET_64BIT
       && flag_pic
-      && (!decl || !targetm.binds_local_p (decl)))
+      && flag_plt
+      && (decl && !targetm.binds_local_p (decl)))
     return false;

   /* If we need to align the outgoing stack, then sibcalling would
@@ -25577,15 +25578,23 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
       /* Static functions and indirect calls don't need the pic register.  */
       if (flag_pic
          && (!TARGET_64BIT
+             || !flag_plt
              || (ix86_cmodel == CM_LARGE_PIC
                  && DEFAULT_ABI != MS_ABI))
          && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
          && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0)))
        {
-         use_reg (&use, gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM));
-         if (ix86_use_pseudo_pic_reg ())
-           emit_move_insn (gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM),
-                           pic_offset_table_rtx);
+         if (flag_plt)
+           {
+             use_reg (&use, gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM));
+             if (ix86_use_pseudo_pic_reg ())
+               emit_move_insn (gen_rtx_REG (Pmode,
+                                            REAL_PIC_OFFSET_TABLE_REGNUM),
+                               pic_offset_table_rtx);
+           }
+         else
+           fnaddr = gen_rtx_MEM (QImode,
+                                 legitimize_pic_address (XEXP (fnaddr, 0), 0));
        }
     }

diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 301430c..aacc668 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -572,6 +572,10 @@ mprefer-avx128
 Target Report Mask(PREFER_AVX128) SAVE
 Use 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer.

+mplt
+Target Report Var(flag_plt) Init(0)
+Use PLT for PIC calls (-mno-plt: load the address from GOT at call site)
+
 ;; ISA support

 m32

筆者は手元のGCC 4.7.3ツリーに似たような変更を加えて試してみたところ、以下のような出力を得られた。

foo:
    call    __x86.get_pc_thunk.cx
    addl    $_GLOBAL_OFFSET_TABLE_, %ecx
    movl    bar@GOT(%ecx), %eax
    jmp *%eax
__x86.get_pc_thunk.cx:
    movl    (%esp), %ecx
    ret

理想的な関数からはまだ遠いが、今の出力よりははるかにマシだ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。C++標準化委員会の文書集が公開されたが、これもすてがたかったのだ。

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

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

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

2015-04-14

Ted Ts'oがEXT4で暗号化を実装

Encryption Support For EXT4 - Phoronix

GoogleのTed Ts'oが、EXT4に直接暗号化機能を実装したそうだ。

Linuxカーネルにおけるストレージの暗号化にはいくつか方法がある。ファイルシステム自体が暗号化機能を備えているというのはわかりやすいが、その他にも方法がある。

eCryptfsはEXT4のような通常のファイルシステムの上に、さらに暗号化されたファイルシステムのレイヤーをかぶせる方法だ。eCryptfsは、、ホームディレクトリ以下を暗号化するのによく使われている。

dm-cryptは、ブロックデバイスレベルの暗号化で、これは通常のファイルシステムの下で暗号化を行うレイヤーだ。

今回は、ファイルシステム自体に暗号化機能をもたせたわけだが、[PATCH 00/22] ext4 encryption patchesによると、Androidで使うことが主な目的らしい。

EXT4はどこまで魔改造する気だろうか。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。そろそろC++標準化委員会の次の論文集が出てもよさそうな時期なのだが。

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

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

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

2015-04-13

餃子

週末は餃子パーティをした。ひき肉を800g使って、餃子を100個以上作った。餃子の包み方が嫌でも上達した。

ところで最近、コンソメスープに凝っている。圧力鍋にコンソメを溶かしたお湯を沸かしブロッコリーをゆで、ベーコン、タマネギ、キャベツを炒めて投下、適当に煮るだけで素晴らしいスープになる。

今の悩みは、ブロッコリーが高いことだ。なぜブロッコリーはあんなにも高いのだろうか。タマネギや人参に比べて需要が低いから供給量も少なく高いのだろうか。しかし、たいていの青果店にはブロッコリーが陳列してある以上、供給量や需要の問題ではないのではないか。あるいは、ブロッコリーは外国産を輸入販売できないほど足が速いので高いのだろうか。

江添ボドゲ会@5月

江添ボドゲ会@5月 - connpass

上記告知通り、5月10日の日曜日に、妖怪ハウスでボドゲ会を行う。

今回もステーキ。手巻き寿司も作るかもしれない。

2015-04-09

libclangを使ったC++のセマンティックハイライトのVimプラグイン、color_coded

https://github.com/jeaye/color_coded

Color_Coded: Bringing LibClang Highlighting To Vim - Phoronix

color_codedは、libclangを利用して、C/C++/Objective-Cの文法を考慮したセマンティックハイライトをしてくれる。単なるキーワードや正規表現指定によるハイライト以上に優れたハイライトが得られる。

なお、Ubuntu 14.10のvimで試そうとしたところ、Vimのバージョンが古いとして動かなかった。

ドワンゴ広告

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

ドワンゴ社内にはEmacsユーザーよりもVimユーザーの方が多いと思われる。

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

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

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