こんな基準でどうか。用語には自信ありません
- クラス(or 型) X のインスタンスを Duck のように振る舞わせたいとき…
- intrusive:X を定義するときに一緒に "X は Duck っぽい" と明記する
- 例: class X implements Duck { ... }
- nonintrusive-explicit: 外付けで "XはDuckっぽい" と明記する
- 例: (ある場所で) data X = ... (別のところで) instance Duck X where ...
- nonintrusive-implicit: 明記しない。普通 duck typing と言うとこれ。特に dynamic なものを指す。
- 例: template<typename X> void foo(X x) { x.like_a_duck(); }
- dynamic: 特定のメソッドを持った異なる種類のオブジェクトを実行時にいっしょくたに扱える
- 例: pets=[Dog.new, Cat.new, Bear.new]; pets.each{|pet| pet.speak}
- static: 扱えない
- typed: 実際にはDuck的でないXをDuckっぽく使おうとすると静的なエラー
- untyped-safe: 実際にはDuck的でないXをDuckっぽく使おうとすると実行時エラー
- untyped-unsafe: 実際にはDuck的でないXをDuckっぽく使おうとすると、何がおきるかわからない
- specialsyntax: 普通のメソッド呼び出しとは違った記法になる
- 例: obj.speak() vs obj.getClass().getMethod("speak").invoke(obj)
- normalsyntax: 普通のメソッド呼び出しと同じ記法
- first-order: 呼び出すメソッドを値として操作できない
- higher-order: 呼び出すメソッドを値として操作できる
- obj.__send__([:to_s, :to_i][(rand*2).to_i])
∧,,∧ ∧,,∧
∧ (´・ω・) (・ω・`) ∧∧
( ´・ω) U) ( つと ノ(ω・` )
| U ( ´・) (・` ) と ノ
u-u (l ) ( ノu-u
`u-u'. `u-u'
- intrusive-dynamic
- 継承 (特に Java, C#, ...)
- intrusive-static
- C++ の CRTP?(静的型言語での)mixin?
- nonintrusive-explicit-dynamic
- structural subtyping(型推論なし)。Haskellの存在型+型クラス http://www.haskell.org/haskellwiki/Existential_type、C の void* とか?、interfaceに適合させるラッパを手書きして継承とか?
- nonintrusive-explicit-static
- Haskell の型クラス。C++0x の explicit concept。Scalaのimplicit conversion/parameter。
- nonintrusive-implicit-dynamic
- いわゆる duck typing。structural subtyping(型推論あり)。静的言語の reflection?
- nonintrusive-implicit-static
- C++/D のテンプレート。 C のマクロ。
lang | intrusive-dynamic | nonintrusive-explicit-static | nonintrusive-implicit-dynamic | nonintrusive-implicit-static |
C++ | 継承すれば。但し primitive 型/標準ライブラリは不可 | void* / RTTIでがんばる / 関数ポインタ | なし | template |
Java | 継承。但し primitive 型は不可 | なし | reflection | なし |
OOスクリプト言語 | なし | なし | duck typing | なし |
Haskell | Phantom type(幽霊型)を使って模倣、実例 | 型クラス | なし | TemplateHaskell?? |
OCaml | 継承 | Obj.magic でがんばる | structural subtyping | なんかありそうな気もする |
Scala | 継承 | implicit conversion/parameter | structural subtyping | なし |
Ada | 継承 | generic / 関数ポインタ | なし | なし |
Delphi | 継承 | 関数ポインタ | RTTI | 次のバージョンからtemplate入るらしい |
Objective-C | 継承 | 関数ポインタ | 非形式プロトコル | #defineでがんばる |
Go | なし | 関数ポインタ | interface | なし |
Rust | なし | trait | なし | マクロで |
intrusive / nonintrusive-explicit / nonintrusive-implicit × static / dynamic
- | intrusive | nonintrusive-explicit | nonintrusive-implicit |
static | | C++(void*, RTTI, 関数ポインタ), Haskell(型クラス), OCaml(Obj.magic), Scala(implicit conversion/parameter) | C++(template), Haskell(TemplateHaskell??), OCaml(できそう) |
dynamic | C++(継承), Java(継承), Haskell(できそう), Scala(継承) | Haskell(存在型+型クラス) | Java(reflection), LL(duck typing), OCaml(structural subtyping), Scala(structural subtyping) |
intrusive / nonintrusive-explicit / nonintrusive-implicit × typed / untyped
- | intrusive | nonintrusive-explicit | nonintrusive-implicit |
typed | C++(継承), Java(継承), Haskell(できそう), Scala(継承), OCaml(継承) | Haskell(型クラス), Scala(implicit conversion/parameter) | C++(template), Haskell(TemplateHaskell??), OCaml(structural subtyping, できそう), Scala(structural subtyping) |
untyped-safe | | | Java(reflection), LL(duck typing) |
untyped-unsafe | | C++(void*, RTTI, 関数ポインタ), OCaml(Obj.magic) | |
- static / dynamicとuntyped / typedの関連がいまいち良くわからない
- 直感的には、
- 違う型の要素をcoersionして同じ型に揃えるのがdynamic
- 違う型の要素は揃えられないといってリジェクトするのがstatic
- じゃないかと思うんだけど、そうすると、typed / untypedの概念と関連がないと変な気がする
- untypedなら、必ずdynamicが可能。一方、typedでdynamicをやろうとすると C++なら基底クラスを使ってexplicit-intrusiveにやるしかない(多分)。 一方、OCamlだとstructural subtypingのおかげでimplicit-nonintrusiveにできる / Haskellだと型クラス(と存在型のおかげで)non-intrusiveにできるが、型クラスなので(structuralでないので)explicit。
- わかりました。私が考えていたのは、untyped && dynamic / typed && non-static / typed && staticという軸が考えられるのではないかということです。static / dynamicの定義は、一番上に書いてある例では型システムの制限なので、typed / untypedの軸に含めても良いような気がします。
- なるほど。dynamicという言葉が適切ではないのかも。 ここのdynamicは「ヘテロなコレクションが可能」という意味ですよね。 あんまりstatic/dynamicという感じではない。 ところで non-static=dynamic?
Keyword(s):
References:[FrontPage] []