2018-12-08

経済学上最適な行動は時として奇妙に見えるという話

極めて興味深い、経済学上合理的で最適な戦略は、時として奇妙に見える。例えば以下の例だ。

Amazonから注文もしていない商品が届き続けた件 | ハーバービジネスオンライン

まとめると以下のようになる。

アマゾンから注文していない雑多な商品が届くようになった。クレジットカードの不正利用ではないし、アマゾンの購入履歴にも存在しない。泥酔したり精神に不調をきたして記憶を失う習慣もない。そもそも自分から購入したいと思うものではない。一度だけ送り状が入っていたので、ギフトであることが判明した。しかしそのようなギフトを送る知人に心当たりはない。アマゾンに問い合わせたところ、ギフトであろうとの回答が来た。ギフトの送り主の個人情報は開示できないとのことであった。

商品の中に、以前マーケットプレイスで注文した商品によく似た商品が混ざっていることに気がついた。もしかしたら、以前利用したマーケットプレイスの出品者が送りつけているのかも知れない。しかしそれは、自分の出品を自分で購入していることになる。自分から自分にカネを動かしているのだから損はないかもしれないが、アマゾンの手数料と諸経費そして発送料の分は損をしている。なぜなのか。

ここでいくつか仮説が述べられている。見かけ上の売上を上げることによりアマゾンのランキング工作をしたいという可能性もあるが、一番合理的で納得の行く説は、商品の廃棄だ。

アマゾンのマーケットプレイスではアマゾンの倉庫に商品を保管できる。これには定期的な保管料がかかる。そのため、しばらく売れない商品は破棄し、これ以上保管料による損失がかからないようにする。これは合理的だ。保管を維持して商品本体の売上よりも保管料が高くなるのであれば、商品自体を破棄したほうがよい。

商品の破棄方法としては、自分自身へ返送して自分で廃棄する方法と、所有権の放棄してアマゾンに廃棄してもらう方法がある。しかしこれはどちらもコストがかかる。

自分自身へ返送する場合は、アマゾンに支払う返送料と宅配業者の送料がかかるほか、受け取りにコストがかかり、さらに何らかの方法で廃棄しなければならない。

所有権を放棄してアマゾンに廃棄してもらう方法もあるのだが、こちらも料金がかかる。

自分で自分の出品を購入して誰かにギフトとして送りつける場合、自分で自分に代金を支払うので、代金の大部分は自分に帰ってくる。かかるコストはアマゾンの手数料とギフトの送り先への送料だが、これが廃棄のコストを下回る場合、廃棄するよりギフトとして誰かに送りつけたほうが結果的に安くなる。

ではどこにギフトとして送りつけるかだが、すでに自分から商品を購入した人の住所に送りつけるのがよい。

これは違法だろうか。ギフトを送りつけられたことによって損害を被った場合は民事訴訟を起こすことができるだろうが、大抵の商品は損害額が小さすぎるために訴訟をする価値がない。まずアマゾンに個人情報の開示申立の裁判をし、その後にギフトの送り主と裁判をすることになるが、これだけで100万円単位の訴訟費用がかかるし、総額2万円ぐらいのゴミ箱やらシャツやらプロジェクターといった雑多で安価な商品を送りつけられたことによる損害に対する補償を求めるにはあまりにもコストがかかりすぎるので、訴えられる心配はまずない。実際、リンク先の記事の筆者も認める通り、このギフトによる実害は発生していない。

経済学とは不思議だ。インセンティブに従い、極めて合理的で最適な戦略を取った結果が、ハタから見ると奇妙に思える。

2018-12-03

三十路を超えたので体について考える

三十路を超えてからというもの、自分の体の無視できぬ変化について意識せずにはいられなくなった。

私は明らかに10年前より顔が変わった。10年前も、5年前より顔が変わったと思っていたのだが、その頃に思っていたよりもさらに顔が変わっている。

嬉しい変化としてはヒゲが伸びるようになったことがある。20代の頃、私は口ひげは数cmほど伸びるものの、あごひげはまばらにしか生えない体質だった。ヒゲを伸ばしたとは思っていたものの、あごひげは伸ばしてもみっともないので剃っていた。今、あごひげも少し伸びるようになってきた。それも、下唇の下は中心から一本の線を描くように伸び、両側は伸びないという生え方をしているので、気に入っている。

一番の懸念事項としては、体重が増え続けているということだ。これはよくわからない。というのも、それほど食べてはいないはずなのだ。特に最近は1日一食程度にまで食べる量を減らしているのだが、体重は減らないどころか増えていく。私は酒を飲む習慣はないし、したがって酒のつまみも食べない。ラーメンも食べない。野菜は好きな方だ。なぜこんなにも体重が増えていくのだろうか。

運動はしている。毎週ボルダリングをしているし、ジョギングもしている。ボルダリングによって筋肉量は数年前より相当上がっている実感があるのだが、体重も増えているために最近はボルダリングの腕も落ちている。ジョギングも10kmぐらい走れるのだが、特に体重の減少にはつながっているように思えない。

視力も落ちてきている。普段はメガネをしているので気が付きにくいのだが、数年に一度メガネを買い換える際に、常に度を一段階上げる必要があることに気がつくのだ。

とはいえ、まだ私は恵まれている方だろう。自覚できる肉体の変化で健康的に悪いことといえば、体重の増加と視力の低下ぐらいなのだから。今のところ、大した病気にはかかっていないし、精神的に不安定でもなく、認知能力の低下もない。

認知能力の低下というのは最近特に意識する問題だ。というのも、私の父親は明らかに認知能力が低下しているからだ。今の父親にとって、世上のあらゆる問題は中国人が原因だということになっている。風が吹けば桶屋が儲かる程度の理屈もなく、あらゆる問題は中国人のせいであるらしい。私の知っているかつての父親はそういう人間ではなかった。なので、上京して以来数年ぶりに帰郷して目の当たりにした父親の激変ぶりに戸惑っている。

父親の年齢はちょうど還暦を迎えた60歳。まだ60歳でしかないのだ。

思えば思い当たる節はある。父親は50歳ぐらいの頃、急に勤め先を退職したいと言い出した。母親は定年まで勤め上げれば給料や退職金がだいぶ違ってくるのでもったいないと言ったが、父親はもう能力的に働けないと主張していた。

[削除済み]

父親を見ると私の将来について一抹の不安を覚える。私も知的能力が必要とされる仕事をしているが、果たしていつまで知的能力は維持できるのだろうか。現在、私の知的能力に自覚できる低下はない。それどころか、英語の読解力は過去最高に上がっている。父親が50歳を超えて自身の知的能力の低下に気がついたのだとしたら、私には20年弱の時間しか残されていないことになる。

2018-11-25

Vimconf 2018のスタッフをしてきた

VimconfとはテキストエディターVimに関する発表をするカンファレンスだ。国際カンファレンスを意識し、発表の多くは英語で行われている。今年は他ならぬVimの作者であるBram Moolenaar本人を招待している。

去年のVimconf 2017には、雇用主のドワンゴがスポンサーをしていたので、スポンサーチケットで参加をした。

今年のVimconf 2018もドワンゴはスポンサーをしていたが、去年は私がスポンサーチケットを使ったので遠慮をして今年は別の同僚に譲った。自腹で行こうかと思ったが、チケット販売サイトはクレジットカードからの入金しか受け付けなかったので、購入を断念した。

残念、今年は参加できないか、と思っていたところ、運営スタッフから人手不足で当日のスタッフが足りないので来てくれと言われ、急遽スタッフとして受付のチケットもぎりをすることになったので、結果的に今年も参加することになった。他の運営スタッフとは違い、当日の、それも開場後前後の1,2時間程度しかスタッフらしいことはしなかったのだが、立派なスタッフ面をいて開場直後以外の発表はバックヤードから聞いていた。

Vimconfは国際カンファレンスを意識して基本的に英語で司会、発表が行われるのだが、無線イヤホン経由の英語と日本語の通訳がついている。去年のVimconf 2017ではプロの通訳ではない運営スタッフの一人が通訳を担当した。プロではないので、通訳内容はだいぶアレでソレであったと聞いている。

今回はなんとプロの通訳を手配したという。私は英語のリスニングができるので通訳の品質を確かめてくれと言われてイヤホンを聞いてみたのだが、さすがはプロだ。流暢な英語が流れてくる。英語は自然で発表内容とあっているように思われるが、本当に発表者の発言と一致しているかという検証は難しかった。というのも発表者の日本語と通訳の英語を同時に聞くのは困難だからだ。驚異的なことに、発表者の発話する日本語に対応して流れる英語の遅延が少ない。あらかじめ発表内容の台本を渡されてそれを翻訳して読み上げているのだろうかと思うぐらい遅延が少ない。さすがはプロの通訳だ。

発表はmattnさんから始まった。VimからTCP/IPのlistenできるようにするという機能の実装で、VimがNUL文字を扱えるようにBLOB型を追加するという内容だった。

いよいよBram Moolenaar本人が発表する番になった。Bram Moolenaarはあまり表に出てこない人だ。Vimconf 2018以前にBram Moolenaarに直接対面したことのある日本人は数えるほどしかいないはずだ。インターネット上でBram Moolenaarを検索すると決まって出てくる、あの有名な酒瓶を掲げたBram画像は11年前の2007年のもので、現在の本人は11年分の齢を重ねた姿になっていた。

Bram Moolenaarの発表はVimの歴史を軽く紹介したほかは、Vimが現在取り組んでいる新機能の現状についての説明があった。Vimscriptが遅いのでパース済みの中間表現を保持することで高速化するアイディアや、Vimscriptのスレッドによる並列読み込みといったアイディアが説明された。そしてプラグインの話になった。最初のプラグイン機構は単一のディレクトリにvimscriptを放り込むものであったが、最近はプラグインごとに独立したディレクトリを持つことができるようになり、だいぶ楽になった。プラグインの例として、なんとあのShougoさんのプラグインが言及され、開場からは驚きの声が上がっていた。思えば遠くまで来たものだ。その後、プラグイン間で共通のライブラリを使いたいという至極当然の欲求から、プラグインの依存関係を記述して解決するパッケージマネージャー機能のアイディアが説明された。

質疑応答では、Bram MoolenaarはLSP(Language Server Protocol)についてあまり興味がなさそうであった。しかしLSPをVimでサポートするのはなかなかよさそうなアイディアに思える。

昼になり弁当が配られた。国際会議なので様々な思想に配慮した結果、すき焼き弁当とベジタブル弁当が用意されていた。私はすき焼き弁当を取りそこねたので、余っていたベジタブル弁当を食べた。ベジタブル弁当の中身はとても品数が多く豪華であった。酒のつまみによさそうな中身だった。

昼休みの余興として、ホワイトボードに模造紙を貼って、Vimで書く言語についてのアンケートが行われた。

ありえないことにCとC++が"C/C++"とひとくくりにされていたので、分割した。

その他の欄には様々な言語が学んだ。まずMarkdownだ。当然ながらVimscriptもVimで書く。Markdownもそうだ。VimでVimを書く人もいた。これはVimでVimの開発をしているということだ。要するにC言語を書くことでもあるのだが。

Python 2を書いてみたところ、シールがいくつか貼られていた。まだPython 2を書かなければならないかわいそうな人たちも参加していたらしい。

ネタで書いたEmacs Lispにもシールが貼られていた。これはネタではなく理由のあることで、環境構築をする際にまずデフォルトで入っているVimでEmacsの設定ファイルを記述し、その後にEmacsをインストールするので、VimでEmacs Lispを実際に書くのだという。

更にわからないことに、Jupyter Notebookが追加されてた。Jupyter Notebookというのはプログラマーではなく科学者向けソフトウェアだ。科学者は頭のいい人間であり、研究に必要なコードは当然書ける。しかし彼らは本物のプログラマーではないので、プログラマーらしいコンピューターの使い方やプログラミング言語の環境構築は苦手だ。Jupyter Notebookはそういう手間を省き、科学者でも様々なプログラミング言語を使えるようにした環境だ。Jupyter Notebookというソフトウェア一つ入れれば、後は何も考えなくてもいい。そのJupyter NotebookをVimから使うとはどういうことか。聞けばVimからJupyter Notebookを操作しているのだという。それができる人間なら、Jupyter Notebookをわざわざ使わずともプログラミング言語の環境構築は簡単にできるはずなのだが、世の中はわからない。

午後の発表になった。Vimの従来のプラグインの機能は、実は今のVim標準の機能で代替可能であることを示す発表があった。Ctrl-Xから始まる各種保管の説明があったが、私は使いこなしていない。

今回の複数の発表によれば、Vimは就職活動に役立つらしい。

vim-historyレポジトリも興味深い。これは1991年にリリースされて27年の歴史を持つVimの更新履歴を単一のgitレポジトリで再現したものだ。Vimは当初、当時の慣習としてtarballで配布され、その後CVSで管理されるようになり、何度かのレポジトリの断絶を経て、今はgitで管理されている。レポジトリの全歴史をgitレポジトリで表現することにより、gitによる様々な操作が可能になる。例えば特定のコントリビューターは何件コミットしているのか。あるコントリビューターの最初のコミットはどれか。などといった、様々な変更の歴史がgitで検索できるようになる。

似たような試みはUNIXにもある。UNIXの歴史をgitレポジトリで再現するプロジェクトがある。

そして、:termdebug機能が言及された。この後の発表はあまり覚えていない。:termdebug機能のあまりの素晴らしさに発表を聞くのがおろそかになってしまったからだ。

:termdebugはVimにデフォルトで同梱されているVimによるGDBのフロントエンドを提供するプラグインだ。使い方は、":packadd termdebug"して、":Termdebug プログラム名"するだけだ。VimはGDBを起動してGDBと通信する。そして、GDBとやり取りするウインドウ、デバッグされるプログラムの標準入出力のウインドウが追加される。現在のウインドウはソースコード表示に使われる。

素晴らしいことに、マウスサポートを有効にしている場合、StepやNextといったボタンが現れ、クリックすら可能になる。そしてGDBに該当のコマンドを送る。

これがすべてVimの中で動くということは、リモートサーバーにsshして動かすことすら可能になるということだ。

しかし、使うとすぐにバグが見つかった。ブレイクポイントはソースコード上で表示されるのだが、break/deleteを繰り返すと存在しないブレイクポイントの表示が消えなくなるのだ。この問題は原因を特定したのだが、最新版のVimでは治っていることが判明した。

もう一つの問題は、Bram MoolenaarがC言語しか想定していなかったための機能不全だ。C++では複数の関数が同じ名前を持つことができる。

void f() {}
void f(int) { }
void f(long) { }

この状態で"break f"とすると、関数fすべてにブレイクポイントが設定される。termdebugはこれに対応していない。

この場合のGDBのブレイクポイント番号の付与は変わっている。"break f"とした場合、1.1(f()), 1.2(f(int)), 1.3(f(long))のようにメジャーブレイクポイント番号と関数ごとにマイナーブレイクポイント番号が付与される。結果としてブレイクポイントは3つできるが、それはすべてブレイクポイント番号1として扱われる。enableコマンドなどは"enable 1.1"のように指定できるが、deleteは指定できない。"delete 1"とするとブレイクポイント番号1に属するすべてのブレイクポイントが削除される。

