The Backyard - BridgeBetweenStrongAndLoose Diff
- Added parts are displayed like this.
- Deleted parts are displayed
like this.
!強い型付言語と弱い型付言語の相互運用
多言語のブリッジを開発する場合、いくつかの考慮点がある。
ここでは以下の2点のうち、特に後者について考察する。
*型システムの差
*メソッドシグネチャに型情報が含まれるメソッドの特定手法
これは、RjbおよびASR(およびその元となったWin32OLE)における相互運用上のデザインについてのメモである。
!!具体例
Rjbを例とする。今、以下のスクリプトを実行していると仮定する。
JString = Rjb::import('java.lang.String')
s = JString.new("ABC")
t = JString.new("\x01\0\x02\0\x03\0")
人間の意図として、これは以下のJavaのプログラムに相当することが考えられる。
String s = new String("ABC");
String t = new String(new byte[] { 1, 0, 2, 0, 3, 0 });
すなわち、最初のコンストラクタの呼び出しは、String(String)、次のコンストラクタの呼び出しは、String(byte[]) である。
しかし、Rubyにはbyte[]に相当する型はないため、このような判定を機械的に正しく行う手段はない。
!!!ユースケースによる判定
この例で示したStringクラスのコンストラクタについては、String(String)の呼び出しに意味がないため、おそらくString(byte[])の呼び出しと判断することは間違いではないだろう。
しかし、これは他のメソッドについて敷衍できるわけではない。
したがって、ユースケースからの考察は現実的な判定方法とは言えない。
!! 判定方法の種類
*自動判定
**最初にマッチした(コアース可能な)メソッド
***呼び出しコスト低、信頼性無
**最後にマッチしたメソッド(全メソッドとマッチ)
***呼び出しコスト高、信頼性無
**ユースケースの内蔵
***非現実的
**優先するメソッドの構成表
***APIとして実装すれば、そのスクリプトの範囲で現実的(実際には自動判定とは言えない)
*プログラマ指定
**メソッド指定
***型パラメータ(型オブジェクト配列): Reflectionの手法
***型パラメータ(エンコードした型オブジェクト配列):Rjbの手法
****C++のマングリングもこの方法の一種と考えられる
**引数指定
***メタデータを持つ引数型(例:Variant)
***型情報の指定
!!引数による型指定
!!!メタデータを持つ引数型
例)
class Argument
def initialize(t, value)
@type = t
@value = value
end
attr_accessor :type, :value
end
...
s = JString.new(Argument.new('[B', 'ABC'))
ブリッジは引数がArgumentクラスのインスタンスであれば、メタデータ(type属性)から型情報を得て、value属性から引数値を得る。type属性で指定された型へのキャストを必要に応じて行う。
!!!!長所
インクリメンタルなスクリプトの修正が可能。
開始
v = foo.bar(1, 2, 3)
実行結果からメソッド指定が必要と判断
v = foo.bar(Argument.new('S', 1), 2, 3)
実行結果からさらに指定が必要と判断
v = foo.bar(Argument.new('S', 1), 2, Argument.new('J', 3))
!!!!短所
記述時点で呼び出すべきメソッドを特定できているのであれば、メソッド指定法と変わらないと考えられる。
引数リストが長くなるためスクリプトの簡潔さが失われる。
!!!型情報の指定
例
s = JString.new({ :value => 'ABC', :type => '[B' })
ブリッジは引数がハッシュならば、:typeキーから型情報を得て、:valueから引数値を得る。:typeで指定された型へのキャストを必要ならば行う。
!!!!長所
特殊なクラス(上記Argumentクラス)や、特殊な記法(Rjbの_invoke)が不要。
!!!!短所
引数リストが巨大になる(読みにくいスクリプト)おそれがある。
!!!メタデータを持つ引数型の拡張
例)
class ByteArrayArgument < Argument
def initialize(value)
super('[B', value)
end
def value
a = []
value.each_byte {|b| a << b }
a
end
end
...
s = JString.new(ByteArrayArgument.new('ABC'))
!!!!長所
スクリプトは比較的記述しやすい。型によっては、ブリッジ側での実行時のメソッド判定処理が型変換処理が単純化できる(上の例ではStringからバイト配列への変換を型指定クラスに実装している)。
!!!!短所
short[]、long[] の判定などが最終的には必要となるため、例で示したような引数クラス自身による変形だけでは完結しない。(これは長所で上げた点に対する短所で、他の方法に比べた場合の短所では無い。他の方法も同様な処理が必要である)
多言語のブリッジを開発する場合、いくつかの考慮点がある。
ここでは以下の2点のうち、特に後者について考察する。
*型システムの差
*メソッドシグネチャに型情報が含まれるメソッドの特定手法
これは、RjbおよびASR(およびその元となったWin32OLE)における相互運用上のデザインについてのメモである。
!!具体例
Rjbを例とする。今、以下のスクリプトを実行していると仮定する。
JString = Rjb::import('java.lang.String')
s = JString.new("ABC")
t = JString.new("\x01\0\x02\0\x03\0")
人間の意図として、これは以下のJavaのプログラムに相当することが考えられる。
String s = new String("ABC");
String t = new String(new byte[] { 1, 0, 2, 0, 3, 0 });
すなわち、最初のコンストラクタの呼び出しは、String(String)、次のコンストラクタの呼び出しは、String(byte[]) である。
しかし、Rubyにはbyte[]に相当する型はないため、このような判定を機械的に正しく行う手段はない。
!!!ユースケースによる判定
この例で示したStringクラスのコンストラクタについては、String(String)の呼び出しに意味がないため、おそらくString(byte[])の呼び出しと判断することは間違いではないだろう。
しかし、これは他のメソッドについて敷衍できるわけではない。
したがって、ユースケースからの考察は現実的な判定方法とは言えない。
!! 判定方法の種類
*自動判定
**最初にマッチした(コアース可能な)メソッド
***呼び出しコスト低、信頼性無
**最後にマッチしたメソッド(全メソッドとマッチ)
***呼び出しコスト高、信頼性無
**ユースケースの内蔵
***非現実的
**優先するメソッドの構成表
***APIとして実装すれば、そのスクリプトの範囲で現実的(実際には自動判定とは言えない)
*プログラマ指定
**メソッド指定
***型パラメータ(型オブジェクト配列): Reflectionの手法
***型パラメータ(エンコードした型オブジェクト配列):Rjbの手法
****C++のマングリングもこの方法の一種と考えられる
**引数指定
***メタデータを持つ引数型(例:Variant)
***型情報の指定
!!引数による型指定
!!!メタデータを持つ引数型
例)
class Argument
def initialize(t, value)
@type = t
@value = value
end
attr_accessor :type, :value
end
...
s = JString.new(Argument.new('[B', 'ABC'))
ブリッジは引数がArgumentクラスのインスタンスであれば、メタデータ(type属性)から型情報を得て、value属性から引数値を得る。type属性で指定された型へのキャストを必要に応じて行う。
!!!!長所
インクリメンタルなスクリプトの修正が可能。
開始
v = foo.bar(1, 2, 3)
実行結果からメソッド指定が必要と判断
v = foo.bar(Argument.new('S', 1), 2, 3)
実行結果からさらに指定が必要と判断
v = foo.bar(Argument.new('S', 1), 2, Argument.new('J', 3))
!!!!短所
記述時点で呼び出すべきメソッドを特定できているのであれば、メソッド指定法と変わらないと考えられる。
引数リストが長くなるためスクリプトの簡潔さが失われる。
!!!型情報の指定
例
s = JString.new({ :value => 'ABC', :type => '[B' })
ブリッジは引数がハッシュならば、:typeキーから型情報を得て、:valueから引数値を得る。:typeで指定された型へのキャストを必要ならば行う。
!!!!長所
特殊なクラス(上記Argumentクラス)や、特殊な記法(Rjbの_invoke)が不要。
!!!!短所
引数リストが巨大になる(読みにくいスクリプト)おそれがある。
!!!メタデータを持つ引数型の拡張
例)
class ByteArrayArgument < Argument
def initialize(value)
super('[B', value)
end
def value
a = []
value.each_byte {|b| a << b }
a
end
end
...
s = JString.new(ByteArrayArgument.new('ABC'))
!!!!長所
スクリプトは比較的記述しやすい。型によっては、ブリッジ側での実行時の
!!!!短所
short[]、long[] の判定などが最終的には必要となるため、例で示したような引数クラス自身による変形だけでは完結しない。(これは長所で上げた点に対する短所で、他の方法に比べた場合の短所では無い。他の方法も同様な処理が必要である)