新・日々録 by TRASH BOX@Eel このページをアンテナに追加 RSSフィード

2016-07-16

プログラミングでのコピペの作法

プログラミングコピペというと、次の2通りの解釈が成立するが:

  1. ソースコード中で、似たような処理を1つにまとめずに、コピペして量産していくこと。
  2. やりたいことに近いサンプルコードやスニペットをネットで探して、コピペして利用すること。

――この記事では2番目の方のコピペにおける作法について書こうと思う。

……1番目の方のコピペ作法? 無いよ。というか1番目のコピペをするヤツは「3日に1回足の小指をタンスの角にぶつけてしまう」呪いにかかってしまえ!

コピペ元コードのライセンスに留意する

コピペ元コードのライセンスを調査して、コピペ先コードに取り込んでも問題ないことを確認した上で、ライセンスに応じた取り込み方をすること。

コピペ元コードの内容を理解する

検索して見つけたサンプルやスニペットは、手放しでそのまま流用できる代物ではない。

  • エラー処理が省略されているかもしれない。
  • (自分がやりたいことからすると)余計なことをしているかもしれない。
  • バグがあるかもしれない。
  • 間違いではないが、ちょっと微妙なコードを含んでいるかもしれない。
    • 例えば、配列の要素を連結した文字列を作るのに、joinのような便利な標準の関数メソッドを使わずに、for文でループして1つずつ連結しているとか。
  • 自分の環境では利用できない技法かもしれない。

この辺の判断を下すためにも、コピペ元コードを読み、内容を十分に理解しなくてはならない。

理解できないなら、コピペするのは諦めたほうがよい。後で問題が起きたとき、結局は中身を理解しなくてはならないのだから。

コピペ元コードから必要な部分だけ抽出する

検索して見つけたスニペットには、大抵は自分が実現したい内容にとって不要な処理が含まれている。自分が本当に必要としている部分だけで構成されていることは皆無だ。

だから、不要な部分は徹底的に排除しなくてはならない。不要な部分が残っていると、後でそのソースコードを引き継いだ別の開発者が発狂するだろう。*1

排除するためには、要不要を判断しなくてはならない。要不要を判断するためには、コピペ元コードの内容を理解しなくてはならない。

コピペ先コードのコーディングスタイルに合致させる

検索して見つけたスニペットは、その作者にとって書きなれたスタイルで記述されている。十中八九、コピペ先コードのスタイルとは別物だ。

コピペする際には、コピペ先のスタイルに書き直すこと。

……3〜4つのサンプルコードをコピペして、スタイルを統一せずに組み合わせたコードを、後で解析するのは地獄ですぜ、旦那。実際、地獄だった。*2

コピペ元コードの悪いところを直す

コピペ元コードがスバラシイものであるとは限らない。仕様・機能は十分満たしているが、コード自体はぐだぐだなことも多い。

そういう悪い部分を引き継ぐ必要はない。コードを取り込む際に直してしまうべきだ。

個人的には、VBAOfficeオートメーション)やVBScriptWSHによるWindowsサーバ管理)のスニペットサンプルコードは、割と「機能は十分だが、コードの中身はちょっと微妙」な代物も多いように思う。VBAは、EUC(エンドユーザコンピューティング)の悪い側面が出ちゃった結果、サンプルコードの品質が微妙なことになった気がする。

まとめ

以下の手順にしたがい、清く正しく美しくコピペすること。

  1. コピペ元コードのライセンスに留意する
  2. コピペ元コードの内容を理解する
  3. コピペ元コードから必要な部分だけ抽出する
  4. コピペ先コードのコーディングスタイルに合致させる
  5. コピペ元コードの悪いところを直す

*1:というか私も発狂しそうになった。だって、全体の3分の1ぐらいが不要なコードだったから。3〜4つのコードをネットからコピペしてきて、キメラのごとく悪魔合体させた代物でねぇ(以下、昔話が続く……)。

*2:400行ちょっとのVBScriptのコードだったのだが、暇を見てこつこつ実施したとはいえ、内容の理解とリファクタリングに2週間近くかかった。

2016-07-11

Windows 7再インストール最速マスター 2016-07版

Windows 7のロールアップ・パッケージも出たことなので、これから古いWindows 7 PCを再セットアップしたり、仮想マシンを構築したりする際の、作業時間短縮を視野に置いた作業手順をまとめておこうと思う。

本当はSP+メーカーなどでHotFix専用インストールCDなどを作っておくとよい気がするが、そこまでやる気がない場合でも、この手順で作業しておくと、Windows 7インストール後のWindows Updateにかかる時間が短縮される。というか実際に短くなった。

事前準備

再セットアップ後に適用する大物のパッチ類を事前にダウンロードしておく。マイクロソフトダウンロードセンターMicrosoft Update カタログなどから集めてくるとよい。

  • Windows 7 SP1(無印Windows 7だった場合)
  • KB3020369
  • KB3125574
  • 最新のWindows Update Agentの更新プログラム
    • KB3125574よりも新しいものが出ている場合のみ。2016-06時点では存在しない。
  • Internet Explorer 11
  • IE11用の累積的なセキュリティ更新プログラムの最新版
    • コレを書いている時点では、2016-06の定例アップデート配信されたKB3160005が該当する。
  • .NET Framework 4.6.1
  • Officeを利用している場合は、当該バージョンのサービスパックなど。

ちなみに、手元のWindows 7 64bit版では、IE11Microsoft Update カタログからパッチを落とせなかったのだが、互換表示設定に「microsoft.com」を追加した上で、Microsoft Update カタログのサイトを「信頼済みサイト(セキュリティのレベル:中)」に登録したところ、無事パッチを落とせるようになった。どうやら、セキュリティレベルの設定を中にするか、「保護モードを有効にする」をOFFにするか、もしくはどちらも変更しておかないと駄目なようだ。

Windows 7インストール/再セットアップ後の作業

インストールや再セットアップ自体は、基本的にマニュアル通りに実行すればよい。ただし、注意点として、Windows Updateの設定を尋ねられた場合は、一旦OFFにしておくとよい。