termdebugはブレイクポイント番号をキーにしてmapでブレイクポイントを管理しているのだが、ひとつのbreakコマンドで複数のブレイクポイントが設定されることを想定していないし、ましてやその複数のブレイクポイントが一つのメジャーブレイクポイント番号に属することを想定していない。そもそもマイナーブレイクポイント番号があることすら想定していない。ブレイクポイント番号をキーにしてmapでブレイクポイントを管理していて、削除時にブレイクポイント番号をキーに検索して削除している。

現在のコードを大幅に変えずに関数のオーバーロードのブレイクポイント表示に対応するのは難しい。HandleNewBreakpointで"1.1", "1.2", "1.3"のようなキーで複数のブレイクポイント番号をキーにしてs:breakpointsに挿入し、HandleBreakpointDeleteで"1.1", "1.2", ...のようにマイナー番号の削除を見つからなくなるまで試みる実装が、とりあえず使えるだろうとは思う。

termdebugは素晴らしい。そして、Termdebugとそのバグのおかげで、Bram Boolenaarと会話ができたという思わぬ副産物もあった。VimconfにBram Moolenaarが来ると聞いて会話をしたいとは思っていたものの、特に話すべき内容は思いつかなかった。なるほど、私はVimを毎日使っているが、Vimの開発に参加しているわけはない。せいぜい挨拶をするのが関の山だと思っていたのだが、Termdebugの存在で会話内容ができてしまった。英語によるスピーキングは普段全くしていないので英語が口から一切出てこないのだが、不思議なことにtermdebugがC++をサポートしていないことについてとその原因についてであれば、英語で説明をすることができた。言語の利用には慣れた文脈が必要のようだ。

termdebugをなぜ今まで知らなかったのだろうと疑問に思っていたが、どうやら今年の7月にVimに入ったばかりのだいぶ新しい機能であるようだ。道理で知らないわけだ。termdebugの存在を知ることができたという理由だけでvimconf 2018のスタッフをしたかいがあった。

その後、もう一枚ホワイトボードが追加され、今度はVimに欲しい新機能のアンケートが行われた。人気の機能はVimscriptの高速化であった。私は、VimがtmuxやScreenのように、シェルからのdisownによるログアウト後の実行継続と、detach/attach機能がほしい。この機能があれば、tmuxはいらなくなる。Vimがtmuxの代わりを務めることができるのだ。リモートサーバーにsshしてvimでテキストを編集し、その編集中のvimの実行を継続したままログアウトし、後にログインして前回の続きから作業を再開したい時、今はtmuxの中でvimを実行しなければならない。これがvimだけで済むようになるのだ。

新機能では端末でエスケープシーケンスによるグラフィック表示をするSixelも人気があった。これは解せないことだ。Sixelはテキスト処理だけで完結するが、グラフィックの表現としては非効率的すぎる。効率を重視するならば、ビットマップデータを直接流し込むようなAPIがほしい。もちろんこれはNULも扱えるようにBLOB型が必要になるだろう。

Vimconf 2018は素晴らしかった。来年も開催されるだろうか。楽しみだ。

ワンナイト人狼とボードゲームの知的財産権について

なぜか一部のボードゲーム作者は、事実の羅列や純粋な思想、新規性も進歩性もない発明であるゲームルールに排他的な独占権を欲しがる。そのような権利が認められた場合、我々は日常会話すら困難になるのだが、そのことに思いが至ることはないようだ。

ワンナイト人狼と同等のルールがオリジナルを考案した我々の許諾なく販売されたと嘆いている。

「太刀打ち」という物騒な言葉まで用いて攻撃的な対立姿勢を明らかにしている。

しかし、本人も認めるように、事実の羅列や抽象的な思想にすぎないゲームルールは著作権では保護されない。特許として認められるほどの新規性と進歩性も満たしていない。

ライセンスというのは排他的な独占権があってはじめて成立するものだ。そのような権利を持たずして一体何を求めているのか。

唯一なにかできるものがあれば、「ワンナイトルール」という商標の有効性についてだけだ。

望む内容に注意せよ。期待通りの結果をもたらさないことがある。

2018-11-18

自転車を買おうか悩んでいる

私は職場から直線距離4kmの場所に住んでいるのだが、電車による通勤は40分ほどかかる。理由は自宅が駅から遠いことと、乗り換えが必要なためだ。

自宅から職場まで歩くと50分かかる。道なりに5kmほど歩くので、6km/hで歩くとそんなものだろう。

これを考えると、自転車通勤をしたほうがいいのではないかと思う。しかし、駐輪場に自転車を止めるのは面倒だ。では折りたたみ式の自転車を使えばいいのではないか。

と考えていると、同僚からCARRYMEを勧められた。これは10万円するとても小さな折りたたみ自転車の自転車だ。実際に載ってみたが、やはりホイール径が8インチでは乗り心地が悪い。するとBROMPTONという自転車を勧めらた。これは20万円する折りたたみ自転車でホイール径も14インチ。なかなか悪くないがまだ乗り心地が悪そうだ。調べたところDAHHONはホイール径が20インチの折りたたみ自転車だ。これはなかなかよさそうだが少し大きい。これならKHSのような普通の自転車を2つに折りたたみましたぐらいの自転車の方が乗り心地がよさそうだ。

しかし、折りたたみ性能と乗り心地は両立できないらしく、どちらかに振らなければならない。そして、10万、20万も出すのであれば、とても乗り心地のいい折り畳めない自転車が買える。であれば駐輪場の手間を考えても普通の自転車を買うべきだろうか。

2018-11-13

C++標準化委員会の2018サンディエゴ会議の結果

2018 San Diego ISO C++ Committee Trip Report (Ranges v1 TS for C++20; consensus on modules design; new Language and Library Evolution Incubators) : cpp

2018年サンディエゴ会議のトリップリポートが公開されている。今回も大きく変わった。

Range

Rangeが入った。Rangeは膨大なのでここでは解説しない。

Yet another approach for constrained declarations

autoと書くべきところをCocept autoと書けるようになった。


template <auto N >
auto f( auto x )
{
    auto y = x ;
}

というコードを、


template < Concept auto N >
Concept auto f( Concept auto x )
{
    Concept auto y = x ;
}

と書ける。

関数の戻り値の型と変数宣言の場合はautoを省略できる。


template < Concept auto N >
Concept f( Concept auto x )
{
    Concept y = x ;
}

こんなところがまだ変わるようでは、まだまだC++20参考書は書けそうにない。書いたそばから変わっていく。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r2.html

必ずコンパイル時に評価されるconsteval関数が追加された。

consteval int f( int x )
{
    return x+1 ;
}

constexpr関数は実行時評価でよい場合は評価を実行時に遅延させてもよいという規定がある。consteval関数は必ずコンパイル時に評価される。

std::is_constant_evaluated

コンパイル時評価されているときにtrueを返すstd::is_constant_evaluatedを追加する。


constexpr double power(double b, int x) {
  if (std::is_constant_evaluated() && x >= 0) {
    // A constant-evaluation context: Use a
    // constexpr-friendly algorithm.
    double r = 1.0, p = b;
    unsigned u = (unsigned)x;
    while (u != 0) {
      if (u & 1) r *= p;
      u /= 2;
      p *= p;
    }
    return r;
  } else {
    // Let the code generator figure it out.
    return std::pow(b, (double)x);
  }
}

これにより、constexpr関数の中にコンパイル時処理と実行時処理を同時に書くことができるようになる。

少し異質なライブラリで、コンパイラーマジックでサポートされるので、ヘッダーファイルに依存せず使うことが可能となっている。

[C++標準化委員でなければ読めない] p1330r0.pdf

unionの有効なメンバーを切り替える処理をコンパイル時定数にする。std::stringやstd::optionalをconstexpr化するのに必要。

p1002r0.pdf

try, catchをコンパイル時処理では無視する。コンパイル時定数への対応ではない。標準ライブラリの多くをconstexpr化するのに必要。将来的に例外をコンパイル時定数に対応する可能性を閉ざすものではない。

Allowing dynamic_cast, polymorphic typeid in Constant Expressions

dynamic_castとtypeidをコンパイル時定数にする変更。すでにコンパイル時にvirtual関数を使えるようになっているため、制限する理由がなくなった。C++20ではC++コンパイラーはコンパイル時に確保されたオブジェクトの型を把握して適切にディスパッチする必要がある。

p1006r1.pdf

std::pointer_traitsをconstexprに対応させる変更。std::vectorをconstexprにするために必要。

今回はまだ入らなかったが、動的メモリ確保も次回あたりにコンパイル時定数になる予定だ。つまりコンパイル時に動的メモリ確保ができるようになる上、その他の例外やらvirtual関数やらunionやらといった処理もすべてコンパイル時定数になるので、std::stringやstd::vectorがそのままconstexprに対応することになる。C++20ではほとんどの処理がコンパイル時定数になる。これは静的リフレクションを入れるために必要な変更だ。

Misc constexpr bits

標準ライブラリのconstexprにできる部分を積極的にconstexprにしていく変更。

P0668R4: Revising the C++ memory model

C++のメモリーモデルの変更。一部のアーキテクチャのとても弱い保証に対応した。一部のアーキテクチャー、PowerやNVIDIAのGPUとARMは、memory_order_seq_cstに対応しつつrelease/aquireに対応できない。memory_order_seq_cstの存在を許すaquire/releaseを実装するためには、よりペナルティの高い強めのフェンスを挿入しなければならない。しかしそのような理論的な問題のためだけに強いフェンスを使いたくはない。そのために、memory_order_seq_cstには対応しない弱いatomic型を追加する。

P1236R0: Alternative Wording for P0907R4 Signed Integers are Two's Complement

符号付き整数型の値の表現は2の補数であることがC++の規格で保証する変更。

char8_t: A type for UTF-8 characters and strings (Revision 5)

UTF-8文字リテラル、UTF-8文字列リテラルの文字の型を表現するchar8_tを追加する提案。私が9年前にC++0xのときに提案したところ、「でもchatは生のバイト列を表現するのに適切な型だからー」と寝ぼけた主張で却下されたにもかかわらず、後になって「やっぱchar8_tにしとけばよかったなぁ」となったので変更された。私には愚痴を言う権利がある。

Nested Inline Namespaces

インライン名前空間をネストで書けるようにする。


namespace lib::container {
    inline namespace v1 {
        namespace node {
        }
    }
}


namespace lib::container {
    inline namespace v2 {
        namespace node {
        }
    }
}

のように中間のinline名前空間を書く際にはC++17に追加されたネストされた名前空間で書けなかったが、


namespace lib::container::inline v1::node {
}

namespace lib::container inline v2::node {
}

のように書けるようにする。

p1289r0.pdf

contractの中ではアクセス指定を無視する変更。

p1007r2.pdf

std::assume_aligned<N>(ptr)の追加。ポインターptrの指すアドレスがNでアラインされていることをコンパイラーにヒントとして与える


// intの配列から合計をSIMD演算で計算する関数
int sum_ints( int * ptr, std::size_t n )
{
    std::assume_aligned( ptr, alignof(int) ) ;    
    // アライメント要求のあるSIMD演算で合計を計算
    return 
}

実際に指定したアライメントになっていることを保証するのはユーザーの仕事だ。std::assume_alignedはアライメントが保証されていると仮定してよいとコンパイラーにヒントを与えることによって、コンパイラーがSIMD演算のようなコード生成を行うときに、アライメント調整用のコードを生成せずに住むようにする。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1085r2.md

spanからoperator ==を取り除く変更。spanをregularにするために必要な変更。

STLの作者Alexander StepanovはC++では型はRegularであるとが重要だと力説した。型がRegularでない場合、もたらす利便性よりも混乱のほうが大きくなる。

コピーコンストラクターとコピー代入演算子は、オブジェクトの「値」をコピーする。

operator ==やoperator <はオブジェクトの「値」を比較する。

型がRegularであるためには、コピーと比較は同じ「値」を比較しなければならない。コピーと比較で「値」の定義が異なっている場合、混乱の元だ。

さて、spanはどうなっているか。spanのコピーはshallowだ。つまり、ポインターとそのサイズがコピーされる。一方、spanのoperator ==はdeepだ。つまり、ポインターの参照する先のストレージが比較される。

spanをRegularにするためには、spanのoperator ==を廃止する。

Smart pointer creation with default initialization

make_unique_default_init<T>/make_shared_default_init<T>を追加する。これはデフォルト初期化されたunique_ptr<T>/shared_ptr<T>を返す。

size_t型の引数nを取るものもあり、こちらはunique_ptr<T[]>/shared_ptr<T[]>を返す。


// デフォルト初期化されたint型の値の
// std::unique_ptr<T>
auto p = std::make_unique_default_init<int>() ;
// それぞれデフォルト初期化されたint型の値で要素数が5の
// std::unique_ptr<T[]>
auto a = std::make_unique_default_init<int>(5) ;

C++標準化委員会では、特定の分野について議論するStudy Groupが設置されるが、今回、新しいStudy Groupとして、SG19 Machine LearningとSG20 Educationが追加された。SG19は名前だけみると機械学習についてで、SG20は前から作ると宣言されていた教育に関するSGだ。

C++を発展させるEvolution Working Groupでは以下のような興味深い議論があった。

モジュールの中でmain関数を定義できる提案と、プログラムにデータを埋め込むstd::embed提案はより深い議論とフィードバックが必要だとされた。

void main提案は却下された。

興味深いのは、operator []の中の operator , の利用をdeprecatedにしようという決定だ。


int a[5] ;
a[1,2] ; // a[2]と同じ

このコードがdeprecated扱いになる。operator []の中のカンマは、多次元配列を実装するための何らかの新しい機能として予約される。

short float提案についてコンセンサスは得られなかった。

std::colonyはもっと作業が必要だとされた。

設計的には賛同できるのでC++20に追加する方向で進めるライブラリとして、テキストフォーマット(std::format)、スタックトレースライブラリがある。

SG13 Graphics Study Groupではオーディオに関する興味もあるらしい。またweb_viewに対するさらなる作業を推奨する雰囲気だ。

今後の予定としては、2019年春のKona会議でFeature freezeをし、2019年夏のドイツのCologne会議でCommittee Draftの文面を完成させる。つまり来年の半ばにはC++20の概要は決定するわけだ。

モジュールはおそらくC++23以降に延期される。コルーチンやExecutorも延期される。ネットワークライブラリはおそらくC++26以降になるだろう。

2018-11-10

かつてPSエミューレーターにスラップ訴訟を仕掛けたソニーのPSクラシック、自由ソフトウェア実装のPSエミュレーターであるPCSX ReARMedを使っていることが判明

かつてPSエミュレーターをスラップ訴訟により嫌がらせをして事実上の販売停止に追い込んだ邪悪なソニーが販売するPSクラシックには、自由なソフトウェア実装のPSエミュレーターであるPCSX ReARMedが使われていることが判明した。

Kotakuによるレビューによれば、PSクラシックの使用する自由ソフトウェアのライセンス表記の一覧にPCSX ReARMedが確認できたという。

PCSXは自由ソフトウェアによるPSエミュレーター実装で、2000年に公開された。その開発は停滞したが、2006年にPCSX-dfとしてforkされた。またPCSX-Revolutionいうforkもあった。2009年にはこの2つのforkを参考にPCSX-Reloadedいうforkも行われている。

PCSX ReARMedはPCSX-Reloadedのforkで、PCSXをARMアーキテクチャに移植する目的で開発されている。

さて、ソニーはPSエミュレーターに対して悪名高いスラップ訴訟を仕掛けてきた歴史がある。

