Haxeの構造的部分型(typedef)ってstaticでも使える
Haxeを使い始めて2年ぐらい経つけど、今更こういうコードが書けることに気が付いた。
typedef Foo = { function print(): Void; }
class Hoge { public static function print() { trace("Hoge"); } }
var foo: Foo = Hoge; foo.print();
Haxeで仕方なくnullと付き合う
Haxeは現時点で選択しうるaltJSの中では型システムが一番出来が良く、代数的データ型(Haxeではenum)が扱える点が素晴らしい。しかし、元々はFlashを前提とし、今はマルチターゲット(JavaScript、PHP、C++、C#等)にコンパイルする言語として設計されているため、どうしてもnulを扱わなければならない。
これはHaxeに限った話ではなく、F#やScalaなどでも同様の問題があるのだが、これらの言語と比較すると、Haxeはすこしnullが全面に出てしまっている(むしろnullを許容する言語設計にすることで、学習時の敷居を下げているのではないかとも思えるが…)ので、nullを根絶したい勢にすると、ちょっとぐぬぬとなる面がある。
少し前置きが長くなったが、Haxeで仕方なくnullを付き合うための方法の1つを書いてみる。
そもそも、nullを使わないコードとは?
Option型(言語によってはMaybe型)を使うコードである。Option型とは、「値が存在しない可能性があるデータ」を表現するための型である。
最近普及期に入ってきた型システムがリッチな言語(Scala、F#、OCaml、Haskell等)では当たり前に利用できる。
要は「nullの代わりに使いましょう」という型なのだが、nullのと大きな違いは、型安全である(「いわゆるnullチェック」にあたるコードを書かないとコンパイルすら通らない)という利点がある。nullを許容する場合だと、nullチェックを書かなくてもコンパイルが通ってしまうため、ケアレスミスによるバグが混在してしまう可能性がある。
蛇足ではあるが、リッチな型システムを使うメリットは「計算機がチェックできる範囲を広げることで、人間が楽をできる」ことであるので、食わず嫌いをして使わないのは勿体がない。
Haxeでnullを使わざるをえないところ
大きく2つある。
1. デフォルト引数
Haxeは関数やメソッドにデフォルト引数が設定できるのだが、デフォルト引数にOption型を指定することができない。そのため、どうしても次のような定義を書かざるをえないことがある。
function foo(option: String = null): Void { ... }
2. 環境依存や外部ライブラリを利用するケース
JavaScriptでDOMやjQueryなどを扱わなければならない場合に多発する。
var elem = js.Browser.document.querySelector("#hoge");
// valueにはnullが入る可能性 function setProperty(name: String, value: String): Void { var node = new JQuery("#hoge"); node.prop(name, value); }
これらの他にも、コールバック関数で受け取る値がnullというようなケースも多々ある。
ちょっとした工夫をする
まず次のようなHelperを作成する。ScalaのOption型まんまである。
class OptionHelper { public static function create<T>(x: T): Option<T> { return (x != null) ? Some(x) : None; } public static function getOrElse<T>(a: Option<T>, b: T): T { return switch (a) { case Some(x): x; case None: b; } } }
これだけあれば、結構いける。どうしてもコーディング規約的なものになってしまうが、無いものは仕方がない。
function foo(rawOption: String = null): Void { var option = OptionHelper.create(rawOption); ... }
using OptionHelper; //using mixin function setProperty(name: String, value: Option<String>): Void { var node = new JQuery("#hoge"); node.prop(name, value.getOrElse("")); }
OptionHelperにmap()等のメソッドを追加すると更に便利である。本当はこのあたりを全て標準ライブラリで用意してもらいたい…。
Windows用のPostgreSQL 9.3でUUIDを使えるようにする
シーケンスの代わりにuuidをIDとして使う | Siguniang's Blogを見ながら必要なことだけをメモ。
UUIDを生成する
v1, v3, v4, v5が使えるらしいけど、実質v1とv4ぐらいしか使わないよね。
select uuid_generate_v1(); select uuid_generate_v4();
UUIDをプライマリキーにしたテーブルを作る
CREATE TABLE sample ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), value text )
Windows 8.1上にScalatra開発環境を作る
基本手順は公式ページに書いてある通りだが、Windowsだと多少面倒が発生する。
Conscriptのインストール
Conscriptとは、GitHubでホストされているScalaプログラムの管理(インストール/アップデート)を行うためのツールのようだ。GitHubにアクセスする関係上、Gitコマンドに依存しているらしい(未確認)ので、予めGit for Windows等をインストールしないとダメかもしれない。
Windowsでインストールする場合は、ConscriptのGitHubページからダウンロードできるJava製のインストーラを利用する。おそらくjarをダブルクリックでインストーラが起動できるはずだが、インストーラが起動しない場合は、次のようなコマンドを実行する。
$ java -jar conscript-0.4.4.jar
インストール処理が完了しても、渋いインストーラ画面は表示されっぱなしなので注意が必要である。なお、%USERPROFILE%\bin に対してPATHが通ってない場合、インストール完了時に次のような画面が表示される。
このような画面が出た場合は、PATHに %USERPROFILE%\bin を通しておく。
giter8のインストール
giter8はテンプレートからScalaプロジェクトのスケルトンを作成するツールのようだ。
インストールは次のコマンドを実行するだけで良い。
$ cs n8han/giter8
scalatraプロジェクトの作成
適当なディレクトリに移動して、次のコマンドを実行する。
$ g8 scalatra/scalatra-sbt
プロジェクトのひな形を作るための設定の入力を求められるので、適当に入力するとプロジェクトが作成される。設定内容についてはFirst steps | Scalatraを参照。
プロジェクトが作成されたら、ルートディレクトリ内に、次の内容で sbt.bat ファイルを作成する。
@echo off java -Dinput.encoding=Cp1252 -Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M -jar "%SBT_HOME%bin\sbt-launch.jar" %*
scalatraプロジェクトの起動
次のコマンドを実行すると、 http://localhost:8080/ で作成したscalatraアプリにアクセスできる。sbt初回起動時は依存ライブラリのダウンロードで非常に長い時間待たされるので注意…。
$ sbt > container:start
また、container:start した後で、sbt上で次のコマンドを実行すると、ファイルを編集した際に自動コンパイルしてくれるようになる。
> ~ ;copy-resources;aux-compile
Scalatra + ScalaTestでunit test
公式ドキュメントの記載通りに設定すれば動く。
ScalaTest | Testing | Scalatra guides
設定
project/build.scalaのlibraryDependenciesに、次を追加。
"org.scalatra" %% "scalatra-scalatest" % "2.2.2" % "test"
テストコード
package test.app import org.scalatra.test.scalatest._ import org.scalatest.FunSuite class TestServletTests extends ScalatraSuite with FunSuite { addServlet(classOf[TestServlet], "/*") test("simple get") { get("/") { status should equal (200) body should include ("Hello") } } }
テスト実行
$ sbt > test
特定のテストだけ動かしたい時は、次のようにする。
$ sbt > test-only org.acme.RedSuite org.acme.BlueSuite > test-only *RedSuite
細かい点については、ScalaTestのページを参照。
Debian wheezy(Debian 7.4)にPostgreSQL 9.3(最新版)をインストール
公式ページの手順通り。
PostgreSQL: Linux downloads (Debian)
PostgreSQLのaptリポジトリを追加
/etc/apt/sources.list.d/pgdg.list を作成して、次の通り記述する。
deb http://apt.postgresql.org/pub/repos/apt/ wheezy-pgdg main
リポジトリのキーを追加して、パッケージリストを更新。
$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - $ sudo apt-get update
PostgreSQL 9.3をインストール
$ sudo apt-get install postgresql-9.3