以下、インストール/再セットアップ直後に実施する作業を時系列順に挙げる。

  1. ネットワークから切り離し、オフライン状態にする。
  2. Windows Updateを完全に無効化する。
  3. Windows 7 SP1を適用する(無印Windows 7だった場合)
  4. KB3020369をインストールする。
  5. KB3125574をインストールする。
  6. 最新のWindows Update Agentの更新プログラムがあるなら、インストールする。
  7. Internet Explorer 11をインストールする。
  8. IE11用の累積的なセキュリティ更新プログラムをインストールする。
  9. .NET Framework 4.6.1をインストールする。
  10. Officeを利用している場合は、当該バージョンのサービスパックを適用する。
  11. ウイルス対策ソフトを入れる(または入れ替える)場合は、ここで実施する。
  12. ネットワークに接続する。
  13. ウイルス対策ソフトを入れた場合は、ここで手動アップデートする(可能な場合)。
  14. Microsoft Updateを有効にする。
    1. 上記操作でWindows Updateが開始するので、そのまま続行して適用する。
    2. 以後、「更新プログラムの確認」でWindows Updateを何回か繰り返して、更新プログラムが残っていない状態にする。
  15. Windows Updateの更新設定を元に戻す。

事前にオフラインで大物のパッチを適用しておくと、Windows Updateにかかる時間や回数が結構短くなる。

その理由は2つある。1つ目は、Windows Update AgentやIE11パッチが適用されることで、Windows Updateに異常に時間がかかる不具合が修正されるためだ。2つ目は、システムに適用済みのパッチが多いので、パッチの大量ダウンロードと、それに付随して発生するスワップアウトが起こりにくいためだ。

2016-07-04

Microsoft Update時に再起動が求められる理由 初級編

Windows Update/Microsoft Updateの時、システムの再起動を求められることが多い。なぜ再起動が必要なのか、再起動しなくてはならないものなのか、ちょっと書いてみる。

といっても、私は別にWindowsについて詳しくないし、OSや情報セキュリティについて正式な勉強をしたことのない人なので、突っ込んだ話はできない。

なので、Windowsに限らずMac OS XLinuxでも通用するだろう、一般的なことを大雑把に書く。例のごとく、より詳細かつマニアックな中級編以降を誰か書いてくれるものと期待している。

推奨読者レベル:基本情報技術者レベルの「テクノロジ系:コンピュータシステム」の知識があること。

前提知識

現代の大抵のコンピュータでは、プログラム内蔵方式が採用されている。実行するプログラムは主記憶装置に置かれていて、CPUは「主記憶装置から命令を1つ読み出し、実行し、次の命令を1つ読み出し……」といった按配にプログラムを実行していく(逐次制御方式)。

この構図は、WindowsMac OS Xなどのオペレーティングシステム(以下、OS)も、OS上で実行されるアプリケーションソフトウェア(以下、アプリケーション)も同じだ。どちらも、CPUが実行する命令は主記憶装置上にある*1

WindowsMac OS Xを動かすようなコンピュータでは、主記憶装置として半導体メモリが使われている。半導体メモリは安価で高速だが、通電状態でないとデータを保持できない。電源を止めると、データは消えてしまう。

そこで、OSアプリケーションハードディスクドライブHDD)やソリッドステートドライブ(SSD)などの補助記憶装置にプログラムを保存しておき、実行する時に主記憶装置に読み出すようになっている。

OSは、コンピュータ起動時に補助記憶装置から主記憶装置に読み出され、実行される。アプリケーションは、OSの起動が完了した後に、任意のタイミングで補助記憶装置から主記憶装置に読み出され、実行される。

つまり、プログラムAを実行している時、その実体は、補助記憶装置上のプログラムa(雛形のようなもの)と、主記憶装置に読み出されたプログラムa'(いわゆる「計算プロセス」とでもいうべきもの)の2つが存在することになる。多重起動可能なアプリケーションの場合、主記憶装置上にプログラムa'が2つ以上存在する状況もありうる。

セキュリティ更新では何をしているか?

