CoffeeScript クラス定義メモ

class Hoge
    # private static member (Is accessible from all members.)
    _aaa = 0
    _bbb = 0
    # public static member
    @getAAA = () -> _aaa
    @getBBB: () -> _bbb
    # constructor
    constructor: (@a, @b, aaa) -> # Variables 'a' and 'b' are defined as public instance members.
        _aaa = aaa
        _bbb = aaa * 2
        # private instance member (Is not accessible from public methods.)
        _c = a * b
        # privileged instance member
        this.getC = () -> _c
    # public instance member
    getA: () -> @a
    getB: () -> @b

h1 = new Hoge(1, 2, 10)
h2 = new Hoge(3, 4, 20)
alert(h1.getA() + ", " + h1.getB() + ", " + h1.getC()) # 1, 2, 2
alert(h2.getA() + ", " + h2.getB() + ", " + h2.getC()) # 3, 4, 12
alert(Hoge.getAAA()) # 20
alert(Hoge.getBBB()) # 40

わかりづらい・・・。
全部 public にして、外部からアクセスして欲しくないメンバーには接頭辞に _ を付ける、ってスタンスがいいと思う。
あと、紛らわしいから static メンバーには @ じゃなくてクラス名を使う方がいいかな。

class Hoge
    # static member
    Hoge._aaa = 0
    Hoge._bbb = 0
    Hoge.getAAA = () -> Hoge._aaa
    Hoge.getBBB = () -> Hoge._bbb
    # constructor
    constructor: (@_a, @_b, aaa) ->
        Hoge._aaa = aaa
        Hoge._bbb = aaa * 2
        @_c = @_a * @_b
    # instance member
    getA: () -> @_a
    getB: () -> @_b
    getC: () -> @_c

h1 = new Hoge(1, 2, 10)
h2 = new Hoge(3, 4, 20)
alert(h1.getA() + ", " + h1.getB() + ", " + h1.getC()) # 1, 2, 2
alert(h2.getA() + ", " + h2.getB() + ", " + h2.getC()) # 3, 4, 12
alert(Hoge.getAAA()) # 20
alert(Hoge.getBBB()) # 40


[おまけ]
一つ目のスクリプトから変換された JavaScript

Hoge = (function() {
  var _aaa, _bbb;
  Hoge.name = 'Hoge';
  _aaa = 0;
  _bbb = 0;
  Hoge.getAAA = function() {
    return _aaa;
  };
  Hoge.getBBB = function() {
    return _bbb;
  };
  function Hoge(a, b, aaa) {
    var _c;
    this.a = a;
    this.b = b;
    _aaa = aaa;
    _bbb = aaa * 2;
    _c = a * b;
    this.getC = function() {
      return _c;
    };
  }
  Hoge.prototype.getA = function() {
    return this.a;
  };
  Hoge.prototype.getB = function() {
    return this.b;
  };
  return Hoge;
})();

h1 = new Hoge(1, 2, 10);
h2 = new Hoge(3, 4, 20);
alert(h1.getA() + ", " + h1.getB() + ", " + h1.getC());
alert(h2.getA() + ", " + h2.getB() + ", " + h2.getC());
alert(Hoge.getAAA());
alert(Hoge.getBBB());

二つ目のスクリプトから変換された JavaScript

Hoge = (function() {
  Hoge.name = 'Hoge';
  Hoge._aaa = 0;
  Hoge._bbb = 0;
  Hoge.getAAA = function() {
    return Hoge._aaa;
  };
  Hoge.getBBB = function() {
    return Hoge._bbb;
  };
  function Hoge(_a, _b, aaa) {
    this._a = _a;
    this._b = _b;
    Hoge._aaa = aaa;
    Hoge._bbb = aaa * 2;
    this._c = this._a * this._b;
  }
  Hoge.prototype.getA = function() {
    return this._a;
  };
  Hoge.prototype.getB = function() {
    return this._b;
  };
  Hoge.prototype.getC = function() {
    return this._c;
  };
  return Hoge;
})();

h1 = new Hoge(1, 2, 10);
h2 = new Hoge(3, 4, 20);
alert(h1.getA() + ", " + h1.getB() + ", " + h1.getC());
alert(h2.getA() + ", " + h2.getB() + ", " + h2.getC());
alert(Hoge.getAAA());
alert(Hoge.getBBB());

F# の書式指定文字列

printf 使ってるとすぐに気付くんだけど

let s = "hoge"
printfn s

これ、コンパイル通らないですね。

error FS0001: 型 'string' は型 'Printf.TextWriterFormat<'a>' と互換性がありません


Console.WriteLine みたいに単純に文字列を受け取るわけじゃないみたいです。


こういう間違った指定もコンパイルエラーになります。

printfn "%s, %i" 100 200

つまり、コンパイル時に文字列リテラルを解析して各プレースホルダーの型を解決できちゃう、と。
これはなかなか粋なことしてくれます!


ちなみに Printf.TextWriterFormat<'a> は PrintFormat<'a, System.IO.TextWriter, unit, unit> の型省略形です。
次の検証結果を見るとよくわかりますが、文字列リテラルを直接 PrintfFormat 型として扱うことができるってことですね。

> let format:PrintfFormat<_,unit,unit,unit> = "%s %i";;
val format : PrintfFormat<(string -> int -> unit),unit,unit,unit>

PrintfFormat のコンストラクタの引数に対しては解析処理は働きません。これは文字列リテラルを普通に string 型の引数として渡しているだけだから当然です。

> let format = new PrintfFormat<_,unit,unit,unit>("%s %i");;

error FS0030: 値の制限。値 'format' は次のジェネリック型を持つと推論されました。
    val format : PrintfFormat<'_a,unit,unit,unit>
単純なデータ用語として 'format' を定義するか、明示的な引数を使用して関数にするか、ジェネリックにする意図がない場合は型の注釈を追加してください。