Mac用のPSエミュレーター実装であるConettixのVirtual Game Stationの販売を著作権侵害のスラップ訴訟を起こして差し止めようとした。これは最終的にソニー側に不利な和解で終わっているが、その間VGSの販売が差し止められた。

また、Bleem CompanyによるPSエミュレーターBleem!を著作権侵害と不正競争防止法によりスラップ訴訟を起こして差し止めようとした。この訴訟でソニーが完全に敗北している。PSエミューレーターは不正競争防止法に反しないばかりか、宣伝に使ったPSゲームのスクリーンショット利用すら、著作権法に照らし合わせて正当な引用であるとの当然の判決が下った。しかし、物語はハッピーエンドには終わらない。長引く訴訟により膨れ上がった訴訟費用に耐えかね、Bleem Company は倒産。結果的に邪悪なソニーはBleemの販売を事実上差し止めることに成功した。

その悪名高い札付きのソニーが当時の愚かな行いに対する謝罪もなく、何食わぬ顔で自由ソフトウェアを使ったPS互換機を販売するとは、恥知らずにも程がある。ソニーはPSクラシックの販売にあたって、過去の過ちを認め、公に謝罪するべきである。

結局、抵抗は無意味であり自由ソフトウェアが勝利するのだ。

参考文献:

PlayStation Classic Plays Fine, But It’s A Bare-Bones Experience

Sony using open source emulator for PlayStation Classic plug-and-play | Ars Technica

Sony to sue Connectix over PlayStation emulator • The Register

Connectix Virtual Game Station - Wikipedia

Bleem! - Wikipedia

PCSX-Reloaded - Wikipedia

PCSX ReARMed

2018-10-29

帰ってきたきれいなリーナス・トーバルズ、無作法な開発者をたしなめる

Linus Torvalds Shows His New Polite Side While Pointing Out Bad Kernel Code - Phoronix

人の心の読み方を学んで復帰したリーナス・トーバルズは、さっそく無作法なプルリクエストをたしなめている。その文章は大文字センテンスも4文字言葉も使っていない優しいものに変わっている。

問題はプルリクエストはBigBenゲームコントローラーに対するドライバーの追加で、このドライバーはデフォルトで有効にされていた。これはLinuxカーネルの慣習にそぐわないものだ。新しく追加された名前もきいたこともないようなデバイス用のドライバーが、いきなりカーネルでデフォルトで有効にはされないものだ。新参者のドライバー開発者は、大抵自分のドライバーはとても重要で、自分の所有しているデバイスは全員所有しているのでデフォルトで有効にするのは当然だと傲慢にも考えている。このような既存の慣習に従わない傲慢な態度は、通常、リーナス・トーバルズによって発見され次第、罵詈雑言を持って鼻っ柱を叩き折り、厳しくしつけられる。

それがなんと以下のように穏やかなメールになっている。

新しいポッと出のドライバーがデフォルトで有効にされることは「ない」。そのデバイスが聞いたことのないような名前の場合は「特に」ありえない。

にもかかわらず、このマージ期間で新しく追加された「BigBenインタラクティブ」ドライバーとやらはまさにそういうことをしている。

そういうことはするな。

分かってる分かってる。開発者は全員、自分のドライバーはとても特別で魔法のように重要なので、当然デフォルトで有効にされるべきだと考えているものだ。だが違う。何千ものドライバーがあるなかで、ポッと出の新しいドライバーが、一部の開発者が特別だと思っているという理由だけで、デフォルト有効にされることはない。

そういうわけで、コミット256a90ed9e46 ("HID: hid-bigbenff: driver for BigBen Interactive PS3OFMINIPAD gamepad")の

default !EXPERT

は完全に間違いだ。プリーズこういうことはしないでくれ。

リーナス

比較のために、去年の11月に似たような問題をたしなめたリーナスのメールを見てみよう。

テメーは新しいドライバーを追加してデフォルトonにしただと。

(大文字)コイツァゼッテーに受け付けらんねーッ。

何でこの俺が直々にマージ期間のたびに毎回言わなくちゃなんねーんだよ。だがもっかい言ってやるぞ。

開発者として、テメーは自分のドライバーとか機能が超絶最高に重要なものだと思ってて、しかもテメーは対応するデバイスも持っているわけだ。

(大文字)だがそんなのァ誰も気にしちゃいねぇんだよ。

これ読んで泣きベソでもかいとけ。オメーのハードウェアが超絶に普及してない限り、全員の設定でデフォルトでデフォルト化されているべきじゃねぇ。

(一部単語が大文字)このブランチで追加されたすべての"defult"の行は間違ってる。

こういうことはやめろ。みんなの期待を裏切る行為だぜ。俺が"make oldconfig"したとき、ポッと出の新しいハードウェアドライバーが有効にされてほしくはない。

もう一つリーナスの忍耐力を試すイベントがあった。リーナス様の環境がKernel oopsをお出しになったのだ。

俺のラップトップが今のgitツリーでカーネルページフォルトを出した。今の所怪しいコミットは

9ee3e06610fd ("HID: i2c-hid: override HID descriptors for certain devices")

これだが、そう思った理由は単に今回のマージ期間でこの辺をいじってるコミットがこれしかないからだ。

oopsは以下の通り

(省略)

だから俺は新しいi2c_hid_get_dmi_hid_report_desc_override()のコードを疑ってるわけだ。

思うに問題はi2c_hid_dmi_desc_override_table[]がNULLエントリーで終端されていないことなので、今からテストする。

この問題はすごく悲しい。これはつまりこのコードは文字通り誰にもテストされてないってことで、誰もこのリストにエントリーを入れてないってことだ。

ちなみに以前、リーナスがパッチを適用したカーネルをブートするだけで確実にカーネルoopsを発動させるような初歩的なミスを発見した場合は、大文字で「テストされてないクソ」となじり、罵詈雑言あふれるメールが飛ぶものだ。

2018-10-24

C++標準化委員会の10月の興味深い文書

2018-10のC++標準化委員会の文書集が公開されていたので、興味深い新機能の提案に限って紹介する。

secure_val

セキュリティ上の理由でメモリの内容を破棄したい場合、コンパイラーの最適化によって意図通りのコードが吐かれないことがある。


void decrypt()
{
    char password[64] ;
    // パスワードを取得
    get_password(password) ;

    // 複合処理
 
    // パスワードをメモリから破棄
    std::memset( buffer, 0, 64 ) ;
}

このコードでは最適化の結果memsetが省略されるかもしれない。なぜなら、bufferはmemsetの後に使われていないから、memset自体が不要だとコンパイラーは判断できるからだ。

そのために、最適化によって消えずに値を消去できるライブラリを提供する。


void secure_clear( void * data, size_t size ) noexcept ;
template < typename T >
void secure_clear( T & object ) noexcept ;

この提案はさらに、secure_val<T>クラスを提案してる。secure_valはT型を保持するクラスで、デストラクターはT型をセキュアに破棄する。T型の値にアクセスする方法は関数オブジェクトを指定するもので、コピーを許さない。


void decrypt()
{
    std::secure_val<char [64]> val ;

    val.access([]( auto & data )
    {
        get_password( data ) ;
    } ) ;

    // 複合処理

    // valのデストラクターがセキュアにメモリ上の値を廃棄
}

unique_val

secure_valに似ているunique_val。これはT型をコピーせずにムーブするクラスだ。

ムーブしたあとのT型はデフォルト初期化された値になる。

ポインターやシステムリソースへのハンドルを扱うのに使える。

Remember the FORTRAN - p1300r0.pdf

C++に現在提案されているモジュールの実験的な実装はFORTRANが30年間解決できなかったパフォーマンス上の課題を抱えていると警鐘を鳴らす文書。

GCCのモジュール実装では、モジュールのソースファイルをコンパイルして.nsmファイルを作成しその後そのモジュールをimportするソースファイルをコンパイルすると、該当する.nsmファイルを使う。

FORTRAN-90はモジュール機能を備えており、これは今のC++のモジュールと原理的に同じ機能を同じ実装で提供している。つまりFORTRANは30年前からモジュール機能がある。

あるモジュールをimportするソースファイルをコンパイルするためには、事前に依存するモジュールをコンパイルしなければならない。モジュールは別のモジュールをimportできる。つまりモジュールをコンパイルするには事前に依存する別のモジュールをすべてコンパイルしなければならない。

これはビルドシステムととても相性が悪い。ビルドシステムが複数のソースファイルからなるプログラムをビルドするとき、モジュールの依存関係を把握してDAGを構築し、適切な順序でモジュールをコンパイルしなければならないということだ。つまりビルドシステムはC++ソースファイルを解釈する必要がある。

IntelのFORTRANコンパイラーのマニュアルは「プログラムが依存するモジュールのファイルは事前に生成しておけ」という。Intelという超巨大で世界的な大企業ですら、莫大な利用料を支払う顧客に対して、「依存してるモジュールは事前に全部コンパイルしとけよ」ぐらいの助言しか与えられていないのだ。

著名なGNU Fortran開発者ですら、Fortranのプログラムをビルドするときは、「Makeを成功するまで十分な回数実行する」と言っている。

モジュールを正しくコンパイルするにはモジュールの依存関係の解析が必要で、そのためにはソースファイルの解釈が必要になる。Makeやninjaのような汎用的なビルドシステムにC++を解釈する機能をつけることは現実的ではないので、C++コンパイラーが依存関係を解決する機能を提供するようになるだろう。

ところで、Windowsはプログラムを起動するパフォーマンスが極めて悪い。1ソースファイルごとにC++コンパイラーを1回起動して依存関係を解決するような実装はWindowsではパフォーマンスが悪い。

不自由で低能なWindowsはプロセスの作成もスレッドの作成も遅いし、ましてやファイルの作成に至っては、i7でNVMeのSSDを積む高性能なコンピューター上で動くWindows 10がRaspberry PiとSDカード構成のRaspbianにすらパフォーマンスで負けるという信じられないほどの低能を誇っている。

Benchmarking OS primitives – Bits'n'Bites

そして、ソースファイルの一部だけを変更した後の部分的なビルドですら、モジュールの依存関係が変わるかもしれないので依存関係の解決が必要だ。

モジュールはビルド時間を削減するべきであって、ビルド時間を増やすのは本末転倒だ。

FORTRANが30年かかっても解決できていない問題は解決できそうにない。

P1283R0: Sharing is Caring

Linuxのshared libraryやWindowsのDLLのためにエンティティをexportする属性、sharedの追加の提案。

P1282R0: Ceci N’est Pas Une Pipe: Adding a workflow operator to C++

新しいワークフロー演算子として<|と|>を追加する提案。


// 右から左
a <| b ;
// 左から右
a |> b ;

C++20にはレンジやExecutorやコルーチンやモナドが提案されているがこれらの提案は右から左、もしくは左から右といった処理の流れを記述する。例えば以下は1から始まる整数列を生成し、奇数だけをフィルターした整数列にし、その先頭から5個だけを取り出した整数列にするレンジのコードだ。


iota(1) | filter(odd) | take(5) ;

これは処理の流れがわかりにくい。すでにoperator >>はあるが、これは演算子の評価順序の関係で使えない。operator >>=なら使えるがこれは汚い。

そこでオーバーロード可能なワークフロー演算子を追加する。


iota(1) |> filter(odd) |> take(5) ;

これはほしい。

P1281R0: Feature Presentation

本当の条件付きコンパイル機能の提案。

constexpr ifは条件付きコンパイルではなく、条件付きテンプレート実体化抑制機能だ。そのために意味上エラーとなるコードを書くことができない。

この提案では、条件付きコンパイル機能を提供する属性により、文法上正しいが、意味上エラーとなるコードを書けるようにする。


[[ feature("key")]] 

[[feature()]]はキーとなる文字列を受け取る。このキー文字列が宣言されていないか、ブロックリストに入っている場合は、その属性がある宣言とその中身がASTから取り除かれる。

利用例は以下の通り。


struct [[feature("vulkan")]] Device {
  [[feature("glsl-to-spirv")]]
  static Shader compile(std::filesystem::path filename);
  static Shader load (std::filesystem::path spirv_file);
};

struct [[feature("direct-x")]] Device {
  [[feature("hlsl-to-spirv")]]
  static Shader compile (std::filesystem::path filename);
  static Shader load (std::filesystem::path spirv_file);
};

いまグラフィックAPI用のライブラリを書きたいとする。このライブラリはVulkanとDirectXを両方サポートする。ただしコンパイル時の環境では、VulkanかDirectXのどちらかしか提供されていない。上のようなコードで、"vulkan"か"direct-x"のどちらかのキー文字列だけを宣言することで、2つのDeviceクラスの実装のうち、どちらか片方だけを有効にできる。無効な属性のクラスはまるごとASTから取り除かれる。

さらにこのライブラリはシェーダー言語であるGLSLやHSSLからSPIR-Vへの変換機能を提供するが、条件次第ではこの機能を提供しないことも選択できる。

文法上妥当である必要があるので、比較的穏当な条件付きコンパイルだ。#ifdefはいずれ廃止したいものだ。

P1280R0: Integer Width Literals

ビット長を指定した整数型intN_tとuintN_tに対するユーザー定義リテラルとして、operator "" iNとoperator "" uNを追加する提案。


using namespace::literals ;

auto a = 0i16 ; // std::int16_t
auto b = 0i32 ; // std::int32_t

auto c = 0u8 ; // std::uint8_t
auto d = 0u64 ; // std::uint64_t

便利だ。

P1279R0: std::breakpoint

プログラムからブレイクポイントを設定できるライブラリstd::breakpointの提案。


using namespace std::literals ;

int main()
{
    std::breakpoint() ;
    std::cout << "hello"sv ;
    std::breakpoint() ;
    std::cout << "world"sv ;
    std::breakpoint() ; 
}

P1278R0: offsetof For the Modern Era

std::offsetofの提案。offsetofはマクロでstandard layout classにしか使えない。std::offsetofはstd::bit_castで実装できるが、std::bit_castはconstexprではない。std::offsetofはconstexprになるべきだが、議論が必要だ。

P1277R0: Subscripts On Parade

operator []で複数の引数を取れるようにする提案。


struct S
{
    int & operator [] ( int a, int b, int c ) ;
} ;

int main()
{
    S s ;
    s[1,2,3] = 1 ;
}

多次元配列ライブラリが提案中だが、多次元配列へのアクセスをできるだけ直感的に書けるようにしたい。

P1276R0: Void Main

void mainを認める提案。すでにmain関数は空のreturn文を認めていて、その場合は0を返したものとみなされる。ならばvoid mainも認めてよいはずだ。

P1275R0: Desert Sessions: Improving hostile environment interactions

C++にプログラムの引数の参照と、環境変数を参照、変更できるライブラリを追加する提案。C++風にイテレーターでアクセスできる。

P1274R0: Bang For The Buck

識別子としてダラーサイン($)を認める提案。さらに、識別子の最後に限り驚嘆符(!)と疑問符を(?)を認める。

これにより"set!"や"empty?"のような関数名も使えるようになる。

$は静的リフレクションのキーワードreflexprの代わりに使えるようにすべきだという声もあるが、著者は識別子として使えるようにしたほうが有益だと主張している。

私としては$はreflexprの代わりに使いたい。jQueryのように・・・というと縁起が悪いが。

Pattern Matching - p1260r0.pdf

パターンマッチの提案。文法は比較的穏健。

整数の例