Windows Updateや、Mac OS Xセキュリティアップデートでは、概ね次のようなことをやっている。

  1. 補助記憶装置上のプログラムの差し替え
  2. 実行中のプログラムの終了と再実行(≒再起動

プログラムは補助記憶装置から主記憶装置に読み出され、実行される。なので、補助記憶装置上のプログラム脆弱性対策が施された新しいものに置き換えてしまえば、少なくとも次回プログラムを起動した際には、更新されたバージョンが実行されることになる。

ただし、実行中のプログラムについては、CPUが実行している実体は、補助記憶装置上のプログラムが更新される前に主記憶装置に読み出された「更新前のプログラム」だ。補助記憶装置上のプログラムを更新しただけでは、主記憶装置上のプログラムは更新されない――つまり、実行中のプログラムには脆弱性が残ったままだ。

では、主記憶装置上のプログラムを更新するには、どうすればよいか?

一般的には、実行中のプログラムを一旦終了し、再度起動することで、脆弱性対策が施されたバージョンが実行されるように対応することが多い。最近のブラウザなどの、自動更新機能を持つアプリケーションにおいて、バックグラウンドで自動更新処理が実行された後にアプリ自体の再起動が促されるのは、この理由による。またLinuxのパッケージ管理コマンドでシステムを更新した際に、ログ等にデーモン再起動が記録されているのも、同じような理由からだ。

OSへのセキュリティ更新適用と、システムの再起動

OSへのセキュリティ更新適用でも、やることは「補助記憶装置上のプログラムの差し替え」と「実行中のプログラムの終了と再実行」だ。

問題は、「実行中のプログラムの終了と再実行」をいつ行うかだ。というのも、OSコンピュータ起動時に実行が開始され、シャットダウン時に終了する。OSは、コンピュータ稼働中にシステムのリソース管理を行うプログラムだ。コンピュータを稼働させたまま、途中でOSのみを再起動することはできない。

そこで、補助記憶装置上のOSプログラムを更新した後にコンピュータ再起動させる。OSは、コンピュータ起動時に補助記憶装置から主記憶装置に読み出されので、再起動後の主記憶装置上のOSプログラムは、補助記憶装置上のものと同様の、脆弱性対策が施された更新版になる。

この点は、WindowsMac OS XLinuxFreeBSDなどのいずれも同じだ。OS(正確にはカーネル)が変更されたなら、更新されたOSが実行されるように、コンピュータ再起動する必要がある*2(ただし、OSの種類によってカーネルの更新が発生する頻度に差がある*3)。

主記憶装置上のプログラムを直接修正できないか?

さて、補助記憶装置上のプログラムを差し替えた後に、主記憶装置上のプログラムを修正版にするために、プログラム再起動するのだった。では主記憶装置上のプログラムを直接修正することはできないだろうか? 主記憶装置上のプログラムを修正できるなら、再起動は不要になるはずだ。

技術的には、主記憶装置上のプログラム自体に修正を適用する方法も無くはない。ただし、以下ような制約があるため、この方法は一般的ではない。どちらかといえば、エンタープライズ向けの、高可用性が要求されるプログラム(それだけコストをかけることが許される環境)向けの話となるし、そのような環境でも常にその方法が使えるとは限らない。

  1. そのプログラムを実行しているプラットフォームのサポートが必要。
  2. 技術的な制限により、この方法では対応できないケースがある。
    • そもそも、プログラム・カウンタを含めて、機械語レベルの命令の実行位置や、関数呼び出しでのジャンプ先/復帰先をアドレス値で管理している以上、プログラム実行中に、プロセス中の機械語のレイアウトが急に変更されてしまうと、プログラムの実行が滅茶苦茶になってしまう訳で。
    • あと、やはり実行中に、プロセス中の大域変数が配置されている部分のオフセットが変化したり、内部変数の追加で「スタックに詰まれているデータ」と「スタックに詰まれるべきデータ」に齟齬が生じた場合も、大惨事になりかねない。
    • Windowsのホットパッチや、Linuxのライブパッチ機能(kpatch)では、原理的には「関数呼び出し部分にて、何らかの方法で『本来呼び出されるはずの関数』から『実際に呼び出されてほしい関数』に挿げ替える」ということを行っていて、これによって「不具合/脆弱性が含まれる機械語群」ではなく「不具合/脆弱性が解消された機械語群」が実行されるようにしている。
    • 逆に言えば、上記のような「関数の挿げ替え」レベルでの対応が難しいケースでは……。
  3. パッチを提供する側のコストが高くなる。
    • 主記憶装置として半導体メモリを使っている以上、主記憶装置上のプログラムに適用された修正はシャットダウン時にプログラムごと消えてしまう。補助記憶装置上のプログラムも忘れずに差し替えておく必要がある。
    • 主記憶装置上のプログラムと補助記憶装置上のプログラムでは、修正を適用するアプローチが違うため、それぞれ別々のパッチが必要となる。つまり、1つの問題に対して2つのパッチを開発・テストしなくてはならない。単純に考えると、コストが2倍となる。要求品質が高いプログラムの場合、開発した2つのパッチについて、「パッチ適用後のプログラムの振る舞いが全く同じか?」ということまで検証しなくてはならないかもしれない(その分だけ、新たな開発コストが発生する)。
    • 主記憶装置上のプログラムに修正を適用するためのパッチの開発コストは、補助記憶装置上のプログラムへのパッチよりも高い。

例えば、LinuxKernel 4.0以降には、ライブパッチ機能が組み込まれている。今後、開発が進むことで、Linuxディストリビューションにてライブパッチによる修正が提供されるようになるかもしれない。

かもしれないのだが……例えばRHELで何らかの契約を締結している顧客向けに提供されることはありうるように思うが、果たして全くのコミュニティ・ベースで無償で提供されるものだろうか? 個人的には、ちょっと考えにくい気がする。

Windows特有の事情1:どこまでがOS

Windows特有の事情として、LinuxなどではOSとは独立したプログラムとして提供されている機能が、OSと比較的密接なプログラムとして提供されることがある、という点がある。

現在は割合と改善されているが、かつてはInternet ExplorerのようなブラウザWindows内部との結合度が高く、IEの巻き添えでWindowsまで落ちるようなことがあった。

このような環境では、他のOSではアプリケーション単体の更新・再起動で済むようなケースでも、WindowsではOS自体の再起動まで必要となることがある。

一方、LinuxFreeBSDなどでは、WindowsではOSが提供している機能が、OSとは独立したデーモンなどとして提供されていることが多い。この場合、当該デーモン再起動だけで済む。OS本体(カーネル)が変更されない限りコンピュータ自体の再起動は不要となる。

今ではLinuxでも再起動が必要な機会が増えた感じがあるが、少なくともかつての「OS再起動の回数」の差は、OSの責務の幅による部分も大きかったように思う。

Windows特有の事情2:実行ファイルのロック

これまたWindows特有の事情として、「実行中の実行ファイル(*.exeや*.dllなど)への上書きや削除ができない」というものがある。*4

このため、Windows Updateにて補助記憶装置上のOS絡みの実行ファイルを完全に差し替えることが難しい。なぜなら、これらのファイルはOSの実行中――コンピュータを起動してからシャットダウンするまでの間ずっと、OS関連のプログラムが使用している可能性があるからだ。

これは推測だが、上記の問題を回避するために、システムを更新する際には、シャットダウン中や再起動時のブート中に、通常のOS稼動状態とは異なる状態に一旦遷移して更新処理を行っているようだ。

まとめ

セキュリティ更新を「現在実行中のプログラム」にまで適用させるには、プログラム再起動する方法が確実で、これがOSの場合「プログラム再起動する=コンピュータ再起動する」となるのです。

ということで、Windows Updateなどのセキュリティ更新を実行して、OSアプリケーション再起動要求されたら、なるべく早めに再起動すること。でないと脆弱性の修正が「実行中のプログラム」にまで適用されず、危険なままとなってしまう。

*1:仮想記憶が絡んでくると微妙なのだが、今回のテーマでは気にする必要がないので無視する。後段に書いているが、仮に仮想記憶で一時的に補助記憶装置にデータを置いていたとしても、コンピュータをシャットダウンする際に削除されるので、主記憶装置上のデータと同じ条件だといえるからだ。

*2:ただしLinuxについては、Kernel 4.0にてライブパッチ機能が組み込まれたこともあり、今後事情が変わってくる可能性がある。

*3:とはいえ、同じLinuxでも、Ubuntuデスクトップ版を使うのと、Debianのstableをサーバとして運用するのでは、再起動の頻度は違うからなあ(Ubuntuデスクトップ版では意外と再起動の機会がある気がする)。この辺は各ディストリビューションのポリシーによるところが大きくて、新機能をガンガン取り入れていくポリシーだとカーネルも頻繁に更新されるし、逆に保守的なポリシーだと脆弱性対応のバックポートしか受けつけないので更新頻度は低くなる。

*4:正確には、OS本体ではなくファイルシステムに起因する制限であるようだ。

2016-06-27

今までどのくらいプログラミング言語を触ってきたか(3秒で挫折したものものも含む) Ver.8

2016/06/27現在のステータス。id:eel3:20150614:1434290001 から1年経て、こうなっている。

なおCSSHTMLXMLは除外*1

よく使っている

AWK (Gawk)
単純なテキストレコードの処理にはAWKで十分。自作ツールをAWKGawk単体で実装することは皆無なものの、シェルスクリプトMakefileの中にコードを埋め込んで他のコマンドと組み合わせて使う機会は依然として多い。シェル上でワンライナーでデータ処理するときにも重宝している。これはこれで十分AWKらしい使い方だよね?
C++
ちょくちょくお仕事で使うが、本職のC++使いではない。C++11やC++14は非常に便利で、better Cでも使う価値があると思う今日このごろ。C++の標準ライブラリは、C++03の時代からC言語の標準ライブラリよりはるかに充実していたが、C++11でさらに充実しちゃってどうするのよ?*2 ラムダ式とかautoによる型推論とか使えるようになって大変ですよ。低水準の処理を行いつつも便利な機能で実装時間を短縮できるのは便利。だけど機能多すぎ/複雑すぎなところはなんとかならないものか。強力な反面、使い手を選ぶ言語だ。
C言語
お仕事での主力言語。シンプルかつ低水準の世界が垣間見れるところが割と好き。とはいえ最近の他の言語と比較すると、シンプルすぎて安全機構が欠けていたり標準の便利機能が少なかったりするので、入門用の言語としては薦められない。にもかかわらず、プログラミング未経験者向けのC言語の本は毎年出版されている――謎だ。クロスプラットフォームモジュール屋としては、現実解としてC89を採用しているものの、そろそろC99とかC11とか次世代の言語とか主流になってほしいところ。えっ、C++なら今からでも大丈夫だって? 冗談がきついなあ、10年以上前の秘伝のコンパイラを使ってる現場じゃあC++03だって無理無理。
DOSバッチファイル
プログラミング言語に含まれるかどうか不明だが、含めてしまう。ちょっとした自動化や、複数ツールを組み合わせて使うときのラッパーとしてよく使う。コマンドプロンプトはシバン(shebang)に対応していないので、スクリプト言語で書いたツールを起動するラッパーとしても多用している。
make (Makefile)
プログラミング言語に含まれるかどうか不明だが、DSL扱いで……いやGNU Makeはそこそこプログラミング言語的か。GNU Make 4.0はさらにプログラミング言語的だな、特にGNU Guileなところが。先人の遺産をコピペしてガシガシ書き換えるだけだった私も、FizzBuzzを切欠に本格的にGNU Makeを触り始めた。伝統的なmakeやNetBSD Make(pmake)やNMAKEとは随分異なるのね。もう素のmakeは書けないかもしれない :) まあでも私はGuileのコードが書けないので、その分だけはまだまだ素のmakeやpmakeに近いはず――といいつつも、最近書いたNMAKEも独自拡張アリアリで使ってたな。pmakeも独自拡張アリアリになるから、要は素のmakeでは書けないのか。
Objective-C, Objective-C++
時代の流れに逆らえず、iOS向けの試作とかが発生するようになった――あれ、でも主に弄っているのはMacアプリのコードだな。最近流行の言語と比べると良くも悪くも80年代的だが、アプリケーションプログラミング用としてはC言語よりマシだし、C++ほど複雑怪奇*3ではない。まあ、アプリケーション開発向けの充実感はApple謹製のフレームワーク・各種ライブラリのパワーによる面も大きいわけで、その肝心のフレームワークMaciOS以外の開発で使用できないのが悲しいところ*4。あとフレームワーク込みでObjective-Cを勉強するにはMacが必要なので、貧乏人にはちょっとつらい。言語的には、Objective-Cハイブリッドな所は好きだが、Objective-C++はハイブリッドすぎて微妙。せめてbetter CなC++にとどめたObjective-C++にしてほしい。C++のクラスとObjective-Cのクラスを、C++ラムダ式Objective-Cのブロック構文を同時に使うのは地獄だ。便利ではあるんだけど、ねぇ。
Ruby
自作ツール実装にて、AWK代替言語の最有力候補。テキスト処理でも重宝するが、バイナリデータへの変換が絡んでくるとAWKよりもRubyを使った方が効果的だ*5。そろそろirbを電卓代わりに使うスタイルも板に付いてきた気がする。to_s(16)やto_s(2)で基数変換して表示できるところが好き。
sed
プログラミング言語に含まれるかどうか不明だが、DSL扱いで*6。テキスト処理用。シェルスクリプトMakefileにて他のコマンドと組み合わせて使う。というか正規表現でのテキスト置換以外の機能を使った記憶が……あったな、dとiとpと=とブレースによるグループ化ぐらいだが。私のレベルではsedでFizzBuzzを書けないので、sedで難しい処理を記述しないようにしている。
シェルスクリプト (/bin/sh)
プログラミング言語に含まれるかどうか不明だが……いや、私的にはシェルスクリプトは立派なプログラミング言語だ。基本的な用途はバッチファイルと同じくちょっとした自動化や複数コマンドを組み合わせて使うときのラッパーだが、実現できる内容は遥かに多い。言語本体(?)がバッチファイルよりも高機能だし、Unixユーザランドはコマンドが充実している。その意味ではMSYSよりもCygwinで環境構築した方がマシだと思う。CygwinやMSYSでは、主要な処理をシェルスクリプトで記述しておき、bashからはシェルスクリプトを利用し、コマンドプロンプトではラッパーのバッチファイル経由でシェルスクリプトを叩く使い方をしている。ただWindows上では処理速度が妙に遅くなる点が不満だ。

あまり使っていない

bash
最近はデフォルトシェルbashな環境も多いので、自分用のツールぐらいは素の/bin/shではなくbashで書いても大丈夫な気がしてきた。shよりbashの方が遥かに便利だからなあ――PerlRuby等には負けるけど。bashスクリプトを書くときの唯一の欠点は、メジャーバージョンごとの差異や各ディストリでのビルドオプションの違いにより、同じbashという名前でも実は千差万別なところだと思う。PerlRubyのバージョンは気にするけど、これがシェルになると意外とバージョンに無頓着になってしまう。なんでだろう?
C#
かつて、勉強を兼ねてC# 2.0を少し触ろうとするも未完に終わった過去をもつ私。あらためてVisual Studio 2013をインストールして、また少しだけ触ることに。言語仕様的にはC# 5.0の環境だが、使用する機能はC# 4.0相当だろうか。変数型推論ラムダ式LINQデフォルト引数は便利っすね。それと.NET Frameworkの機能数は反則ものだが、所々に微妙に抽象化が行き過ぎたAPIが見られるのは気のせいだろうか? それにしても、クラスが必須ではないC言語C++に慣れてしまった弊害か、アプリケーション・メインエントリすらclass内に定義しなくてはならないC#には、なかなか慣れない。Javaよりはマシなのだが。
D言語 2.x
仕事柄「C/C++の次のシステムプログラミング言語」はそれなりに興味の対象で、Go言語ほどではないが、D言語も気になる存在だ。D言語シンタックスがC・C++に近いだけでなく、コーディングしている時のアプローチ・判断についても、CやC++での流儀がそこそこ通用しやすい気がする。少なくとも、Go言語でコーディングするよりは、文化的背景の違いによるモヤモヤは感じにくい。あと、標準ライブラリを使ってテキストフィルタを書いたところ、エラー処理を1〜2ヶ所のtry - catchにスッキリまとめることができて、ちょっと驚いた。throwされる例外のメッセージ文字列が、ちょうどよい塩梅の内容だったため、メッセージを変更する(いったんcatchして、再throwする)必要がなかった。ちょっと残念なのは、マルチバイト対応だが……。
flex (lex)
プログラミング言語に含まれるかどうか不明だが、DSL扱いで。字句解析用のツールという印象が強かったのだが、よく考えてみたら、flexってsed(1)のよくある使い方と同様に「正規表現でパターンマッチング --> 何らかのアクション」ということをやるためのツールだった。ただ単に、「何らかのアクション」をC言語で書けることと、flex自体ではパターンマッチングをせずに「パターンマッチングするC言語のコード」を生成することが少々風変わりなだけ。grep(1)やsed(1)その他で小ツールを実装して運用しつつ、性能が求められたらflexで専用ツール化するとか――夢が広がるな、いまさらながら。
Go
寡作ながらもいくつか小ツールを書いてみたが、標準ライブラリが充実しているコンパイラ型言語っていいっすね。C言語に比べればC++の標準ライブラリも充実しているが、どちらかといえばプリミティブな機能が中心だ。PythonRubyばりの標準ライブラリを抱えているGoには及ばない。その辺は、やはりCプログラマ(特にCでフィルタデーモンの類を書く層)には受けそうな言語だと思う。並列処理周り(goroutines)とかARM対応とかが気になる。ソフトリアルタイム限定だが「組み込みLinux + Goで書いたデーモン」とかどうだろう? ただメモリを食うらしいという噂がどうなったか気になる――64bit環境では解消されるという話だったようだが、32bit環境でも解消されるようになったのだろうか? 組み込みでは現時点では逆立ちしたって64bit CPUはありえないからなあ、スマホタブレット以外では。
Groovy
JDKがなくてもJava APIを叩くスクリプトを書けるので非常に便利。動的型付け言語っぽくいくもよし、@CompileStaticや@TypeCheckedで型推論するもよし。言語仕様はJavaよりも好みだ。コンソールアプリを書く人としては、オプション引数解析用の機能を標準で持っている点で、GroovyClojureScalaよりもポイントが高い*7。個人的には、IoT時代に「Java VMベース」の言語としてどこに活路を見出すのが、興味深く見守りたいところ。やはりサーバサイドだろうか?
Perl 5
時々、やむをえない事情で触ることがある。だが基本的によく分からない。何というか、あの記号の羅列っぽさに中々慣れないというか、自分は余りに自由度が高すぎる言語は苦手だと気づいたというか。(言語仕様に慣れているなら)半ば使い捨てなテキストフィルタとかをさっと書くには、悪くない言語だと思うのだが。
Python
Perl 5と同様に、やむをえない事情で触ることが多い。Open usp Tukubaiが入っている環境でスクリプトを書くとなると、確実に使える処理系Python 2.xなので、Python 2.xを念頭にコードを書くことになる。しかし日本語を扱うにはPython 3.xの方がよいらしい。うーん、どちらを学べばよいのだろう? Perl 5やRubyと比べると、Pythonではlazyなスタイルが許されず、整然とコードを記述する必要がある。その辺り、Perl 5やRubyとは随分と雰囲気が異なる。Pythonで気になるのは、インデントが必須な言語仕様であるために、シェルスクリプトに埋め込んで使うのが苦痛な点だ。使い方を間違っているのだろうか。
QML
宣伝文句のとおり、QMLはGUIの記述に非常に向いている。それも、単に標準のUI部品(エレメント)を使うだけでなく、少し改造して使うとか、オリジナルのUI部品を作って使うとか、それらを別のアプリケーションに使いまわすとか、そういう時に威力を発揮する。あと、プロパティバインディングやレイアウトのアンカー指定など、画面サイズの変更に追随するUIを作りやすい機能も揃っている。JavaScriptでちょっとした処理も記述できる。とはいえ、やりすぎるとパフォーマンスの罠が……。少なくとも、JavaScriptでゴリゴリコードを書くのはQML的ではない。QMLは宣言的に、シンプルに書くものだ(というか、力技でロジックでゴリ押しすると、色々と罠に嵌る)。個人的には、QDialのようなダイアルのコンポーネントが標準で用意されていたらなあ、と思っていたらQt 5.5で追加された!
Scheme
GaucheWindowsネイティブ環境用バイナリは実験版だが、私が触る分には何の支障もない*8ことに気づいて久しい今日この頃。『Scheme手習い』と『Scheme修行』を購入したので、とりあえずCommon LispではなくGaucheScheme)の勉強をする方向に転換しようか検討*9しているうちに何年たったのやら。Gaucheフィルタ・ライクな小ツールの実装用としても良い感じだ。しかし最も多い利用方法はREPLを電卓代わりにすることだ*10。うーん、作業環境がMac OS XLinuxに移ったなら、大手を振ってGaucheフィルタを書くのだが。
Tcl/Tk
Tclは書き方を忘れた頃にテキスト処理ツールを書いている気がする。Tclは結構独特な言語だ。構文がシェルスクリプトばりに全てコマンドだったり、値が全て文字列だったり、実はリスト構造だったり、意外とTCPソケット通信が得意だったり……。それでも慣れれば結構使いやすい。意外とプロトタイピングに向いている気がする。8.6以降ではオブジェクト指向プログラミングもOKだが、それよりも例外処理用のtry末尾呼び出しの最適化用のtailcallの方が興味深い。しかし、これからメジャーになる可能性は低そうだ。Tkは……小規模なGUIツールをさくっと構築できるところは便利だが、Webアプリ全盛の時代にどれだけ訴求力があるのやら。
Vim script
少し触ってみた分には、exコマンドの拡張(=コマンドの羅列)とは気づかない程度にはプログラミング言語らしいと思う。とはいえ妙なところで嵌ったり微妙に一貫性のない部分があったりするので、その辺りで好き嫌いが別れる気がする。
Windows PowerShell
v5.0も出たというのに、自分も周囲もWindows 7ユーザなのでv2.0で頑張っている。スクリプト言語としてのPowerShellは――またMicrosoftもエライ代物を出してきたものだ。シェルスクリプトなのにオブジェクト指向.NET Frameworkを触れてダイナミックスコープでスクリプトブロック(という名の無名関数)って、無茶しやがって……完全にプログラマ向けじゃないか。あえていえば、コマンドプロンプト上に構築した既存のツールや作業環境との親和性が微妙にイマイチなのが玉に瑕かも(特に文字コードとか)。それにしても、PowerShell 3.0は無理としても、せめて2.0に対応した言語解説本(日本語のもの)が出てくれないだろうか。『Windows PowerShell イン アクション』は良書だが1.0の頃の本なので、他人に薦められないのだ。