// Before
switch (x) {
    case 0: std::cout << "got zero";
    case 1: std::cout << "got one";
    default: std::cout << "don't care";
}

// After
inspect (x) {
    0: std::cout << "got zero";
    1: std::cout << "got one";
    _: std::cout << "don't care";
}

文字列の例


// Before
if (s == "foo") {
    std::cout << "got foo";
} else if (s == "bar") {
    std::cout << "got bar";
} else {
    std::cout << "don't care";
}

// After
inspect (s) {
    "foo": std::cout << "got foo";
    "bar": std::cout << "got bar";
    _: std::cout << "don't care";
}

tupleの例


// Before
auto&& [x, y] = p;
if (x == 0 && y == 0) {
    std::cout << "on origin";
} else if (x == 0) {
    std::cout << "on y-axis";
} else if (y == 0) {
    std::cout << "on x-axis";
} else {
    std::cout << x <<','<< y;
}

// After
inspect (p) {
    [0, 0]: std::cout << "on origin";
    [0, y]: std::cout << "on y-axis";
    [x, 0]: std::cout << "on x-axis";
    [x, y]: std::cout << x <<','<< y;
}

他にもvariantの例、ポリモーフィック型の例、式を評価する例がある。

pattern_matching

別のパターンマッチの提案。こちらはどの関数型言語からやってきたんだというぐらい既存のC++にそぐわない異質な文法になっている。

enumの例


enum color { red, yellow, green, blue };