最近使ってないが、縁は切れてない

bison (yacc)
プログラミング言語に含まれるかどうか不明だが、DSL扱いで。やっぱり構文解析系統のコードを自作するのは割に合わない――だなんてうそぶきつつ、LALR法とか全く知らないままに、既存のyaccのコードを切り貼りして遊んでいるところ。まだ簡易電卓レベルだが便利さを体感しつつ、さっそくtypo 1文字で痛い目(shift/reduce)に遭った。とりあえず、flexと組み合わせた上でのエラー処理(エラーメッセージの改善)が課題だ。
CASL II
生まれて初めて触れたプログラミング言語その1。何だかんだで、後でCプログラマになってからも低水準での思考ツールとして微妙に役に立っている。まあ考えるための言語であって実用言語ではないけど。仮に実用的な処理系*11があったとしても余りに命令がシンプル過ぎて悶絶するなあ、なんてFizzBuzzしてみて思った。
Java
生まれて初めて触れたプログラミング言語その2。でも、もう忘れてしまった――と思っていたのだが、思い立って昔どこかから拾ってきたツールのコードに手を入れたり、急にAndroid用のサンプルアプリを触ることになったり。うーん、JDKインストールしたり更新したりするのが面倒だ……。とりあえず、構文の見た目は保守的なC++に似ているが中身はC++とは似ても似つかない代物だということは分かった。
Clojure, Scala
JDKがなくてもJava APIを叩くスクリプトを書けるので非常に便利。Scala型推論とか、便利っすね。言語仕様はJavaよりも好みだ。とはいえ、IoT時代にJava VMベースでどこまでメインストリームに居残ることができるのか? ちょっと興味深い。サーバサイドに活路を見出すのだろうか?
JavaScriptクライアントサイド)
組み込み系のCプログラマ世間の流行には逆らえず、クライアントサイドJavaScriptのコード書いてみた。機器のWeb管理コンソールとか、Webアプリとの連携とか。言語仕様的に単体テストしやすい(モックへの差し替えが簡単な)ところが羨ましい。無名関数クロージャも好きだ。
JavaScriptサーバサイド?)
Node.jsやPhantomJSが出てきたこともあり、クライアントサイドJavaScriptサーバサイドJavaScriptの2大潮流とは別に、JavaScriptフィルタ等の小ツールを作る文化が広まらないか少しだけ期待中。いやあ、TCP絡みのダミーサーバもどきをサクッと作るのにNode.jsが地味に便利だなあ、と。
Lua
Wiresharkパケット解析スクリプトを書いてから数年。今度はC言語で書かれたUnixデーモンの設定ファイル用に組み込むことに。これはこれで「職業柄」の範疇、なのだろうか? Windowsのことを考えなければ、自前でライブラリビルドしてアプリに組み込むのは結構簡単だった。
SQL
生まれて初めて触れたプログラミング言語その3ぐらいに位置する。MySQLを入れてコンソール用のモニタからSQL手入力で弄って遊んだことがある。組み込みの人なのでSQLとは無縁だと思っていたが、まさかTransact-SQLをちょっとだけ触ることになるとは。
Visual Basic .NET
いまさらVisual Basic .NETである。しかも2003。古いシステムの改修と移行だから、仕方ない。
XSLT
縁が切れたと思いきや、仕事でXHTMLから特定要素を抜き出す作業に使うことに。XMLからテキストレコードに変換してしまえば、後はUnix流テキストフィルタの世界が待っている。餅は餅屋というもので、定型的なXMLの変換はXSLTで記述すると楽だ。唯一気に入らないのは、xsl:sortでアルファベットの大文字と小文字を区別してソートすることができないこと。ぐぬぬぬ。

これから(また)使うかもしれない

Alloy
形式手法の中では比較的カジュアルに使えそうなので期待中。入門書処理系も入手した。私の場合、先に何か論理型の言語をかじった方がよいのかも。
Common Lisp
2009年に勉強しようと思い立ったものの、未だに進んでいない。階乗とかハノイの塔とかiotaぐらいは書いたが、目標は「ちょっとしたツールを自作する」だ。まだ道は遠い。最近は時々CLISPを簡易電卓代わりにしている。
Coq
ソフトウェアの基礎が気になるので、処理系だけ入手。
Emacs Lisp
.emacsコピペ」限定で。Common LispSchemeを触ったためか、何となく内容を追えるようになってきた気がしていたが、勘違いだった。
F#
OCamlは「Windows上で日本語を扱う」という視点では処理系がちょっと微妙なので、いっそのことF#に乗り換えようかと……。『実践F#』が積読状態になっている。
Forth
pForthをMinGWビルドしたので処理系は手元にある。スタック指向の言語はいつか勉強したい。
Io
プロトタイプベースである点を除けば、何となくSmalltalk的であるような――公式ドキュメントらしきIo Programming Guideでも影響を受けた言語として真っ先にSmalltalkが挙げられているから、あながち思い違いでもないだろう。
LOGO
そういえばLOGOを触ったことがない。とりあえずUCBLogo(Berkeley Logo)だろうか? Windows上でUCBLogoばりにGUI無しで動作する処理系はないだろうか?
Object REXX
思うところがあって処理系IBM謹製のドキュメントを入手したものの、そこから先の進展は無いまま。ReginaでClassic REXXっぽい感じで触っているからなあ。
OCaml
Common Lispを勉強するはずが、いつの間にか触っていた言語。一応、階乗ぐらいは書いた。時間が取れたらもうちょっとしっかりと勉強したいが、面倒なのでF#に移行しようか検討中。
Oz
ふと思い立ってUbuntuにMozartを入れた。『Scheme手習い』の次はCTMCP片手にOzで勉強かなあ。道は遠いな……。
PostScript
これかForthか、どちらに手を出すべきか? 悩ましい。
Processing
入門書処理系も入手して、あとは弄る時間をつくるだけ。
Prolog
少し前に触っていた言語。『7つの言語、7つの世界』の地図の色分けプログラムには衝撃を受けた。何というか「正しい問い」を見つけられるか否かが肝なのか。この辺は、根底の部分でAlloyに通じる何かがあるように思う。ひとまず、Prologで論理プログラミング宣言的なスタイルに慣れておけば、形式手法にて「論理で宣言的に」記述するときに戸惑いが減るのではないかと期待している。
Rust
仕事柄「C/C++の次のシステムプログラミング言語」はそれなりに興味の対象で、Go言語やD言語ほどではないが、Rustも……まあ、気にならなくはない。ちなみに、これら3言語と同列にObjective-CSwiftが挙げられることもあるようだが、個人的見解としては、システムプログラミング言語としてのこの2言語には全く期待していない。あれは、Appleというしがらみからは逃れられないでしょうな。
Smalltalk (Squeak, Pharo)
Smalltalkは有名な古典的プログラミング言語だというのに、触ったことがない。ということでSqueakとPharoの処理系のみ準備完了。うーん、「環境」付きなのが気になる――言語を弄くる基準が「コンソール上でテキストフィルタ」という変な人種な私だからなあ。
Smalltalk (GNU Smalltalk)
個人の思想信条による理由よりSqueakとPharoにわだかまりを感じてしまう変人なので、邪道だと思いつつもコンソールでテキスト処理もOKなGNU Smalltalkも用意してみた。これで言語としてのSmalltalkの勉強に集中できる……か?
Swift
Appleの新言語については未だ未知の代物なのだが、その割には見覚えのあるシンタックスのような……。Objective-Cを駆逐して、D言語・Go言語・Rustと並ぶ4大次世代システムプログラミング言語となるか、はたまたMac/iOSアプリ専用(システムプログラミングなんて関係ないね!)となるか……まあ、後者だろうなあ。Objective-Cと併存可能ということは、処理系LLVMのフロントエンドとして実装しているのだろうか?
VBA (Visual Basic for Applications)
今までVBAから逃げ回っていたのだが、ついに使うことになりそうな予感。たぶん、Access VBA 8割にExcel VBA 2割ぐらい。