// Before
const Vec3 opengl_color = [&c] {
  switch(c) {
    case red:
      return Vec3(1.0, 0.0, 0.0);
      break;
    case yellow:
      return Vec3(1.0, 1.0, 0.0);
      break;
    case green:
      return Vec3(0.0, 1.0, 0.0);
      break;
    case blue:
      return Vec3(0.0, 0.0, 1.0);
      break;
    default:
      std::abort();
  }();

// After
const Vec3 opengl_color =
  inspect(c) {
    red    => Vec3(1.0, 0.0, 0.0)
    yellow => Vec3(1.0, 1.0, 0.0)
    green  => Vec3(0.0, 1.0, 0.0)
    blue   => Vec3(0.0, 0.0, 1.0)
  };

あまりにもC++として異質すぎる。

クラスに対するパターンマッチの例


struct player {
  std::string name;
  int hitpoints;
  int lives;
};

// Before
oid takeDamage(player &p) {
  if(p.hitpoints == 0 && p.lives == 0)
    gameOver();
  else if(p.hitpoints == 0) {
    p.hitpoints = 10;
    p.lives--;
  }
  else if(p.hitpoints <= 3) {
    p.hitpoints--;
    messageAlmostDead();
  }
  else {
    p.hitpoints--;
  }
}

// After
void takeDamage(player &p) {
  inspect(p) {
    [hitpoints:   0, lives:0]   => gameOver();
    [hitpoints:hp@0, lives:l]   => hp=10, l--;
    [hitpoints:hp] if (hp <= 3) => { hp--; messageAlmostDead(); }
    [hitpoints:hp] => hp--;
  }
}

あまりに既存のC++の文法とは違いすぎる。

p1235r0.pdf

implicit constexprの提案。

constexpr関数の制約は今後ますます減っていき、コンパイル時定数式にしたい処理は今後ますます増えていく。

C++17ではlambda式のoperator ()は暗黙にconstexprだ。この結果、以下の同じように見えるコードの挙動が異なる。


int f( int x ) { return x ; }
auto g = [](int x ) { return x ; }

// Error
constexpr int a = f(0) ;
// OK
constexpr int b = g(0) ; 

そこですべての関数を暗黙にconstexprにしてしまおうというのがこの提案だ。

C++ Compile

C++のコンパイル方法を標準化しようという提案。C++の教育SGが提唱されたり、パッケージシステムも議論される中、必要な提案ではあると思うが、果たして受け入れられるだろうか。

この提案では、コンパイラーのオプション指定は+で指定する。長いオプションは++で指定する。

cpp hello.cpp ++output=hello

まず<compile>ヘッダーにコンパイラーを呼び出すライブラリが追加される。


namespace std
{
  int compile(int, char * *) noexcept;
  int compile(vector<string>) noexcept;
}

一つ一つの文字列がargumentとして処理される。+で始まらないargumentはソースファイル名だ。

+で始まるのはコンパイル時のオプションで、例えばヘルプメッセージの出力、出力ファイル名、デバッグといったC++コンパイラーによくあるオプションを定義している。

コンパイル方法を標準化することによって、教育や提案中のパッケージシステムで使いやすくなる。

ファイルシステムライブラリも標準C++にある今、C++ライブラリとしてのビルドシステムという不思議な概念が浮かんだ。

p1177r0.pdf

パッケージシステムの全容の提案、コンパイラーAPI、ビルドシステムAPI、パッケージ依存解決API、パッケージ検索APIによって構成される。

P1214R0: Pointer to Member Functions and Member Objects are just Callables!

メンバーへのポインターをINVOKEのように振る舞わせる提案。


struct Foo
{
    int data ;
    int func( int x ) { return x ; }
} ;

int main()
{
    int (Foo::*data_ptr) = &Foo::data ;
    int (Foo::*func_ptr)(int) = &Foo::func ;
    Foo obj ;

    // Before
    obj.*data_ptr = 123 ;
    (obj.*func_ptr)(123) ;

    // After
    data_ptr(obj) = 123 ;
    func_ptr(obj, 123) ;
}

ジェネリックコードで大量の特殊化を書く必要がなくなる。

p1227R0: Signed size() functions

符号付き整数を返すsize関数としてssizeの提案。

std::vector<int> v ;
for ( int i = 0 ; i < v.size() - 1 ; ++i )
{ }

このコードは"0u-1"を実行してしまうので意図通り動かない。ssizeがあれば、"v.ssize() - 1"と書ける。

P1108R1: web_view

画期的に使いやすいグラフィックライブラリ、webviewの提案の改定案。変更点としては議論が追加されている。これはHTMLとCSSをブラウザーで表示し、JavaScriptを注入できる極めて簡単なライブラリだ。

2018-10-23

SQLiteの行動規範がキリスト教徒の戒律を全文引用していて香ばしすぎる

Code Of Conduct

SQLite creator crucified after code of conduct warns devs to love God, and not kill, commit adultery, steal, curse... • The Register

SQLiteの行動規範(Code of Conduct)は大真面目に西暦500年の聖ベネディクトの作った72か条の戒律を全文引用している。この行動規範はSQLiteの利用者が同意する必要はないが、開発者は同意しなければならない。結果としてSQLiteは危険すぎるので使ってはならない。なぜならばSQLiteの開発者は全員キリスト教原理主義者で奴隷制度を肯定し非武装でキリスト教徒に改宗すらさせた敵をジェノサイドしたカルト宗教の信奉者であり、キリスト教の教義に合わないコードは書かず、異教徒を攻撃するだろうからだ。

聖ベネディクトが西暦500年ごろに作った72か条の戒律のほとんどは現代の価値基準に照らし合わせて香ばしい。

  1. まず第一に、主たる神をまつたき心、まつたき魂、まつたき力を以って愛せよ
  2. しこうして、汝の隣人を汝がごとく愛せよ
  3. 殺すなかれ
  4. 姦淫するなかれ
  5. 盗むなかれ
  6. 欲するなかれ
  7. 偽証するなかれ
  8. 皆を敬え
  9. 汝自身にせぬことを他人にするなかれ
  10. キリストに従うために汝自身を否定せよ
  11. 汝自身を折檻せよ
  12. 喜びに耽るなかれ
  13. 断食を愛せよ
  14. 貧者を慰撫せよ
  15. 裸人に服を与えよ
  16. 病人を訪れよ
  17. 死人を埋葬せよ
  18. 艱苦を救え
  19. 嘆きを慰撫せよ
  20. (訳注:異教徒どもの罪深い)世界とは手を切れ
  21. キリストへの愛のほかには何も好むな
  22. 怒りに身を任せるな
  23. 遺恨を養うな
  24. 心に偽りを抱くな
  25. 偽りの和平を結ぶな
  26. 寄進を惜しむな
  27. 呪うな、汝自身を偽るがゆえに
  28. 心からの真実のみを口にせよ
  29. 邪悪に邪悪をもって返すな
  30. 他人に邪ならずして、汝への邪は甘んじて受けよ
  31. 汝の敵を愛せよ(訳注:敵の存在も神の思し召しなるがゆえに)
  32. 汝を呪うものを呪うな。祝福せよ
  33. 正義のために懲罰を受け入れよ
  34. 誇るなかれ
  35. ワインを痛飲するなかれ
  36. 鯨飲馬食するなかれ
  37. 寝ぼけるなかれ
  38. 怠けるなかれ
  39. 愚痴るなかれ
  40. 中傷するなかれ
  41. 望みを神に託せ
  42. 汝にかかる良きことは汝の功にあらずして神の功とせよ
  43. 己の行いは邪にして己の責に帰すことを思え
  44. 審判の日を恐れよ
  45. 地獄を恐れよ
  46. 全身全霊で永久の命を欲せよ
  47. 毎日死を見つめよ
  48. 人生における行動に常に気をつけよ
  49. 神はすべての場所を見張っていることを確実に知れ
  50. 邪なる思いが胸中に生ずるときはただちにキリストに帰依し、精神の父なることを認識せよ
  51. 邪なる言葉を口にするなかれ
  52. 饒舌を愛するなかれ
  53. うぬぼれや笑いをもたらす言葉を話すなかれ
  54. やかましい笑いと行き過ぎを愛するなかれ
  55. 聖書の朗読を積極的に聞け
  56. 頻繁に祈れ
  57. 祈りにおいては毎日己が神に対する罪に落涙嘆息し、かかる邪を将来に償うことを思え
  58. 肉の欲望を満たすなかれ
  59. 己が意思を憎め
  60. 神が権威を託した者の命にすべて従え。たとえ権威者が自ら率先せずとも従え(そは神の禁じたもうことなり)。主のかの言葉を思い起こせ「他人の言葉を汝行い、他人の行いを汝行うなかれ」と
  61. 己の至らぬのに聖人と呼ばわるることを望まずして、呼ばわるるところの聖人たらんとせよ
  62. 神の戒律を日々満たせ
  63. 禁欲を愛せよ
  64. 誰をも嫌うな
  65. 嫉妬羨望するなかれ
  66. 諍いを好むなかれ
  67. 傲慢を避けよ
  68. 目上を敬え
  69. 目下を愛せよ
  70. 汝の敵にキリストの憐憫を祈れ
  71. 日没までに汝の反対者と和平せよ
  72. 神の慈悲に悲嘆するなかれ

2018-10-22

江添誕生日ボドゲ会@10月28日

江添誕生日ボドゲ会@10月28日 - connpass

10月は誕生日なので週末の28日に昼からボドゲ会、夕方からすき焼き会をすることにした。参加表明はconnpassから行える。

2018-10-14

消費税について考えたこと

「消費税10%は100円が110円になると考えるのではなく、1000万円が1100万円になると考えるべきだ」というつぶやきを目にした。しかしこれは言っていることが同じだ。

私はむしろ、消費税とは手取りに対する税金ではないかと考えている。貯蓄をしない家計では、消費税は実質手取りに対する税金だ。貯蓄をしない家計にとって、消費税10%とは、手取り20万円が18万円になることだ。

もっとも、この考え方にも問題はある。というのも貯蓄をしない家計は賃貸住宅に住んでいるだろうが、不動産の貸付料である家賃には消費税はかからない。手取り20万円の家計で家賃6万円の場合、14万円が12万6千円になるということだ。

消費税と言えばイタリアは先進国だ。1973年という昔から12%の消費税を導入し、1997年には20%に引き上げられた。そのイタリアでは、表に出ず消費税を脱税した地下経済とマフィアが発展した。

消費税が10%ともなると、日本でも地下経済と、地下経済の信用取引を履行させるためのヤクザが発展するだろうか。

日本ではヤクザの人権を剥奪する法律によりヤクザの人口が急激に減りつつある。また個人間の送金手段は経済に悪影響を及ぼすほど厳しく規制しているので地下経済も発展しにくい。

とはいえ、消費税があまりにも高くなれば地下経済は発展するだろうし、地下経済が発展したならば、その信用取引を確実に履行させるための機関としてヤクザが必要になり、ミカジメ料を支払うようになるのでヤクザも再び興隆するだろうか。

ということを考えながら、消費税制度の解説を眺めていたところ、興味深い定義を発見した。

「郵便切手類、印紙、証紙、物品切手の譲渡は非課税取引」

興味深い定義だ。すべての取引が地下経済に潜ることはできない以上、我々は表の取引もする。であれば、一部の取引を切手や印紙による取引とするのは現実的ではないだろうか。素晴らしいことに地下経済にする必要すらない。単なる非課税取引をしたにすぎないのだから。

具体的に考えよう。君は牛を二頭持っている。今君は牛を一頭売る契約をしたので契約書作成の税金を収めるため収入印紙を貼る必要がある。君は残りの牛一頭のミルクを売って現金を得て消費税を払い、残りの現金で収入印紙を買う。もし、君がミルクと収入印紙を直接交換したならば、消費税を支払う必要はない。

すばらしい。我々は現金ではなく収入印紙で支払うことによって消費税を節税することに成功した。消費税を支払わない分、ミルクの値段を下げるか、利益を上げることができる。

こう考えると、消費税の存在は貨幣経済に対する足かせであるように思えてくる。

しかし収入印紙は日本国に対する支払いにしか使えない用途の限定された通貨だ。現金という汎用的な通貨ではない。この問題をどうすればいいのだろう。

収入印紙には需要がある。需要があるものは汎用的な通貨である現金と交換できる。例えば金券ショップでは、収入印紙は額面の95%ぐらいで交換できる相場だ。ところで今の消費税は8%である。収入印紙で取引して収入印紙を現金化した場合の損失が、消費税率を下回る場合、これは得をしたと言えるのではないか。しかも合法だ。つまり収入印紙での取引は合法的な節税になるのではないか。

私は経済学にも消費税制度にも詳しくないのだが、この解釈は正しいのだろうか。

2018-10-07

Steven WeinbergのTo Explain The Worldを読んだ

邦訳では「科学の発見」という題名がついているSteven WeinbergのTo Explain The Worldを読んだ。

著者のSteven Weinbergはノーベル物理学賞の受賞者でイスラエルの熱烈な支持者だ。

冒頭で「本書で筆者は過去を現代の基準で批判する愚を犯す」と書きながら、この本は科学がどのように発展してきたかを解説している。

本書はまず、古代ギリシャにおける万物を構成する元素の説について取り上げる。古代ギリシャの哲学者が、元素は水だとしたり、火だとしたり、水、火、土、空気の4種類だと主張している歴史を取り上げる。

ここまではまあいいとして、プラトンの提唱した説を取り上げて悶絶する。プラトンは四大元素である火、水、土、空気について、とても小さい元素が存在し、5種類ある正多面体をそれぞれ割り当てた。たとえば火は正四面体で、水は正二十面体といった具合だ。その仮説を立てるのはいいとして、割り当ては一体どういう理由で行われたのか。プラトンは単にそれが理想だからとしか語らない。

科学というものは、まず観測し、観測結果から仮説を立て、仮説が観測結果に従うことを検証するものだ。

しかし古代ギリシャでは、科学は科学ではなく哲学で、単に理想を追求するものでしかなかった。なので万物を構成する元素は元素は火や水といったわかりやすい理想的なものになり、元素は5種類ある正多面体であるとし、完全数を尊びといった、現実の観測結果より理想を追求し、理想が現実に従わないことは無視されていた。

その後、本書の大半は天体の運行の予測を通じた科学の発展に費やされる。

天体の運行には規則性があり、古代から占星学などの存在により、天体の運行を正確に予測する需要があった。

古代ギリシャ時代から地球が中心で月、惑星、太陽、その他の恒星は全て地球の周りを回っている説が主流であった。

古代ギリシャ時代にはすでに地球を中心とした天体の運行を予測する数式モデルが考案されていたが、他の天体はすべて地球を中心とした真円で回るなどと定義されていたため、現実の観測とは大いに異なっていた。しかも、それぞれの天体が謎の理由で割り当てられた正多角形に内接する真円で回るなどという、これまたプラトンのように理想を追求したモデルであった。

天体は地球を中心に真円で回転するモデルを使うと、惑星はある時期だけ逆方向に回りだしたりする。惑星が大抵の言語で語源からして、惑う星であるのも、これが原因だ。

そこでプトレマイオス説が考案された。この説では、天動説で現実の観測結果に近似させるために、あまりにも無理やりな天体のモデルを考案した。天体は太陽を中心に真円で回っている。この真円を従円と呼ぶ。天体は従円を線上を中心としてさらに真円で回っている。この真円を周転円と呼ぶ。

プトレマイオス説は複数の真円を組み合わせ、真円の大きさをパラメーター化することで、惑星の運行を現実に近似させることを試みた。その結果、かなりの制度で現実の観測に近似した天体モデルを作ることに成功した。

プトレマイオス説は科学だ。観測から観測結果に従う数式モデルを作ったわけで、これは科学と言える。

プトレマイオス説は哲学者からは理想ではなく天体の予測のための方便であるとされていた。天文学者(この時代の天文学者は占星学をかねる)は積極的に使っていた。というのも、プトレマイオス説は現実の観測結果の近似していて、予測に役立つからだ。

その後、様々な天文学者がプトレマイオス説により複雑な周転円を追加することで、さらに現実の観測結果に近づける努力が行われた。

太陽を中心として天体が公転している地動説は以前にも理想として提唱されたことはあったが、現実の観測結果を説明できる具体的な数式モデルはコペルニクスによってまず作られた。ただし、コペルニクスの数式モデルは精度が悪かった。というのも、コペルニクスは天体は太陽を中心に真円で公転していると定義したが、実際には太陽は中心ではなく、天体の公転軌道は真円ではないからだ。

本書は中東の科学についても解説している。中東の科学はイスラム教の普及によって妨害されるまでヨーロッパより進んでいた。ギリシャ時代の学説は中東からもたらされる形でヨーロッパに再発見された。その後イスラム教の普及により中東の科学の発展は阻害された。

そしてガリレオ・ガリレイの時代までやってくる。ガリレオ・ガリレイは優秀な望遠鏡を発明し、望遠鏡によって精密な天体観測をした。その結果地動説を唱えるわけだが、その上でパトロンであるローマ教皇を天動説を信じているなどと批判したので宗教裁判にかけられて地動説を封印する。後世に残る逸話によれば、このときガリレオは「それでも地球は回っている」とつぶやきながら法廷を後にしたと言われる。

宗教裁判の後、ガリレオは晩年まで自宅に軟禁状態におかれるわけだが、ガリレオの科学への情熱は冷めていなかった。ガリレオは落下する物体の速度について研究していた。落下する物体の速度を観測するのは当時としては難しい。というのも、速度が速すぎるために正確な観測ができないためだ。

ガリレオはこの落下速度の問題に対し、科学的な観測方法を考案する。緩やかな傾斜面を転がる球を使うことで速度の計測を可能にした。時間の計測には水時計を使った。傾斜角を変えることでガリレオは速度は傾斜角に比例することを示し、傾斜角を転がる球は落下速度の計測の代わりに使うことができることを示した。もちろん現実には、球と傾斜面の摩擦にもエネルギーが使われるが微々たるもので当時実現可能な観測方法としては十分なものだった。ガリレオは傾斜角を転がる球を机の端から飛ばし、その軌道が放物線であることも観測している。

本書はニュートンの説明に移る。ニュートンによって科学革命はクライマックスを迎えるわけだが、しかしこのニュートンという人物はなんという奇人だろうか。ニュートンは生涯、イングランドのごく狭い地域より外に出ることはなかった。ニュートンは潮の満ち引きについて多大なる関心を持っていたにもかかわらず、生涯一度も海を見ることはなかった。中年に至るまでニュートンは身近に女を寄せ付けることがなかった。母親とて例外ではない。50代になってから親戚の美しい娘を家政婦として雇っているが、この2人の間に男女関係はなかった。ニュートンは科学以外にも、非科学的な錬金術や宗教について多大な著作を残している。

ニュートンの研究者の間でよく言われることには、ニュートンは最初の科学者ではない。ニュートンは最後の魔法使いである。時代が魔法から科学に変わる節目の時期にあって、魔法から科学への橋渡しをした人物だ。

ニュートンの法則を記述したPrincipiaは、単に重力を説明し得たために偉大だというわけではない。ニュートンはPrincipiaによって、物理的現象は簡単な数学的原則と、その原則の応用で説明できることを示したのだ。

中国の悪意あるハードウェアの細工を見破る方法

中国で生産されているハードウェアに悪意あるチップが取り付けられておりAppleやAmazonが被害にあっているとする報道があり、真偽について議論がある。

これに関連して、Hacker Newsで興味深いコメントが寄せられていた。

I have worked in card payment industry. We would be getting products from China ... | Hacker News

俺はカード支払い業界で働いている。中国から送られてくる製品にクレジットカード情報を送信する装置が取り付けられていることがある。これは国家による攻撃ではない。装置は生産ラインの途中で取り付けられている。大抵は賄賂を受け取った従業員によるものだ。装置が組み立てられた後は、改造防止の機能が動くので、改造を検知させずに装置を分解するのは不可能だ。

この問題が発覚してから、我々は製品の重さを計測することにした。我々も製品を分解することはできないからだ。分解したならば改造検知により装置は動かなくなる。

攻撃者は重さの計測に気がついたので、製品内部の必須ではないプラスチックを引っぺがして装置を追加することによって増加した重さの調整をしてくるようになった。

結局、我々は特別な土台を使い製品の角運動量(訳注:慣性モーメントか)を計測するようになった。とても高価な装置で角運動量を計測する。俺が作った土台を使って2つの角度から角運動量を計測している。2つの製品の角運動量がどの角度からでも一致するならば製品は同一というわけだ。すべての角度から角運動量を計測できないが、今のところ破られていない。

角運動量ではなく慣性モーメントだろうという用語の甘さや、慣性モーメントは3軸を使って全角度を測定できるのではというツッコミが入っているが、この話自体はよくあるものらしい。

なんでそんな製造段階で悪意ある細工が混入した製品を送ってくるところと取引を続けるんだというコメントに対し、この製品を製造しているのは今や中国をおいて他にないとか、中国の商習慣では信頼を前提としない契約による取引に応じてくれないとか、中国と取引するには製品の欠陥は自前で発見できなければならない、発見できないのはマヌケな顧客であり欠陥品で十分だとみなされる、などの中国のお国柄を指摘するコメントが続いている。

2018-09-20

健全なP2Pネットワークの信用のためには全利用者の参加が必須であるという話

「Zaifが5966BTCやられたようだな」
「ククク、あれは後発取引所ゆえ保有量が最弱」
「85万BTCを溶かした余の足元にも及ばぬ」

また一つ暗号通貨の取引所が失敗した。人はいつになったら学ぶのだろうか。中央権威のないP2Pネットワーク上の信頼は、利用者全員が参加することでしか担保できぬと。

信じられないことに、暗号通貨の利用者の中でも、なぜ暗号通貨が信用できるか、というより暗号通貨の何を信用しているかを理解しているものは少ない。皆暗号通貨と日本円などの国家通貨の交換レートしか気にしていない。国家通貨との交換レートなど、暗号通貨の実現している技術的な価値に比べればチリほどの価値もない。暗号通貨の価値は、中央権威のない通信越しに偽造できない通貨の取引を実現したということにある。

問題を簡単にするために、暗号通貨とは違う例で考えよう。

アリスとボブが仕切りを隔てて音声による会話しかできない状況に置かれている。この状況で、アリスとボブはコイントスによる勝負をする。コイントスは投げたコインが表か裏のどちらを上にして落ちるかで勝敗が決まる。アリスが表で勝つのであれば、ボブは裏で勝つ。アリスが裏ならばボブは表で勝つ。

アリスとボブが賭ける表裏を音声による会話で選択したとして、一体どうやって信頼できるコイントスをすればいいのだろうか。アリスとボブのどちらか一方がコイントスをして結果を相手に伝える場合、音声による会話しかできないので、相手はコイントスの結果を信用できない。アリスとボブ以外に勝負の審判をしてくれる都合のいい第三者はいない。

実は、この状況でアリスとボブがどちらも信用できるコイントスを行うことは数学的に可能だ。

では問題を変えよう。ここに60億人の人間がいる。全員、音声による会話しかできない。60億人のうちのある一人のアリスが、ある一人のボブに自分の持っている通貨の支払いたい。支払った後のアリスは通貨を失い、ボブは通貨を得る。しかし全員音声による会話しかできないのに、どうやったらそんな取引が信用できるのだろうか。

これも、数学的に信用できる方法がある。bitcoinを始めとする暗号通貨が行っているのはこれだ。

信用を担保するには、60億人が全員同じ方法で数学的な計算を行い、不正がないことを確かめなければならない。もし、30億人と一人が不正のための計算に協力したならば、アリスが支払ったはずの通貨はアリスの手元に残り、ボブの手元には通貨がない常態にすることも可能だ。しかし、そのような参加者の過半数を超える大規模な計算は難しい。

ただし、この方法で信用できるのは、ある暗号通貨の取引だけだ。暗号通貨と日本円の取引とか、物の取引は暗号通貨の信用の範囲外だ。

残念ながら、世の中の暗号通貨利用者の大半はズボラで、自ら信用を担保することを考えていない。こういうマヌケ共は、自ら信用のための計算をせずに、取引所と呼ばれる他人に計算を任せる。本来ならば証明された数学と計算力を信用すればよいはずの暗号通貨を、他人の信用に置き換えてしまう。こうなるともはやその計算を任された取引所が権威となり、単一障害点になってしまう。その結果、取引所が失敗すると任せていた全員が失敗する。

人はいつ学ぶのだろうか。

そういえば、CloudflareがIPFSのゲートウェイを提供するという興味深いニュースがあったので、今はIPFSについて学んでいる。今学んだ限りでは、名前解決であるIPNSを除けば、IPFSが喧伝していることはBitTorrentプロトコルに対するフロントエンドで実装できそうで、あまり目新しい価値はないように思える。そして、Cloudflareのような大手がゲートウェイを提供し、皆が自前でフルノードを動かさずにゲートウェイに依存することで、健全なP2Pネットワークの信用が損なわれてしまうだろう。

2018-09-17

Linus、今までの行いを謝罪し一時的にカーネルメンテナーの立場を退いて人の気持ちを勉強してくると発言

完全に背景事情を調べ上げたわけではないのだが、どうもLinusが毎年参加しているLinuxカーネルの会議に、Linusがスケジュールを間違えて参加できなくなるという事態が発生した。当のLinus本人はもう20年も続いている会議だし自分がいなくてもやっていけるだろうと楽観視していたが、会議自体がLinusの都合にあわせてリスケジュールされた。

LinuxにおいてLinus Torvaldsといえば第一人者であり極めて重要な存在で、そのLinusが毎年参加している重要な会議にLinusが参加できないとあれば、その他のあらゆるコストを度外視して根回し調整を行い、Linusが参加できるようにイベント全体のリスケジュールを行うのは人間の感情から考えて当然である。しかし当のLinus本人は他人の感情が読めず、そこまでの大事になるとは考えていなかった。その認識の差が今回の騒動に発展した。

Linux 4.19-rc4 released, an apology, and a maintainership note - Linus Torvalds

[ その他の長々しい話 ]

いつもの発表とは違う先週のことについて。メンテナーとカーネルコミュニティについての、公になっているカーネルサミットによるものと様々なプライベートなやり取りの議論について。議論の一部は俺がメンテナーサミットのスケジュールを間違えたから起こったわけだが。

こういう議論は今週になって初めて始まったわけでもない。メンテナーとコミュニティについては長年議論してきたわけだ。プライベートでもメーリングリストでもたくさん議論されてきた。カンファレンスでも毎回トークがあるし、これも、一般向けのものと、廊下を歩きながら話す種類のものがある。

先週がいつもと違ったのは、俺の反応と、俺が反応しすぎたためだ(判断は読者に任せる)

要するに議題は2つある。

ひとつは俺がメンテナーシップサミットのスケジュールでヘマをやらかしたことに対する俺の反応だ。いや、実際日付を間違えたのは失敗だったが、でも正直なところ、俺がここ20年ぐらい参加していたカーネルサミットに今回ぐらい参加しなくてもいいんじゃないかと思っていたのだ。

実際には、サミットがリスケジュールされたし俺の「俺なしでもやれるんじゃない」って意見は覆されたわけだ。だがこの状況が別の議論の呼び水になった。これが議題の2つめにかかってくるわけだが、俺は気がついたんだよ。俺って人の気持ちが読めないんじゃないのってことに。

要するに「鏡で自分の顔を見てみろよ」って瞬間だな。

というわけで、俺がついに気がついたこととして、俺が毎年のカーネルサミットを今回ばかりパスするのは面白くもないしいい兆候でもないってことと、俺は今の今までコミュニティの気持ちを汲み取れていなかったということだ。

何というかな。無視できるってものは、だいたい俺が首を突っ込みたくないものなんだな。

これが俺という人間の現実だ。俺は他人の感情を読み取るのが得意ってタイプの人間じゃないし、そのことはみんなも当然気がついていただろうから驚きはないだろう。俺以外はな。俺が長年、他人の気持ちを読み取れずにいて、大人でない環境を作り出していたってのは良くないことだ。

今週、コミュニティ内の人間は俺が人の感情を理解できていないということについて批判してきた。俺の反論は大人気なかったし良いものでもなかった。特に俺個人の問題としたことについてだ。俺がよりよいパッチを追求することについて、これは俺の中では当然のことだ。これはどうもよろしくない態度だと気がついたわけで、正直すまんかった。

こうくどくど書き連ねているのはつまり俺が誤りを認めて、おいおい、お前は態度を改めなければならんぞ、という辛い思いをかみしめているのであって、俺の態度で気分を害したりカーネル開発から抜けてしまった人間にあやまりたい。

ちょっとここらで休みを取って、他人の感情を理解する方法と、適切な応対の方法について、誰かから学んでくる。

別の視点で考えると、カンファレンスに呼ばれた時、俺はよく、カーネル開発の厄介な問題点はたいてい技術的な問題ではなくて、開発フローと態度の変化の問題なのだというトークをよくする。

この厄介な問題点というのは、パッチを管理する方法とか、やり方の大規模な変更とかだ。「パッチとtar-ball」によるリリース(15年前に「Linusはスケールしない」という厄介な議論が持ち上がった原因)から、BitKeeperを使う方法に変わり、それも無理になってきたのでgitを使う方法に変わった。

そういう厄介な問題点は、ここ10年ぐらいなかったわけだ。だが今週、それに匹敵する厄介な問題点が見つかった。

これを4.19-rc4のリリースに結びつけると(いや、実際関係しているのだが)、4.19はなかなかよいものになると思うよ。このリリースサイクルは「落ち着いた」期間になるし、Gregに話はつけておいたので、Gregが4.19を取り仕切ってくれる。その間に俺が休みを取って、俺の態度について修正してくるわ。

これは「俺はもう燃え尽きた。もう逃げ出したい」っていう休みじゃない。Linuxのメンテナーを辞めたいなどとは思っていない。実際逆だ。俺はこの30年近く関わってきたプロジェクトをまだ続けたい。

これは前にもあったように、"git"という小さなツールを書くためにカーネル開発をちょっと停止するひつようがあったように、今回もちょっと休憩して、誰かに手伝ってもらって、態度を改め、俺のツールとワークフローの問題を修正するということだ。

実際のところ、修正の一部はツールで解決できるかも知れないのだ。例えば、メールフィルターをかまして、俺が罵詈雑言を含むメールを送信しようとしたら差し止めるとか。ほら、俺はツールの信者だからさ、一部の問題は、簡単な自動化で防げるかもしれないだろ。

俺が本当に「鏡を見た」とき、明らかに俺に必要なのは変化だけではないわけだが、いや、ほら・・・何か提案があったらメールで送ってくれよな。

メンテナーサミットで会えるのを楽しみにしているよ。

Linus

2018-09-10

TempleOSの作者Terry Davisが列車に引かれて死んだ

Man killed by train had tech following | The Dalles Chronicle

Man killed by train had tech following By Neita Cecil As of Friday, Septem - Pastebin.com

両親と喧嘩をして勘当され路上生活をしていたTerry Davis(Terrance Davis)が8月11日に列車に引かれて死んだことが確認された。享年48歳。

Terry DavisはTempleOSの作者だ。

TempleOS

読者の多くはTempleOSを知らないだろう。TempleOSとはx86-64 Ring-0上で動作するOSだ。プロセス分離はなく、メモリ保護もなく、そもそも仮想メモリではなく物理メモリアドレスを直接使うOSだ。コンセプトは古き良きCommodore 64の現代版だ。あの頃のPCはメモリアドレスは直接メモリアドレスであって、仮想メモリによってどこか不定の物理メモリアドレスにマッピングされたりなどしなかった。

TempleOSはキリスト教の影響を受けておりキリスト教の聖書やキリスト教に由来するゲームが多数入っている。

TempleOSはHolyCで書かれている。HolyCはC言語に似た文法を持っている。TempleOSのシェルはHolyCのJITコンパイラーになっていて、シェルに書き込むと、HolyCがJITコンパイルされ実行されるようになっている。

作者は統合失調症を患ったOS開発者で、大抵のインターネット上のフォーラムからは出禁の扱いを受けていた。なぜならば、Terry Davisの発言には必ず人種差別と罵詈雑言が含まれていたからだ。彼にとってほとんどの人間は「ニガーでCIAのスパイ」だと認識されていた。

Terry Davisは統合失調症の症状が強く現れてからは職を辞め、両親と同居して、キリスト教の神の神殿をコンピューター上に再現するTempleOSを開発していた。

何年もそういう状況であったが、2017年に両親とだいぶひどいいさかいを起こし、ホームレスになっていた。

ホームレスになった後も定期的に動画が上がったりなどして生存が確認できていたが、ここ最近、死亡説が噂されていた。それが確認されたことになる。

悲しい

GitHubからDXVKレポジトリが消失

GitHubのDXVKレポジトリが500を返すようになった。

https://github.com/doitsujin/dxvk

DXVKはDirectX 10/11の自由なVulkan実装だ。DXVKによってWineやProtonはDirectXの使われたWindows用ゲームをGNU/Linuxで実行することができる。DXVKにより不自由なMicrosoft Windowsはとうとうゲーム用OSとしても完全に敗北し、その座をGNU/Linuxに明け渡すことになる予定だが、どうしたことだろう。

DXVK github not found and valve's copy throws error? Whats happening? : linux_gaming

どうやら、DXVKの作者のGitHubアカウントが謎の理由でBANされたそうだ。

DXVK github not found and valve's copy throws error? Whats happening? : linux_gaming

作者によってすぐにGitLab上でDXVKが公開された。

Philip Rebohle / dxvk · GitLab

Redditでは「そういえばGitHubはMicrosoftに買収されるんだよな」というジョークが書き込まれているが、ジョークで済むだろうか。

追記2018-09-10 9:14: 復活した。

2018-09-03

江添ボドゲ会@9月8日

自宅ボードゲーム会を以下の要領で開催します。

江添ボドゲ会@9月8日 - connpass

2018-09-02

DNAの読み取りについてプログラマーが誤解していること

世の中にはDNAの読み取りを使った技術が実用されすぎている。DNAを使った生物の共通祖先の判定、人間の出アフリカ以降の移動の推定、特定の病気にかかりやすい遺伝子を持つかの判定、親子鑑定、刑事裁判におけるDNA鑑定などなど。

あまりにもDNAの読み取りを使った技術が実用化されすぎているため、世間ではDNAの読み取りは簡単なものだと考えている。プログラマーとて例外ではない。

大抵のプログラマーはヒトDNAの読み取りを以下のように考えている。

「一本の長い磁気テープを先頭から末尾までシーケンシャルにリードする」

より現実的に例えると以下のようになる。

  • 長さ30kmの長大な磁気テープをだいたい長さ1cmのテープ片に切断する
  • 上記1cmのテープ片を数百本複製する
  • 上記複製した数百本の1cmテープ片をマイクロメートル単位のテープ片にズタズタに切り裂いて混ぜ合わせる
  • 上記混ぜ合わせたマイクロメートル単位のテープ集合からランダムでテープ片を手当たりしだいに読み込み、組み合わせパズルを解いて元の1cmの磁気テープ分の正しいデータ配列を決定する
  • 残りの29.999999kmのテープについても同様に1cmづつ処理する

マイクロメートル単位のテープ片をランダムに読み取って組み合わせパズルを解き、元の1cmのテープ分のデータ配列を決定するのはソフトウェアにより実装されている。読者はそのようなパズルを解くプログラムをバグなしで実装できるだろうか。

ただし、より例え話を現実に近づけると、1cmのテープ片をマイクロ単位のテープ片に切り裂くのはランダムではない。この1cmのテープ辺には数百-2ビットから数千-2ビット程度のデータが記録されている。テープをマイクロメートル単位に切り裂くカッターは、テープの末尾の2ビットの値がn回目に出現したmであるときに切断するという条件付きカッターだ。これにより、00, 01, 10, 11のいずれかの2ビット値の1回目の出現、2回めの出現、3回目の出現といった単位でテープをカットできる。

マイクロメートル単位のテープ辺を読むリーダーはあまり融通が聞かない。すでに読んだテープ辺と同一内容のテープ編を何度も読み込むことになるし、同一内容のテープ辺は同じ回数読み込まれるわけではない。読み込みエラーが発生して任意の2ビットが別の値になってしまうかもしれない。なのでできるだけ何度も読み込み、まれにしか現れない異端データを読み取りエラーと判断して除外する処理も必要だ。

これを考えると、プログラマーとしての私は、DNA読み取りを使う技術が信頼できなくなってしまう。私のDNAを読み取った結果、特定の病気になりやすい遺伝子が含まれているとか、ある人物と親子関係にあるとか、犯行現場に残されていたDNAと一致したなどと言われても、その結果は信頼することができない。なぜならばDNAを読み取るという処理が極めて大雑把で信頼できない確率的な統計処理だからだ。

現実のDNA読み取りはどうしているかと言うと、30億塩基配列ほどあるヒトDNAを、数百塩基から数千塩基のサイズに分割し、たまたま高温に耐える都合のいい細菌から得たDNA複製酵素と一緒に容器の中に放り込み、定期的に温度を上げ下げする装置を使い、ポリメラーゼ連鎖反応を起こしてDNA片を複製する。そして特定の塩基配列に対してのみ反応してDNAを切断する酵素を使い、n回目に4種類ある塩基(アデニン、グアニン、シトシン、チミン)の特定の一種類が現れたDNAをそこで切断させる。そうやって切断されたDNA片を片っ端から読み込み、組み合わせパズルを解く。

実際、アメリカではDNA鑑定の結果が証拠として信頼できないとして、DNA鑑定に使われたソフトウェアを検証するために開示請求がなされたこともある。

せめてプログラマーだけでもDNA読み取りの正しい理解をしてほしいものだ。

ssh経由のtmuxの中で動くvimのウインドウサイズ変更にマウスを使う方法

私はマウスが好きだ。

30行以上、100列以上の文字が表示できる端末を使っている私にとっては、マウスは必須である。画面上に表示される任意の1文字にカーソルを合わせたい場合、キーボードだけでカーソルを移動させるのはとてもつらい作業である。一方、マウスならばその場にカーソルを動かすだけでよい。

端末を分割して複数の画面にする時、それぞれの画面のサイズをその場で微調整するには、キーボードで画面サイズの数値を指定するよりは、やはりマウスで直感的にドラッグしたい。

例えばvimだ。以下のようにすると

:set mouse=a

Vimはマウスを扱えるようになる。端末の任意の文字にカーソルを合わせるのにマウスを使えるのみならず、マウスでスクロールやマウスで範囲選択もできる。

Vimは画面を複数のWindowに分割できる。

:split
:vsplit

このとき、マウスを有効にしているとウインドウの枠をドラッグすることでサイズを直感的に変更できる。

tmuxも重要なソフトウェアだ。

tmuxは.tmux.confに以下の設定をすれば、

set -g mouse on

マウスを使えるようになる。マウスでスクロール、範囲選択ができるし、

Ctrl-b "
Ctrl %

で作ったtmuxのpaneのサイズもドラッグで直感的に変更できるようになる。

ところが、tmuxのなかで実行したvimのウインドウのサイズをマウスで変更できないことに気がついた。

調べた結果、これは.vimrcに以下のように書き込めばできる。

set mouse=a
set ttymouse=xterm2

どうやらxterm2にあるドラッグ中もマウス入力を通知し続ける機能を使うそうだ。tmuxも対応している。

これで問題は完璧に解決したと思ったが、もう一つ問題に出くわした。ssh先のリモートで実行したtmuxの中で実行したvimではマウスによるウインドウのりサイズができない。

これは.tmux.confに以下のように書けばできる。

set -g mouse on
setw -g alternate-screen on

man tmuxをみるとデフォルトでonになっているはずだが、なぜかUbuntu server 18.04ではonになっていないようだ。

これで以前からやりたかったssh越しにも違和感のまったくない環境を作ることができた。

2018-09-01

ポータブルオーディオプレイヤーは二極化している

今のポータブルオーディオプレイヤーは二極化している。格安のゴミみたいな製品と、オーディオフィリ向けのクソみたいな製品があり、その中間がない。

最近、減量のためにジョギングを再開した。ジョギングは一回あたり1時間ほど行うのだが、これが思いの外ヒマだ。この時間を有意義に使いたい。走っている最中にできることは音を聞くぐらいなものだ。音楽に興味はないが英語の朗読を聞くのは有意義なことのように思われる。例えば筆者はまだシェイクスピアのハムレットを読んだことがない。ハムレットを読むには時間がかかるが、ジョギング一回あたりの1時間を使えば、何度か走るだけでシェイクスピアを通して聞くことができる。

そこで早速、ジョージ・オーウェルの1984やシェイクスピアのハムレットを朗読した自由な録音をダウンロードした。

LibriVox

元々が低音質なソースであるのだから、それほど高級な製品はいらない。そこで、アマゾンでよく購入されていた適当な格安ポータブルオーディオプレイヤーであるAGPTEK A01Tと、格安BluetoothイヤホンであるSoundPeats Q30を購入した。

さっそくハムレット朗読のmp3ファイルをコピーするが、なぜか再生の順序がファイル名の文字列順にソートされない。どうやら、FAT32のファイルのディレクトリーエントリーの順番で再生されるようだ。そこで仕方なく、以下のようにして問題を解決した。

ls | while read file ; do mv $file path-to-mp3-storage/$file

いざ聞いてみると、今度は片耳にしか音が聞こえてこない。どうやらこの格安ポータブルオーディオプレイヤーは、モノラルmp3ファイルに対して片耳しか出力しないようだ。残念ながらモノラルmp3ファイルを再エンコードなしでステレオにすることはできないので、以下のようにして無駄にステレオにした。

ls | while read file ;< /dev/null do ffmpeg -i $file -ac 2 -b:a 320k path-to-mp3-storage/$file

当初動かずに困惑したが、ffmpegが標準入力を食べてしまうことが原因だった。

そしてGNU Parallelを使ったほうがよかったことに実行した後に気がついた。

mp3のエンコード速度はそれほどパフォーマンスを重視していない私のラップトップでも175倍速だった。たしか私がmp3プレイヤーを使っていた15年ほど前はせいぜい20倍速に満たない程度だった気がするのだが、いい時代になったものだ。私の一つ上の世代は、mp3をリアルタイムデコードするためにCPUをオーバークロックしたと聞く。

本の朗読を聞くために買ったのだからあまり期待はしていなかったものの、この格安ポータブルオーディオプレイヤーはあまりにもひどい品質だ。おまけに、文字コードの対応もひどい。どうやらいまだにUCSに対応していないらしく、本体の言語設定をした文字に引きづられる。例えば言語をEnglishに設定するとASCII以外が文字化けし、日本語に設定するとシフトJIS外の文字が文字化けするようだ。これは解せない。ファイルシステムであるFAT32はファイル名をUCS-2で管理しているのだから、文字化けを起こすのはわざわざ何かとてもバカなことをしているとしか思えない。

不思議なことに、このポータブルオーディオプレイヤーにはFMラジオとかテキストリーダーとか万歩計とか録音とか動画再生などの様々な機能がありながら、ファイル名によるソート機能すらない。

ではもっとマシなポータブルオーディオプレイヤーはないものか。実は今ポータブルオーディオプレイヤーは二極化しているのだ。

ひとつには私が買ったような数千円で変えるクソのような格安の粗悪品。もう一つには、最低数万円から数十万円もするようなオーディオフィリ向けのバカのような高級品だ。中間層の市場はスマフォが完全に支配してしまったため、ポータブルオーディオプレイヤーは格安と高級品に二極化してしまったのだ。

では高級なポータブルオーディオプレイヤーとはどのようなものだろうか。安いものでも数万円から、高いものになると30万円ぐらいする。30万円だ。嘘ではない。本当だ。曰くハイレゾ、曰く超高性能DAC、曰くUSB Audio/DACに両方とも対応。厳選された高性能で高品質なキャパシタ、コイル、メッキなどなど。

ちょっとまってもらいたい。人間の可聴域は若者でもせいぜい20kHz程度であり、だからこそせいぜい40KHzのサンプリング周波数で20kHzまでの音を再現できるようにしているのだ。ハイレゾに意味はない。USB Audioに対応しているのはともかくとして、なぜUSB DACとして使える必要があるのだ。そして高級なキャパシタやコイルに至っては完全にオーディオフィリの領域だ。

5000円ぐらいでまともなUIを備えたポータブルオーディオプレイヤーはないものか。そもそも格安プレイヤーにすらいらない機能が多すぎる。必要なのはファイル名によるソート、シークバー、Bluetoothだ。自由にプログラミングできればなおよい。

という愚痴を漏らしていると、物好きな同僚がRaspberry Pi Zero WHを進めてきた。初代Raspberry PiのSoCを使い、WiFiとBluetoothが搭載された低電力なボードだ。Raspberry Piはその普及によって圧倒的に自由なソフトウェアスタックを得た。その性能はmp3やoggのリアルタイムデコードを難なくこなせるであろうし、Bluetoothも使える。しかも値段も2千円程度。確かに理想的なポータブルオーディオプレイヤーのように思える。

問題はUIをどうするかだ。タッチパネル付きのディスプレイをつけるのが一番いいように思える。考えてみよう。

2018-08-23

Steam Playで不自由なWindows用ゲームをGNU/Linux上で実行するにはPython 2が必要

Steam Playが発表されたので、早速使ってみた。

Steam PlayというのはWineからforkしたValveのProtonを使ったGNU/LinuxでWindows用ゲームを実行する機能だ。なぜWineをforkしているかというと、ProtonではWineにまだ入っていない変更を使っているからだ。例えばDirectXをVulkanで実装したdxvkや、同期処理をユーザースペースで行うValveが開発したWineに対するパッチesyncを使っている。

https://github.com/ValveSoftware/Proton

Steam Playを使うには、まずSteamクライアントのSettings→Account→Beta participationからSteamクライアントBetaを使う設定であるSteam Beta Updateに切り替え、Steamクライアントをアップデートする。

すると設定にSettings→Steam Playが追加されているのでこれを有効にする。Valveが検証したゲーム以外のすべてのゲームでSteam Playを有効にするには、その設定項目のEnable Steam Play for all titlesを有効にする。これでGNU/LinuxのSteam クライアントでもWindows用ゲームがインストール、実行できるようになる。

ここまではSteamクライアントで必要な変更だ。GNU/Linux側でも必要な用意がある。Steam PlayにはVulkanに対応したかなり最新のグラフィックスタックが必要になる。

詳しい内容は

https://github.com/ValveSoftware/Proton/blob/proton_3.7/PREREQS.md

に書いてある。

NvidiaのGPUを使っている場合は、不自由なバイナリブロブドライバーを396.51以上のバージョンにしなければならない。Ubnuntu 18.04のドライバーはLatest Long Lived Branchである390を使っているので、最新のバージョンをインストールしなければならない。

sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt install nvidia-driver-396

AMDとIntelのGPUを使っている場合は、最近のMesaとLLVMをインストールしなければならない。

sudo add-apt-repository ppa:paulo-miguel-dias/mesa
sudo apt dist-upgrade
sudo apt install mesa-vulkan-drivers mesa-vulkan-drivers:i386

AMDでVRゲームを実行する場合は、以下のパッケージが必要だ。

sudo add-apt-repository ppa:kisak/steamvr4pk
sudo apt dist-upgrade
sudo apt install linux-generic-steamvr-18.04

現在、IntelのGPUによるVRゲームはサポートしていないそうだ。

DirectX 11を使ったゲームを実行するには、NVIDIA 396.51以上、もしくはMesa 18.1.xが最低でも必要だ。LLVM 7も推奨されている。

OpenCLを使ったゲーム(DOOM 2016, Google Earth VR)を実行するには、Mesa 18.2.x以上が最低でも必要になる。

一部のディストロでは1プロセスあたりのfd limitが低いので、これを変更しなければならない。4096は1990年台には妥当な値ではあったかもしれないが、この2018年には少なすぎる。DebianとUbuntuでは上限が引き上げられているので問題はないそうだ。

そして最後にとても重要なソフトウェアをインストールする。Python 2だ。

sudo apt install python-minimal

こともあろうかこの2018年にProtonとgit submoduleしているffmpegがpython 2に依存している。

これでSteam Playを使う用意が整った。いくつかのWindows用の不自由なゲームを実行してみたが、いずれもよく動いている。

GNU/Linuxにおけるゲームは卵が先か鶏が先かという問題に直面していた。ゲーム開発者はGNU/Linuxゲーマーの需要がわからないのでGNU/Linux用のゲームを出さず、GNU/Linuxユーザーは対応しているゲームが少ないので仕方がなくWindowsかWineを使うので、結果として潜在的なGNU/LinuxゲーマーはWindowsゲーマーとしてカウントされてしまう。するとゲーム開発者はGNU/Linuxゲーマーの需要がわからないというデッドロック問題だ。

Steam Playによるゲームの実行は、GNU/Linuxユーザーとしてカウントされ、ゲーム開発者に通知されるしSteamの統計にも出る。これにより我々GNU/Linuxゲーマーの時代が訪れる。Microsoftの不自由で不便で非効率的なWindowsは最後の砦であったゲーム環境としても滅ぶのだ。未来は明るい。

2018-08-14

江添ボドゲ会@8月18日

江添自宅ボドゲ会を以下の要領で開催します。

江添ボドゲ会@8月18日 - connpass

2018-08-12

違法な職務質問を受けたので国賠訴訟を起こした裁判の傍聴のお知らせ

私の裁判の傍聴をしたいという人が何人かいるので、ここで証人尋問の傍聴の告知をしておく。

  • 日時: 2018年9月19日 水曜日 13時30分から16時頃まで
  • 場所: 東京地方裁判所631号法廷

傍聴をするためには、指定の日時の少し前に東京地裁に行き、金属探知機のある入り口を通過し、そのままエレベーターで6階まで上がって時間通りに631号法廷に行くだけだ。特に予約や手続きは必要ない。また、途中退出してもよいそうだ。

裁判の内容だが、私は約1年前に警察官から違法な職務質問を受けたので東京都を相手に起こした国賠訴訟だ。

本の虫: 警察官に職務質問をされた話

本の虫: 濫用に当たる職務質問を受けたと考えたので弁護士に相談して訴訟を起こすことになった話

裁判を起こすことになって初めて知ったのだが、警察というのは地方自治体の行政であるので、東京都内で生じた警察の行為について裁判を起こす場合、被告は東京都になる。

裁判は公開かつ口頭で行われるということになっているが、その実態としては、口頭で話すべき内容をすべて書面にまとめておき、あらかじめ裁判所に提出する。書面にすべてがまとめられているので、実際の期日に物理的な裁判所でやることはほとんどない。

実際に裁判所で行われる「儀式」は以下のようになる。

裁判官「原告/被告からは準備書面が提出されていますが、これは?」
原告/被告「陳述します」
裁判官「では次回期日ですがX月Y日のZ時からでは?」
原告/被告「その日は差し支えです/大丈夫です」

事前に提出した書面について「陳述」する宣言と、証拠の原本の確認と、次回期日を決めることしかしていない。

このようなやり取りが数カ月に一回発生するのが裁判だ。1回あたり5分から10分で終わる。この裁判の傍聴もできるのだが、傍聴しても退屈なので、これまで特に案内はしてこなかった。

今回は証人尋問が行われる。証人は原告である私と、職務質問の最初から最後まで現場にいたという警察官だ。当事者ではない第三者が傍聴して退屈ではない裁判というと、まず証人尋問だろう。

ところで、今回の裁判で気になる点としては、裁判官が頻繁に交代することだ。前々回でいきなり3人全員が同時に交代したかと思ったら、前回はさらに2人同時に交代した。裁判官の一部が交代するのはよくあることだが、それでも普通は一人ぐらいは最初から最後まで同じ裁判官を残すものだという。さもなければ、判決を書く裁判官はこれまでの裁判の口頭弁論も証人尋問も直接聞かず、書面だけで判断することになるからだ。一人でも最初から担当していた裁判官が残っていればその裁判官が物理的に見ているわけだから、その裁判官が知っているということにできるが、3人同時に交代してしまってはその手法も使えない。

今後の想定としては証人尋問を経て年内には判決が出る見込みだそうだ。

2018-07-31

GCCのgit移行が難航中

GCCはgitへの移行を計画しているが、GCCの既存のsubversionレポジトリをgitレポジトリに変換する作業が難航している。

GCCの移行作業を検証しているのは他ならぬEric S. Raymond(ESR)だ。

ESRお手製の変換ツール、reposurgeonはsubversionからgitへの変換ができる。

Resource page for reposurgeon 3.44

しかしGCCは30年もの歴史を持ち、そのsubversionレポジトリも複雑だ。

ESRはGCCのためにreposurgeonのバグを潰し、勢い変換しようと試みたが、意外な障害に出くわした。メモリ不足だ。

GCC's Conversion To Git Is Being Held Up By RAM, a.k.a. Crazy DDR4 Prices - Phoronix

ESRの所有する64GBのメモリを詰んだマシンではメモリ不足で処理できない。そしてDDR4メモリの値段は高騰している。GCCのビルドサーバーに128GBのメモリを詰んだものがあるからそれを使わせてくれとか、reposurgeonをPythonからGoに移植すればメモリ消費量は減らせる可能性があるが移植は困難を極めるとか、ESRに投げ銭してメモリを買わせようなどと議論をしていたのが7月はじめ。

さて、今はメモリ以外の問題に出くわしている。

GCC's Conversion To Git Is Still Turning Out To Be A Massive Headache - Phoronix

どうもGCCの膨大で複雑な歴史を正しくgitで表現する方法について議論の余地がある他、変換結果が壊れることもある。問題を解決したいが、変換自体がとても遅いため、デバッグが困難だという。

https://gcc.gnu.org/ml/gcc/2018-07/msg00322.html

トンネル出口の明かりが見えたと思ったら対抗列車が突っ込んできやがった。

もう変換はほぼほぼ終わりだと思っていたのに。俺はtrunkとブランチすべてがクリーンに変換されるのを確認したのに。捨ててもいいことに同意した失敗ブランチただ一つを除いては。

後残っているのはexecute-permission propagationとかmid-branch deleteをどうするかという問題だけで、前者はすでに解決済みだし、後者も解決に取り掛かっている。最終的には年末には、たぶん8月とか9月には、完了できるはずだったのに。

そしたらこのザマよ。俺の最新の変換がtrunkで間違った結果を出しやがった。これは実際ヤバイ問題で、GCCレポジトリがあまりにも巨大すぎるので調査するのに時間がかかりすぎる。SVNダンプファイルをreposurgeonで読み込むだけで4.5時間かかるし、フル変換に9時間はかかる。レポジトリは俺が最適化を考えるのと同じぐらい早く増大しているぜ。

しかも悪いことに、クリーンな変換ができるコミットまで戻っても失敗する。たぶん俺がへんてこなブランチコピーの対処を実装した結果こうなってるんだと思う。

パーティーに遅れてやってきた奴のために説明してやると、Subversionのダンプファイルの処理シーケンスの解釈は単純で検証も楽だ。ブランチコピー操作を除いてはな。ブランチコピーが他の操作に及ぼす影響だけはマジで闇が深い。

Subversionのコードが何をすべきかっていう正しいセマンティクスは存在するわけだが、古のSubversion開発者が理解していたことは、今や失われている。ダンプフォーマットはまともにドキュメント化されていない。今の不完全なドキュメントが存在する理由は、他でもない俺が解析したからだ。でも俺のドキュメントも疑問だらけだし、その疑問にはSubversion開発者も回答できないできる。

なのでレポジトリを変換する際にブランチコピーに関連した謎の挙動に出くわすのはよくあることだ。普通、おれは問題のコミットをbisectして、

  1. ダンプを問題が再現する最小のセグメントに切り取る
  2. content blobsをsource commitを識別できるunique small cookiesに置換する処理を行って結果が正しいことを検証
  3. topological reduceしブランチコピーもプロパティ変更でもない無価値なコミットを除去し、結果が正しいことを検証
  4. 手動で不必要なブランチをreposurgeonで削除

いつもなら、俺は今頃、問題を再現できる割と小さめのレポジトリ(今までで200コミットを超えたことはない)を作ってる。デバッグレベルを上げて変換を観察し、何が起こっているのかを観察する。そして問題を修正し、問題を再現する最小例は新たなテストケースになるって寸法だ。

これによって、ダンプファイル解析を着実に改善していき、Subversionのコードがやっていることをより忠実にエミュレートしていく。簡単な仕事ではないが、エッジケースを埋めていくほど楽になる。今まではこれでうまくいってきた。

GCCレポジトリのサイズでは、この戦略がうまくいかない。軽く計算するだけで、bisect一回で最短でも18日かかる。現実的には一ヶ月近くかかるだろう。

つまり、現状ではゲームオーバーで負けたってことだ。GCCレポジトリはでかすぎる上に変すぎる。

この問題を現実的に解決するには、俺のツールはすっげー速くなる必要がある。だいたい桁違いに早くないといかん。

ハードウェア性能を上げるのは無理だ。シングルプロセスを1.3GHz以上にあげたコンピューターはこの世に存在しないし、問題は並列化できない。

ソフトウェアの変更でうまく行く可能性はある。俺はreposurgeonをPythonからGoに移植するということについて考えている。repocutterで実験してみたところ、{Python版の40倍高速化した。reposurgeonではそんなに高速化するとは思えないが、問題を現実的に解決できるぐらいには高速化できるだろうと踏んでいる。40倍の半分だったとしても、9時間のテストランが13分になるわけだから。

この計画の問題点は、GOに移植するのは困難を極めるってことだ。めっちゃむずい。どのくらい時間がかかるかわからんが数カ月単位でかかる。

GCCはどのくらい辛抱強く待つのか決める必要があるな。現状だと、今のソースツリーの状態をそのままgitにしていちからはじめるほうがマシかもしれん。歴史は記録だけに留めるとして。

2018-07-24

しないでマイクロソフトのスタイルガイドライン準拠の翻訳

マイクロソフトは将来的に買収する見込みのGitHubで.NETのドキュメントを公開している。ハロウィーン文書が公開された頃のマイクロソフトからは考えられないほど変わったものだ。

https://github.com/dotnet/docs.ja-jp

その中にある変数名の命名規則に関するスタイルガイドラインについて書かれたドキュメントの文章がおかしい。

https://github.com/dotnet/docs.ja-jp/blob/live/docs/standard/design-guidelines/names-of-type-members.md

しないで動詞または動詞句は、メソッドの名前を指定します。

しないで名詞、名詞句、または形容詞を使用してプロパティの名前を付けます。

しないで次の例のように、"Get"メソッドの名前に一致するプロパティがあります。

しないで後に"List"または"Collection"単数形の語句を使用する代わりに、コレクション内の項目を記述する複数形の語句でコレクションのプロパティの名前を付けます

日本語として極めて不自然な文章になっていて意味がわからない。

原文は英語で書かれている。

https://github.com/dotnet/docs/blob/master/docs/standard/design-guidelines/names-of-type-members.md

原文を確認するとようやく意味がわかる。

DO give methods names that are verbs or verb phrases.

DO name properties using a noun, noun phrase, or adjective.

DO NOT have properties that match the name of "Get" methods as in the following example:

DO name collection properties with a plural phrase describing the items in the collection instead of using a singular phrase followed by "List" or "Collection."

なるほど、"DO"を間違えて「しないで」と訳してしまったのだな。"DO NOT"も「しないで」と訳されている。翻訳する上で間違えて機械的に置換でもしたのだろう。原文の文章の形をなるべく維持したまま日本語に訳すならば、"DO"を「正:」、"DO NOT"を「誤:」とでもすればいいのだろう。ただ、その場合"DO NOT"を使った文中で代替案も示してしまっているのが問題なので、これはできれば原文自体を「すべきこと」と「すべきでないこと」に分割すべきだろう。

そして間違いが20日にissueで指摘された。

https://github.com/dotnet/docs.ja-jp/issues/118

そして土日を挟んで今日、マイクロソフトから正式に回答があった。

https://github.com/dotnet/docs.ja-jp/issues/118#issuecomment-407202477

こんにちは、@megascus

言語に関するフィードバックをお寄せいただきありがとうございました。

お寄せいただいたフィードバックの内容を Microsoft の言語チームで検証いたしましたところ、残念ながら、マイクロソフトのスタイルガイドラインに従わない という理由で、承認基準に完全には適合していないという結果になりました。

記事の品質向上にご協力いただき誠にありがとうございました。引き続きお客様からの貴重なフィードバックをお待ちしています。

敬具

Microsoft DOCS International Team

そしてissueはclosedされた。

ん? である。問題は日本語の翻訳にあるのであってソースコードのスタイルガイドラインとは何の関係もない。上記の日本語を読解できるだけの日本語能力があるならば容易に気がつくはずで、まるでBOTによってなされたような回答だ。

その結果、マイクロソフト用語では"DO"は「しないで」を意味するのだとか、マイクロソフト社内では"DO"と"DO NOT"は同じ意味を持つのだとか、Google翻訳のほうがよっぽどマシな翻訳をしてくれるとか、ユーモラスなコメントが並ぶことになった。

マイクロソフト用語を使うと以下のようになる。

DO fix the document which has a translation error.

しないで誤訳を含むドキュメントの修正

DO translate with MS style guideline conformance.

しないでMSスタイルガイドライン準拠の翻訳

押すなよ、絶対押すなよ(押せ)、というダチョウ倶楽部メソッドを久しぶりに思い出してしまった。

2018-07-13

NPMのESLintのパッケージにマルウェアが混入された問題

Postmortem for Malicious Packages Published on July 12th, 2018 - ESLint - Pluggable JavaScript linter

https://github.com/eslint/eslint-scope/issues/39

要約

2018年7月12日に、攻撃者がESLintメンテナーのnpmアカウントを不正利用し、悪意あるコードが混入したeslint-scopeとeslint-config-eslintパッケージをnpmレジストリに公開した。インストール時に、悪意あるパッケージがダウンロードされ、pastebin.comからコードを実行し、このコードはユーザーの.npmrcファイルの中身を攻撃者に送信する。通常.npmrcファイルにはnpmでパッケージを公開する際のアクセストークンが含まれる。

悪意あるパッケージのバージョンはeslint-scope@3.7.2 並びに eslint-config-eslint@5.0.2であり、すでに両方共npmから非公開になっている。このパッケージが使っているpastebin.comのリンクもすでに取り下げられた。

npmは2018-07-12 12:30 UTC以前に発行されたすべてのアクセストークンをrevokeした。この結果、この攻撃により不正に取得されたすべてのアクセストークンは利用不可能になっているはずだ。

アカウントを不正利用されたメンテナーはnpmパスワードを複数の他のサイトに使いまわしており、かつnpmアカウントに2段階認証を有効にしていなかった。

我々、ESLintチームは今回の出来事について謝罪いたします。この失敗を他のメンテナーは他山の石としてnpm全体のセキュリティを高めることを願っています。

影響を受けたパッケージ

  • eslint-scope@3.7、このスコープ解析ライブラリは他の有名な複数のパッケージから依存されている。これには古いeslintと最新のbabel-eslintとwebpackが含まれる。
  • eslint-config-eslint@5.0、これはESLintチームによって内部的に使われている設定用のパッケージであって、よそではほとんど使われていない。

独自のnpmレジストリを運営している場合、これらのパッケージから悪意あるバージョンを非公開にすべきである。npmjs.comレジストリはすでに非公開にした。

攻撃手法

攻撃手法の詳細についてはhttps://gist.github.com/hzoo/51cb84afdc50b14bffa6c6dc49826b3eを参照。

推奨

今回の事例から、我々はnpmパッケージメンテナーとユーザーが今後取るべき推奨事項をいくつか提案する。

  • パッケージメンテナーとユーザーは同じパスワードを複数の違うサイトに使いまわすことをやめるべきである。1PasswordやLastPassのようなパスワードマネージャーは使いまわさなくても済むような利便性を提供してくれる
  • パッケージメンテナーは2段階認証を有効にすべきである使い方のドキュメント。Lernaを使っているのであれば、ここも参照
  • パッケージメンテナーはnpmの公開権限を持つ人間を精査、制限すべきである。
  • パッケージメンテナーはauto-merge dependency upgradesを提供するサービスの使用に慎重を期すべきである。
  • アプリケーション開発社はlockfile(package-lock.json、もしくはyarn.lock)を使い、新しいパッケージの自動インストールを差し止めるべきである。

時系列

  • 問題発生前:攻撃者はおそらくメンテナーがよそで使いまわしたメールとパスワードが流出しているのを発見し、これを使いメンテナーのnpmアカウントにログインした。
  • 2018年7月12日早朝:攻撃者はメンテナーのnpmアカウントで認証トークンを生成した。
  • 2018-07012 09:49 UTC: 攻撃者は生成された認証トークンを使い、eslint-config-eslint@5.0.2を公開した、これには悪意あるpostinstallスクリプトが含まれ、このスクリプトはローカルマシンの.npmrcの認証トークンの取得を試みる。
  • 2018-07-12 10:25 UTC: 攻撃者はeslint-config-eslint@5.0.2を非公開にした。
  • 2018-07-12 10:40 UTC: 攻撃者はeslint-scope@3.7.2を公開した。これには悪意あるpostinstallスクリプトが含まれる。
  • 2018-07-12 11:17 UTC: ユーザーがeslint/eslint-scope#39"を投稿、ESLintチームに問題を通知。
  • 2018-07-12 12:27 UTC: pastebin.comにある悪意あるコードが貼り付けられたリンクが取り下げられた。
  • 2018-07-12 12:37 UTC: ESLintメンテナーから連絡を受けたnpmチームはeslint-scope@3.7.2を非公開にした。
  • 2018-07-12 17:41 UTC: ESLintチームはeslint-scope@3.7.1のコードをeslint-scope@3.7.3として公開した。これによりキャッシュは新しいバージョンを使えるようになる。
  • 2018-07-12 18:42 UTC: npmは2018-07-12 12:30 UTC以前に生成されたすべてのアクセストークンをrevokeした。

リンク

2018-07-11

C++20の汎用エイリアス宣言の提案

P0945R0: p0945r0: Generalizing alias declarations

提案に誤りが有りすぎる。

C++のドラフトに入る見込みが高そうな提案に、汎用エイリアス宣言がある。

C++では、名前に別名をつけることがよく行われている。

型はtypedef指定子やエイリアス宣言によって別名を付けられる。

typedef int type ;
using type = int ;

関数は転送関数を書くことにより、実質別名を付けられる。

int f( int x ) ;

int g( int x )
{
    return f(x) ;
}

ただし、値は完璧に転送できないし、関数のアドレスも異なるものになってしまう。

変数はリファレンスで別名を付けられる。

int x = 0 ;
int & y = x ;

非staticデータメンバーはストレージを消費せずに別名をつけることができない

enumeratorはconstexpr inline変数によって別名を付けられる。

enum { value } ;

constexpr inline auto flag = value ;

ただしinline変数は名前空間スコープでしか使えない。

名前空間は名前空間エイリアスにより別名を付けられる。

namespace a { }

namespace b = a ;

型テンプレートはエイリアステンプレートで別名を定義できるが、デフォルトテンプレートパラメーターまで再現しなければならない。

template < typename T, typename Allocator = std::allocator<T> >
using vec = std::vector<T, Allocator> ;

ただし、この別名は別のテンプレートとして解釈されてしまう。

コンセプトは別のコンセプトを定義すれば別名を付けられる。

template < typename T >
concept newConcept = oldConcept<T> ;

名前の種類によって別名を宣言する文法が異なるし、単なる別名以上の意味を持つものもある。

この提案では、別名の宣言をエイリアス宣言に集約する。


using alias_name = name ;

型は今までどおりだが、その他

 型、今までどおり
using type = int ;

// 関数
int f(int) ;
using g = f ;

// 変数
int x = 0 ;
using y = x ;

// 非staticデータメンバー
template < typename Type, typename Value >
struct map_node : std::pair<Type, Value>
{
    using std::pair<Type, Value>::pair ;

    using key = first ;
    using value = second ;
} ;

[]{
    map_node< int, std::string> n( 123, "123") ;
    n.key ;
    n.value ;
} ;

// enum

enum { value } ;

using flag = value ;

// 名前空間

namespace a ;
using b = a ;


// 型テンプレート

using vec = std::vector ;

vec<int> v ;

// コンセプト

using newConcept = oldConcept ;

だいぶすっきりする。とくに非staticデータメンバーがよい。

2018-07-10

C++に提案されている静的例外

C++に静的例外が提案されている。

[PDF] P0709R1: Zero-overhead deterministic exceptions: Throwing values

例外はそのパフォーマンスへの影響が懸念され、一部のC++プロジェクトではコンパイラーオプションによって例外自体が無効化されていた。

これは由々しき事態だ。というのも、例外は標準C++の機能の一部であり、標準ライブラリは例外の存在を前提にして設計されている。例外が無効化されているということは、それはもはやC++ではない。C++風の別言語を使っていることになる。

なぜ例外は忌避されるのか。例外のパフォーマンスが非決定的だからだ。例外の実装はスタックからの確保ではなくヒープからの動的なメモリ確保が必要で、例外のキャッチにはRTTIによる型情報の比較が必要だ。

ifとgotoによるエラー処理のパフォーマンス特性は決定的に見積もることができるが、動的メモリ確保のパフォーマンス特性は決定的に見積もることができない。非決定的なパフォーマンス特性を持つ処理は、例えば数ミリ秒以内に必ず処理を終えなければならないような状況で使うことはできない。

この提案では、従来の例外を動的例外とし、新たに静的例外を追加して、例外のパフォーマンスを決定的にする。

まず、静的例外では例外としてthrowできる型が制約を受ける。特別に用意した何らかのstd::error型を投げる。このerror型は内部的には整数型で、デストラクターを実行する必要がなく、サイズは最大でもポインター2つ程度を想定している。標準はこのような型をrelocatableな型として規定する。

この標準のerror型はstd::error_codeを拡張したようなクラスで、様々な一般的にエラーに用いられるカテゴリーわけされた整数を返すことができる。このerror型はC++の標準の例外型は数値で表現できるようになっているので、静的例外と動的例外は標準の範囲であれば相互に変換可能になっている。

静的例外を扱う関数、静的例外関数を追加する。静的例外関数は静的例外指定によって明示的に指定する必要がある。提案では仮に、thorwsキーワードを用いる文法を提案している。


string f() throws
{
    if ( is_error() )
        throw error::something ;
    else
        return "hoge"s ;
}

静的例外関数はあたかもnoexcept(fase)が指定されたかのように振る舞う。したがってnothrow系のtraitsもそのように振る舞う。

静的例外関数が例外を外に投げる場合、例外を従来のスタックアンワインディングを伴う例外の仕組みを使わず、戻り値で返す。つまり静的例外関数はunion { R ; E ; } + boolのような型を内部的に戻り値として返す。ようするにexpected<T,E>のような型と同等の機能を提供する型を返す。

静的例外というのはerror型の値に変換できる値を投げるthrow式のことだ。それ以外のthrow式は動的例外となる。

// 静的例外
throw error::foobar ;
// 動的例外
throw "error"s ;

静的例外関数のなかで静的例外がthrowされ、その関数のローカルに対応する例外ハンドラーがある場合、該当する例外ハンドラーにgotoでとんだものと同じ挙動をする。

 string f() throws
{
    try {
        // ローカルのcatchにgotoで飛ぶのと同じ
        throw error::something ;
    } catch ( error e )
    {
        // ここにgotoで飛ぶのと同じ
    }
}

静的例外関数のローカルに該当する例外ハンドラーがない場合、errorは戻り値として返される。そのため、上の関数は実際には、union { string ; error ; }という型とどちらのunionメンバーが有効かを示すbool値を返したものとみなされる。これは従来のreturnと同じ仕組みで実装できるので、パフォーマンス特性も決定的になる。

静的例外関数が別の静的例外関数を呼び出し、静的例外によるerror型が返った場合は、その場で静的例外がthrowされたものとみなして処理する。

string f() throws 
{
    // 内部的にはerrorがreturnされる
    throw error::something ;
}

string g() throws
{
    try { return f() ; }
    catch( error e )
    {
        // ここにgotoで飛ぶ
    }
}

静的例外関数の中で従来の動的例外が投げられた場合、それが直接throw式で投げられたにせよ、呼び出した関数を通じて間接的に投げられたにせよ、直ちにその場でキャッチされ、適切な例外ハンドラーが選ばれる。

string f() ; // 非静的例外関数
string g() throws ; // 静的例外関数

string h() throw
{
    try {
        auto a = f() ;
        auto b = g() ;
        return a + b ;
    }
    // 静的例外
    catch( error e )
    {
    }
    // 動的例外
    // 従来の非決定的なパフォーマンス特性を持つ
    catch( std::bad_alloc e )
    {
    }
}

もし、静的例外関数から従来の動的例外が投げられ、関数の中に該当する例外ハンドラーがない場合、例外の型がerrorであれば静的例外としてreturnされ、それ以外であればstd::exception_ptrで束縛されてreturnされる。

string fail()
{
    throw "always error"s ;
}

string f() throws
{
    return fail() ;
}

この関数fは、string型をstd::exception_ptrで束縛してreturnする。

std::exception_ptrはC++11から追加された例外のオブジェクトを束縛できる機能だ。もう7年前の大昔に追加された機能なので読者は当然知っているはずだ。

呼び出した静的例外関数がstd::exception_ptrをreturnした場合、その場でただちに例外オブジェクトが取り出され、例外処理が行われる。もし例外オブジェクトがerror型の場合は静的例外が、そうでない場合は動的例外として処理される。

一部のC++の標準例外は、error型に変換される。例えばstd::bad_allocはerror型である(名前は仮のものだが)std::errc::ENOMEMに変換される。

非静的例外関数が静的例外関数を呼び出して例外を受け取った場合、もしerrorに対応するstd::exception型(たとえばerrc::ENOMEMからstd::bad_alloc)があるならば型を変換して動的例外がthrowされる。std::exception_ptrの中身がerror型の場合は取り出してerror型がthrowされたものとして処理される。それ以外の例外は動的例外がthrowされる。

string f() throws
{
    // 動的メモリ確保に失敗するコード
    // return std::errc::ENOMEM ; と同じ
    string s( std::numeric_limits<std::size_t>::max(), 'x') ; 
    return s ;
}

string g()
{
    // throw std::bad_alloc; と同じ
    return f() ;
}

この提案は従来の動的例外と組み合わせて使えるパフォーマンス特性が決定的な、つまりifとgotoを使うのと全く変わらないエラー処理を、例外の文法で実現する、静的例外を提案するものだ。これによりゼロオーバーヘッドの原則を満たした例外が扱えるようになる。

興味深いので入ってほしい。例外はすべてのC++で有効化されるべきだ。例外の使えないC++はC++風の別言語なので、利用者が分断されてしまう。