今は全く使っていない

Active Basic
VBScripを触りだした影響で、時々思い出しては弄くっていた。ほんの少しだけ触って放置して、すっかり忘れてからまた触る――これを繰り返していた気がする。なので毎度初めて触るのと同じ状態だった。String型をバシバシ使用 :)
bc
その昔、Windows標準の電卓アプリの代わりに使おうとして色々あって挫折した。今はirbclisp/goshで計算しているからなあ。
COBOL
FizzBuzzするためだけにOpenCOBOL 1.0をWindows上に用意して触ってみた。なんというか、COBOLの名前と生まれた時代が示すように基幹業務(というかお金や帳簿が絡んでくるところ)向けの言語だよなあ、といった感じ。COBOL 2002のフリーフォーマットを採用するだけでも使い勝手が変わる気がしたが、世の中にはまだ広まらないのだろうか。
CoffeeScript
仕事で使う予定はない。RubyPythonその他の影響を受けているだけあり、その手のスクリプト言語っぽい感じでコードを書けるので、慣れれば素のJavaScriptで直接コーディングするよりは楽だ。しかし標準ライブラリ回りや処理系絡みの機能やサードパーティライブラリなど、結局はJavaScriptを知らないとCoffeeScriptでコードを書けないと思う。それに生成されたJavaScriptのコードを見て「うわぁ、これあまり効率的でないなあ」と感じる時もあって、高速化が必要な部分では生成されるコードを気にしながら記述したりCoffeeScriptを諦めてJavaScriptで書くことになるので、やはりJavaScriptを知らないとマズイ。とはいえ便利なのは確かだ。CoffeeScriptのコードは即Node.jsで実行できるので、その辺りから「CoffeeScriptでテキストフィルタ」的な文化が生まれると面白いかも。気になるのはECMAScript 6の存在で、今までCoffeeScript独自の機能だった部分の多くがES6で取り込まれるので、今後ES6対応が進むにつれてCoffeeScriptの立場がどうなっていくのか、少々興味深い。
Fortran
Fortran 90やFortran 95あたりは結構近代的な言語だと思う。用途次第ではC言語よりもFortranの方が遥かにマシな選択だろう。配列がらみの処理はFortranの方が得意だし、言語機能としてのモジュール化の方法はC言語には存在しない。可変長な文字列の扱いに微妙な制限がある点はマイナスな気もするが、まあ基本的に数値計算プログラム用の言語だからなあ。
GDB (GNU Debugger)
……いやGDBデバッガとして使っているが、GDBスクリプトを書く機会は(FizzBuzz以外に)ない。勉強不足なだけかもしれない。
HSP (Hot Soup Processor)
FizzBuzzで楽しんでみたが、何というか他言語経験者には受けが悪そうな命令体系だと思う。もっとも初心者がプログラミングという行為に深入りせずにWindows用のGUIな何かを作る分には、あの命令体系でも十分な気がしないでもない。ところで元々は「HSPで職業プログラマ的な良いコードを書くと、どんな感じになるか?」というネタを思いついて処理系を用意したのだけど、そちらは全く進展がないまま。
JScript on WSH
他人が使うテキスト処理ツールの実装に使って以来、時々触ってきた。Windows用の配布可能な小ツールを実装する時の定番言語だった。でもそろそろ潮時だろう。HTAと組み合わせてクライアントサイドJavaScriptなノリで簡易なGUIツールを実装できる点も、PowerShell + WPF + XAML代替できそうだ。他のメリットは「JavaScriptECMAScript)でフィルタを書ける」だったが、WSHのなかなか目的にたどり着けないオブジェクト階層にイライラするよりも、Node.jsやPhantomJSを使ったほうが精神衛生的にマシだ。
m4
その昔テキスト処理用に触ろうとして、Windows用のどの処理系も日本語の置換に何かしらの問題を抱えていたので泣く泣く諦めた。思うところがあって改めて少し触ってみたが――なるほど、確かに中毒性のある言語*12だ。
REXX
Open Object REXX処理系を入手したのに、何故かReginaを入れてClassic REXXっぽい方向に走っていた。何というか、COMコンポーネント.NET Frameworkと無関係でいられるのなら、バッチファイルの代替としてはREXXあたりがほどよい塩梅だと感じる。しかし最近流行の言語とは随分と勝手が違うし、日本語の情報も少ない。メインフレーム以外の世界で流行る可能性は少ないだろう。
T4 Text Template
「へえ、こんなものがVisual Studioに入っていたのか。機能多すぎで色々と便利なツールを見逃しているんだな、やっぱり」と思いつつ触ってみた。テンプレート変換の用途ではピカ一だと思う。ただ処理系を手に入れる方法が「Visual Studioインストールする」or「MonoDevelopインストールする」なので、何となく「単体で手軽に使えるツール」ではないというイメージが……。まあC#VBで処理を記述するので、それらの処理系が必要だという面での制約なのだろう。
VBScript on WSH
JScriptほどではないが「Windows上で他人も使えるツールを書くためのLL」扱いしていた言語。Windows Server管理の関係で触っていた。というかWebで入手可能なWSHのサンプルの大半がVBScriptで書かれていたり、ADSI関連のコレクションをJScriptで舐めれなかったりして、結局は必要に駆られて使用することに。明快に記述できる文法は評価に値するが、スクリプト言語としては少々冗長だ。配列は自動拡張しないし、組み込み関数はプリミティブ気味だし、冗長気味な文法との合わせ技でコードがさらに冗長になっていく……。文法や言語仕様の詳細なドキュメントが見つからないのだが、どこにあるのだろうか?*13
秀丸マクロ
7年ほど秀丸エディタを使っていたが、マクロを書く機会はなかった。一念発起してFizzBuzzしてみて感じたのは、最近の便利な言語に慣れた身としては色々とモヤモヤ感がある言語仕様だということ(歴史的経緯的に仕方ないのだが)。とはいえちょっとした拡張ツール的なものを手軽に作れそうではあった。

*1:というか人工言語ではあるけど「プログラミング言語」という括りからは外れると思う。

*2:とはいえ、C++標準ライブラリの充実度をJavaC#.NET Framework含む)のそれと比較してはいけません。

*3:少なくともC++の言語仕様は私の手には余る。自分が把握している範囲の機能でコードを書くのは好きなのだけど。

*4GNUStepの互換性は高いけど高くないというか、マンパワーその他の要因で実装が追いついていないというか。

*5:とはいえ、ついついC++を使ってしまうのだよなあ。

*6:これでもsedチューリング完全な言語だと証明されているらしい。

*7ClojureScalaに関しては、同様の機能を私が見逃している可能性も高いのだが。

*8:支障がある部分を触るほど深入りするには、あと20年ぐらい掛かるのではないか?

*9Schemeの勉強というよりも、再帰の勉強なのか?

*10:現状はirbclispかgoshの3択だ。

*11:――といってもシミュレータだけど。

*12m4マクロプロセッサなのでプログラミング言語ではないはずだけど……。

*13MSDNの資料では物足りない。もうちょっと掘り下げた内容のものが欲しい。

2016-06-17

書籍購入:『プログラミング言語Go』

まごうことなく、プログラミング経験者向けのGo言語入門書の良書。

本書の雰囲気は、『プログラミング言語C 第2版 ANSI規格準拠*1)や『UNIXプログラミング環境 (海外ブックス)』に通じるものがある。あと『ソフトウェア作法』も少々。カーニハンの本のスタイルが肌にあう人なら、本書は最適の入門書だろう。

まだ「第1章 チュートリアル」を読んでいるところだが、コンパクトだけど実用面を視野にいれたサンプルコードが頻繁に出てくる。これ、勉強がてら実用ツールを作ろうとした時に便利だ。

プログラミング言語入門書にありがちなのが、言語仕様・ライブラリ機能の挙動を単に示すだけのサンプルコードだ。それはそれで十分興味深い内容ではあるのだが、「まだ言語仕様を深堀りする段階じゃない! Go言語の流儀のポイントを押さえつつ、動くコードを書きたいのだ!」という段階では、残念ながら細かすぎてあまり役に立たない。

その点、本書はバランスが良くて、分かりやすい本文と、実用面を視野に入れたサンプルコードが、うまい具合に合致している。いい仕事してますな。

*1:ただし翻訳の品質を除く。『プログラミング言語C 第2版』は翻訳の品質が、ちょっと……。それさえなければ、「Unix系OSでのシステム・プログラミングを視野に入れた、プログラミング経験者向けの入門書」としては、セキュア・コーディングへの配慮に欠ける点を除けば、悪くない部類に入ると思う。